• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/declarative_frontend/jsview/js_list.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/log/ace_scoring_log.h"
20 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
21 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/jsview/models/list_model_impl.h"
24 #include "core/components_ng/base/view_stack_model.h"
25 #include "core/components_ng/pattern/list/list_model.h"
26 #include "core/components_ng/pattern/list/list_model_ng.h"
27 #include "core/components_ng/pattern/list/list_position_controller.h"
28 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
29 
30 namespace OHOS::Ace {
31 
32 std::unique_ptr<ListModel> ListModel::instance_ = nullptr;
33 std::mutex ListModel::mutex_;
34 
GetInstance()35 ListModel* ListModel::GetInstance()
36 {
37     if (!instance_) {
38         std::lock_guard<std::mutex> lock(mutex_);
39         if (!instance_) {
40 #ifdef NG_BUILD
41             instance_.reset(new NG::ListModelNG());
42 #else
43             if (Container::IsCurrentUseNewPipeline()) {
44                 instance_.reset(new NG::ListModelNG());
45             } else {
46                 instance_.reset(new Framework::ListModelImpl());
47             }
48 #endif
49         }
50     }
51     return instance_.get();
52 }
53 
54 } // namespace OHOS::Ace
55 
56 namespace OHOS::Ace::Framework {
57 
58 const std::vector<V2::ScrollSnapAlign> SCROLL_SNAP_ALIGN = { V2::ScrollSnapAlign::NONE, V2::ScrollSnapAlign::START,
59     V2::ScrollSnapAlign::CENTER, V2::ScrollSnapAlign::END };
60 
SetDirection(int32_t direction)61 void JSList::SetDirection(int32_t direction)
62 {
63     ListModel::GetInstance()->SetListDirection(static_cast<Axis>(direction));
64 }
65 
SetScrollBar(const JSCallbackInfo & info)66 void JSList::SetScrollBar(const JSCallbackInfo& info)
67 {
68     // default value 1 represents scrollBar DisplayMode::AUTO.
69     int32_t scrollBar = 1;
70     ParseJsInteger<int32_t>(info[0], scrollBar);
71     scrollBar = scrollBar < 0 ? 1 : scrollBar;
72     ListModel::GetInstance()->SetScrollBar(static_cast<DisplayMode>(scrollBar));
73 }
74 
SetEdgeEffect(int32_t edgeEffect)75 void JSList::SetEdgeEffect(int32_t edgeEffect)
76 {
77     ListModel::GetInstance()->SetEdgeEffect(static_cast<EdgeEffect>(edgeEffect));
78 }
79 
SetEditMode(bool editMode)80 void JSList::SetEditMode(bool editMode)
81 {
82     ListModel::GetInstance()->SetEditMode(editMode);
83 }
84 
SetCachedCount(const JSCallbackInfo & info)85 void JSList::SetCachedCount(const JSCallbackInfo& info)
86 {
87     int32_t cachedCount = 1;
88     ParseJsInteger<int32_t>(info[0], cachedCount);
89     cachedCount = cachedCount < 0 ? 1 : cachedCount;
90     ListModel::GetInstance()->SetCachedCount(cachedCount);
91 }
92 
SetScroller(RefPtr<JSScroller> scroller)93 void JSList::SetScroller(RefPtr<JSScroller> scroller)
94 {
95     if (scroller) {
96         RefPtr<ScrollControllerBase> listController = ListModel::GetInstance()->CreateScrollController();
97         scroller->SetController(listController);
98 
99         // Init scroll bar proxy.
100         auto proxy = scroller->GetScrollBarProxy();
101         if (!proxy) {
102             if (Container::IsCurrentUseNewPipeline()) {
103                 proxy = AceType::MakeRefPtr<NG::ScrollBarProxy>();
104             } else {
105                 proxy = AceType::MakeRefPtr<ScrollBarProxy>();
106             }
107             scroller->SetScrollBarProxy(proxy);
108         }
109         ListModel::GetInstance()->SetScroller(listController, proxy);
110     }
111 }
112 
Create(const JSCallbackInfo & args)113 void JSList::Create(const JSCallbackInfo& args)
114 {
115     ListModel::GetInstance()->Create();
116     if (args.Length() >= 1 && args[0]->IsObject()) {
117         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
118         JSRef<JSVal> spaceValue = obj->GetProperty("space");
119         if (!spaceValue->IsNull()) {
120             CalcDimension space;
121             ConvertFromJSValue(spaceValue, space);
122             ListModel::GetInstance()->SetSpace(space);
123         }
124         int32_t initialIndex = 0;
125         if (ConvertFromJSValue(obj->GetProperty("initialIndex"), initialIndex) && initialIndex >= 0) {
126             ListModel::GetInstance()->SetInitialIndex(initialIndex);
127         }
128         JSRef<JSVal> scrollerValue = obj->GetProperty("scroller");
129         if (scrollerValue->IsObject()) {
130             void* scroller = JSRef<JSObject>::Cast(scrollerValue)->Unwrap<JSScroller>();
131             RefPtr<JSScroller> jsScroller = Referenced::Claim(reinterpret_cast<JSScroller*>(scroller));
132             SetScroller(jsScroller);
133         }
134     }
135 
136     args.ReturnSelf();
137 }
138 
SetChainAnimation(bool enableChainAnimation)139 void JSList::SetChainAnimation(bool enableChainAnimation)
140 {
141     ListModel::GetInstance()->SetChainAnimation(enableChainAnimation);
142 }
143 
SetChainAnimationOptions(const JSCallbackInfo & info)144 void JSList::SetChainAnimationOptions(const JSCallbackInfo& info)
145 {
146     if (info.Length() < 1) {
147         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
148         return;
149     }
150 
151     if (info[0]->IsObject()) {
152         RefPtr<ListTheme> listTheme = GetTheme<ListTheme>();
153         CHECK_NULL_VOID(listTheme);
154         ChainAnimationOptions options = {
155             .minSpace = listTheme->GetChainMinSpace(),
156             .maxSpace = listTheme->GetChainMaxSpace(),
157             .conductivity = listTheme->GetChainConductivity(),
158             .intensity = listTheme->GetChainIntensity(),
159             .edgeEffect = 0,
160             .stiffness = listTheme->GetChainStiffness(),
161             .damping = listTheme->GetChainDamping(),
162         };
163         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
164         ParseJsDimensionVp(jsObj->GetProperty("minSpace"), options.minSpace);
165         ParseJsDimensionVp(jsObj->GetProperty("maxSpace"), options.maxSpace);
166         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("conductivity"), options.conductivity);
167         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("intensity"), options.intensity);
168         JSViewAbstract::ParseJsInt32(jsObj->GetProperty("edgeEffect"), options.edgeEffect);
169         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("stiffness"), options.stiffness);
170         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("damping"), options.damping);
171         ListModel::GetInstance()->SetChainAnimationOptions(options);
172     }
173 }
174 
JsWidth(const JSCallbackInfo & info)175 void JSList::JsWidth(const JSCallbackInfo& info)
176 {
177     JSViewAbstract::JsWidth(info);
178     ListModel::GetInstance()->SetHasWidth(true);
179 }
180 
JsHeight(const JSCallbackInfo & info)181 void JSList::JsHeight(const JSCallbackInfo& info)
182 {
183     JSViewAbstract::JsHeight(info);
184     ListModel::GetInstance()->SetHasHeight(true);
185 }
186 
SetListItemAlign(int32_t itemAlignment)187 void JSList::SetListItemAlign(int32_t itemAlignment)
188 {
189     ListModel::GetInstance()->SetListItemAlign(static_cast<V2::ListItemAlign>(itemAlignment));
190 }
191 
SetLanes(const JSCallbackInfo & info)192 void JSList::SetLanes(const JSCallbackInfo& info)
193 {
194     if (info.Length() < 1) {
195         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
196         return;
197     }
198 
199     if (info.Length() >= 2 && !(info[1]->IsNull())) { /* 2: parameter count */
200         CalcDimension laneGutter;
201         if (JSViewAbstract::ParseJsDimensionVp(info[1], laneGutter)) {
202             if (laneGutter.IsNegative()) {
203                 laneGutter.Reset();
204             }
205         }
206         ListModel::GetInstance()->SetLaneGutter(laneGutter);
207     }
208 
209     int32_t laneNum = 1;
210     if (ParseJsInteger<int32_t>(info[0], laneNum)) {
211         // when [lanes] is set, [laneConstrain_] of list component will be reset to std::nullopt
212         ListModel::GetInstance()->SetLanes(laneNum);
213         ListModel::GetInstance()->SetLaneConstrain(-1.0_vp, -1.0_vp);
214         return;
215     }
216     if (info[0]->IsObject()) {
217         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
218         auto minLengthParam = jsObj->GetProperty("minLength");
219         auto maxLengthParam = jsObj->GetProperty("maxLength");
220         if (minLengthParam->IsNull() || maxLengthParam->IsNull()) {
221             LOGW("minLength and maxLength are not both set");
222             return;
223         }
224         CalcDimension minLengthValue;
225         CalcDimension maxLengthValue;
226         if (!ParseJsDimensionVp(minLengthParam, minLengthValue)
227             || !ParseJsDimensionVp(maxLengthParam, maxLengthValue)) {
228             LOGW("minLength param or maxLength param is invalid");
229             ListModel::GetInstance()->SetLanes(1);
230             ListModel::GetInstance()->SetLaneConstrain(-1.0_vp, -1.0_vp);
231             return;
232         }
233         ListModel::GetInstance()->SetLaneConstrain(minLengthValue, maxLengthValue);
234         ListModel::GetInstance()->SetLanes(1);
235     }
236 }
237 
SetSticky(int32_t sticky)238 void JSList::SetSticky(int32_t sticky)
239 {
240     ListModel::GetInstance()->SetSticky(static_cast<V2::StickyStyle>(sticky));
241 }
242 
SetContentStartOffset(float startOffset)243 void JSList::SetContentStartOffset(float startOffset)
244 {
245     ListModel::GetInstance()->SetContentStartOffset(startOffset);
246 }
247 
SetContentEndOffset(float endOffset)248 void JSList::SetContentEndOffset(float endOffset)
249 {
250     ListModel::GetInstance()->SetContentEndOffset(endOffset);
251 }
252 
SetScrollSnapAlign(int32_t scrollSnapAlign)253 void JSList::SetScrollSnapAlign(int32_t scrollSnapAlign)
254 {
255     V2::ScrollSnapAlign param;
256     if (scrollSnapAlign < 0 || scrollSnapAlign >= static_cast<int32_t>(SCROLL_SNAP_ALIGN.size())) {
257         param = V2::ScrollSnapAlign::NONE;
258     } else {
259         param = V2::ScrollSnapAlign(scrollSnapAlign);
260     }
261     ListModel::GetInstance()->SetScrollSnapAlign(param);
262 }
263 
SetDivider(const JSCallbackInfo & args)264 void JSList::SetDivider(const JSCallbackInfo& args)
265 {
266     if (args.Length() < 1 || !args[0]->IsObject()) {
267         LOGW("Invalid params");
268         return;
269     }
270 
271     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
272     V2::ItemDivider divider;
273     if (!ConvertFromJSValue(obj->GetProperty("strokeWidth"), divider.strokeWidth)) {
274         LOGW("Invalid strokeWidth of divider");
275         divider.strokeWidth.Reset();
276     }
277     if (!ConvertFromJSValue(obj->GetProperty("color"), divider.color)) {
278         // Failed to get color from param, using default color defined in theme
279         RefPtr<ListTheme> listTheme = GetTheme<ListTheme>();
280         if (listTheme) {
281             divider.color = listTheme->GetDividerColor();
282         }
283     }
284     ConvertFromJSValue(obj->GetProperty("startMargin"), divider.startMargin);
285     ConvertFromJSValue(obj->GetProperty("endMargin"), divider.endMargin);
286     ListModel::GetInstance()->SetDivider(divider);
287 
288     args.ReturnSelf();
289 }
290 
SetNestedScroll(const JSCallbackInfo & args)291 void JSList::SetNestedScroll(const JSCallbackInfo& args)
292 {
293     NestedScrollOptions nestedOpt = {
294         .forward = NestedScrollMode::SELF_ONLY,
295         .backward = NestedScrollMode::SELF_ONLY,
296     };
297     if (args.Length() < 1 || !args[0]->IsObject()) {
298         ListModel::GetInstance()->SetNestedScroll(nestedOpt);
299         LOGW("Invalid params");
300         return;
301     }
302     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
303     int32_t froward = 0;
304     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
305     if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
306         froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
307         LOGW("ScrollFroward params invalid");
308         froward = 0;
309     }
310     int32_t backward = 0;
311     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
312     if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
313         backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
314         LOGW("ScrollFroward params invalid");
315         backward = 0;
316     }
317     nestedOpt.forward = static_cast<NestedScrollMode>(froward);
318     nestedOpt.backward = static_cast<NestedScrollMode>(backward);
319     ListModel::GetInstance()->SetNestedScroll(nestedOpt);
320     args.ReturnSelf();
321 }
322 
SetScrollEnabled(const JSCallbackInfo & args)323 void JSList::SetScrollEnabled(const JSCallbackInfo& args)
324 {
325     ListModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
326 }
327 
ScrollCallback(const JSCallbackInfo & args)328 void JSList::ScrollCallback(const JSCallbackInfo& args)
329 {
330     if (args[0]->IsFunction()) {
331         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
332                             const CalcDimension& scrollOffset, const ScrollState& scrollState) {
333             auto params = ConvertToJSValues(scrollOffset, scrollState);
334             func->Call(JSRef<JSObject>(), params.size(), params.data());
335             return;
336         };
337         ListModel::GetInstance()->SetOnScroll(std::move(onScroll));
338     }
339     args.ReturnSelf();
340 }
341 
SetFriction(const JSCallbackInfo & info)342 void JSList::SetFriction(const JSCallbackInfo& info)
343 {
344     double friction = -1.0;
345     if (!JSViewAbstract::ParseJsDouble(info[0], friction)) {
346         LOGW("Friction params invalid,can not convert to double");
347         friction = -1.0;
348     }
349     ListModel::GetInstance()->SetFriction(friction);
350 }
351 
ReachStartCallback(const JSCallbackInfo & args)352 void JSList::ReachStartCallback(const JSCallbackInfo& args)
353 {
354     if (args[0]->IsFunction()) {
355         auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
356             func->Call(JSRef<JSObject>());
357             return;
358         };
359         ListModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
360     }
361     args.ReturnSelf();
362 }
363 
ReachEndCallback(const JSCallbackInfo & args)364 void JSList::ReachEndCallback(const JSCallbackInfo& args)
365 {
366     if (args[0]->IsFunction()) {
367         auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
368             func->Call(JSRef<JSObject>());
369             return;
370         };
371         ListModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
372     }
373     args.ReturnSelf();
374 }
375 
ScrollStartCallback(const JSCallbackInfo & args)376 void JSList::ScrollStartCallback(const JSCallbackInfo& args)
377 {
378     if (args[0]->IsFunction()) {
379         auto onScrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
380             func->Call(JSRef<JSObject>());
381             return;
382         };
383         ListModel::GetInstance()->SetOnScrollStart(std::move(onScrollStart));
384     }
385     args.ReturnSelf();
386 }
387 
ScrollStopCallback(const JSCallbackInfo & args)388 void JSList::ScrollStopCallback(const JSCallbackInfo& args)
389 {
390     if (args[0]->IsFunction()) {
391         auto onScrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
392             func->Call(JSRef<JSObject>());
393             return;
394         };
395         ListModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
396     }
397     args.ReturnSelf();
398 }
399 
ItemDeleteCallback(const JSCallbackInfo & args)400 void JSList::ItemDeleteCallback(const JSCallbackInfo& args)
401 {
402     if (args[0]->IsFunction()) {
403         auto onItemDelete = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
404                                 int32_t index) -> bool {
405             auto params = ConvertToJSValues(index);
406             func->Call(JSRef<JSObject>(), params.size(), params.data());
407             return true;
408         };
409         ListModel::GetInstance()->SetOnItemDelete(std::move(onItemDelete));
410     }
411     args.ReturnSelf();
412 }
413 
ItemMoveCallback(const JSCallbackInfo & args)414 void JSList::ItemMoveCallback(const JSCallbackInfo& args)
415 {
416     if (args[0]->IsFunction()) {
417         auto onItemMove = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
418                               int32_t start, int32_t end) -> bool {
419             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
420             auto params = ConvertToJSValues(start, end);
421             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
422             if (!result.IsEmpty() && result->IsBoolean()) {
423                 return result->ToBoolean();
424             }
425             return true;
426         };
427         ListModel::GetInstance()->SetOnItemMove(std::move(onItemMove));
428     }
429     args.ReturnSelf();
430 }
431 
ScrollIndexCallback(const JSCallbackInfo & args)432 void JSList::ScrollIndexCallback(const JSCallbackInfo& args)
433 {
434     if (args[0]->IsFunction()) {
435         auto onScrollIndex = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
436                                  const int32_t start, const int32_t end, const int32_t center) {
437             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
438             auto params = ConvertToJSValues(start, end, center);
439             func->Call(JSRef<JSObject>(), params.size(), params.data());
440             return;
441         };
442         ListModel::GetInstance()->SetOnScrollIndex(std::move(onScrollIndex));
443     }
444     args.ReturnSelf();
445 }
446 
ItemDragStartCallback(const JSCallbackInfo & info)447 void JSList::ItemDragStartCallback(const JSCallbackInfo& info)
448 {
449     if (!info[0]->IsFunction()) {
450         LOGE("fail to bind onItemDragStart event due to info is not function");
451         return;
452     }
453 
454     RefPtr<JsDragFunction> jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
455     auto onItemDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc)](
456                                const ItemDragInfo& dragInfo, int32_t itemIndex) -> RefPtr<AceType> {
457         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, nullptr);
458         auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
459         if (!ret->IsObject()) {
460             LOGE("builder param is not an object.");
461             return nullptr;
462         }
463 
464         auto builderObj = JSRef<JSObject>::Cast(ret);
465         auto builder = builderObj->GetProperty("builder");
466         if (!builder->IsFunction()) {
467             LOGE("builder param is not a function.");
468             return nullptr;
469         }
470         auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
471         if (!builderFunc) {
472             LOGE("builder function is null.");
473             return nullptr;
474         }
475         // use another VSP instance while executing the builder function
476         ViewStackModel::GetInstance()->NewScope();
477         {
478             ACE_SCORING_EVENT("List.onItemDragStart.builder");
479             builderFunc->Execute();
480         }
481         return ViewStackModel::GetInstance()->Finish();
482     };
483     ListModel::GetInstance()->SetOnItemDragStart(std::move(onItemDragStart));
484 }
485 
ItemDragEnterCallback(const JSCallbackInfo & info)486 void JSList::ItemDragEnterCallback(const JSCallbackInfo& info)
487 {
488     if (!info[0]->IsFunction()) {
489         LOGE("fail to bind onItemDragEnter event due to info is not function");
490         return;
491     }
492 
493     RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
494     auto onItemDragEnter = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc)](
495                                const ItemDragInfo& dragInfo) {
496         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
497         ACE_SCORING_EVENT("List.onItemDragEnter");
498         func->ItemDragEnterExecute(dragInfo);
499     };
500     ListModel::GetInstance()->SetOnItemDragEnter(std::move(onItemDragEnter));
501 }
502 
ItemDragMoveCallback(const JSCallbackInfo & info)503 void JSList::ItemDragMoveCallback(const JSCallbackInfo& info)
504 {
505     if (!info[0]->IsFunction()) {
506         LOGE("fail to bind onItemDragMove event due to info is not function");
507         return;
508     }
509 
510     RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
511     auto onItemDragMove = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
512                               const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
513         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
514         ACE_SCORING_EVENT("List.onItemDragMove");
515         func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
516     };
517     ListModel::GetInstance()->SetOnItemDragMove(std::move(onItemDragMove));
518 }
519 
ItemDragLeaveCallback(const JSCallbackInfo & info)520 void JSList::ItemDragLeaveCallback(const JSCallbackInfo& info)
521 {
522     if (!info[0]->IsFunction()) {
523         LOGE("fail to bind onItemDragLeave event due to info is not function");
524         return;
525     }
526 
527     RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
528     auto onItemDragLeave = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
529                                const ItemDragInfo& dragInfo, int32_t itemIndex) {
530         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
531         ACE_SCORING_EVENT("List.onItemDragLeave");
532         func->ItemDragLeaveExecute(dragInfo, itemIndex);
533     };
534     ListModel::GetInstance()->SetOnItemDragLeave(std::move(onItemDragLeave));
535 }
536 
ItemDropCallback(const JSCallbackInfo & info)537 void JSList::ItemDropCallback(const JSCallbackInfo& info)
538 {
539     if (!info[0]->IsFunction()) {
540         LOGE("fail to bind onItemDrop event due to info is not function");
541         return;
542     }
543 
544     RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
545     auto onItemDrop = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
546                           const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
547         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
548         ACE_SCORING_EVENT("List.onItemDrop");
549         func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
550     };
551     ListModel::GetInstance()->SetOnItemDrop(onItemDrop);
552 }
553 
SetMultiSelectable(bool multiSelectable)554 void JSList::SetMultiSelectable(bool multiSelectable)
555 {
556     ListModel::GetInstance()->SetMultiSelectable(multiSelectable);
557 }
558 
ScrollBeginCallback(const JSCallbackInfo & args)559 void JSList::ScrollBeginCallback(const JSCallbackInfo& args)
560 {
561     if (args[0]->IsFunction()) {
562         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
563                                  const CalcDimension& dx, const CalcDimension& dy) -> ScrollInfo {
564             ScrollInfo scrollInfo { .dx = dx, .dy = dy };
565             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
566             auto params = ConvertToJSValues(dx, dy);
567             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
568             if (result.IsEmpty()) {
569                 LOGE("Error calling onScrollBegin, result is empty.");
570                 return scrollInfo;
571             }
572 
573             if (!result->IsObject()) {
574                 LOGE("Error calling onScrollBegin, result is not object.");
575                 return scrollInfo;
576             }
577 
578             auto resObj = JSRef<JSObject>::Cast(result);
579             auto dxRemainValue = resObj->GetProperty("dxRemain");
580             if (dxRemainValue->IsNumber()) {
581                 scrollInfo.dx = CalcDimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
582             }
583             auto dyRemainValue = resObj->GetProperty("dyRemain");
584             if (dyRemainValue->IsNumber()) {
585                 scrollInfo.dy = CalcDimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
586             }
587             return scrollInfo;
588         };
589         ListModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
590     }
591 }
592 
ScrollFrameBeginCallback(const JSCallbackInfo & args)593 void JSList::ScrollFrameBeginCallback(const JSCallbackInfo& args)
594 {
595     if (args[0]->IsFunction()) {
596         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
597                                  const Dimension& offset, const ScrollState& state) -> ScrollFrameResult {
598             ScrollFrameResult scrollRes { .offset = offset };
599             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
600             auto params = ConvertToJSValues(offset, state);
601             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
602             if (result.IsEmpty()) {
603                 LOGE("Error calling onScrollFrameBegin, result is empty.");
604                 return scrollRes;
605             }
606 
607             if (!result->IsObject()) {
608                 LOGE("Error calling onScrollFrameBegin, result is not object.");
609                 return scrollRes;
610             }
611 
612             auto resObj = JSRef<JSObject>::Cast(result);
613             auto dxRemainValue = resObj->GetProperty("offsetRemain");
614             if (dxRemainValue->IsNumber()) {
615                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
616             }
617             return scrollRes;
618         };
619         ListModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollBegin));
620     }
621 }
622 
JSBind(BindingTarget globalObj)623 void JSList::JSBind(BindingTarget globalObj)
624 {
625     JSClass<JSList>::Declare("List");
626     JSClass<JSList>::StaticMethod("create", &JSList::Create);
627 
628     JSClass<JSList>::StaticMethod("width", &JSList::JsWidth);
629     JSClass<JSList>::StaticMethod("height", &JSList::JsHeight);
630     JSClass<JSList>::StaticMethod("listDirection", &JSList::SetDirection);
631     JSClass<JSList>::StaticMethod("scrollBar", &JSList::SetScrollBar);
632     JSClass<JSList>::StaticMethod("edgeEffect", &JSList::SetEdgeEffect);
633     JSClass<JSList>::StaticMethod("divider", &JSList::SetDivider);
634     JSClass<JSList>::StaticMethod("editMode", &JSList::SetEditMode);
635     JSClass<JSList>::StaticMethod("cachedCount", &JSList::SetCachedCount);
636     JSClass<JSList>::StaticMethod("chainAnimation", &JSList::SetChainAnimation);
637     JSClass<JSList>::StaticMethod("chainAnimationOptions", &JSList::SetChainAnimationOptions);
638     JSClass<JSList>::StaticMethod("multiSelectable", &JSList::SetMultiSelectable);
639     JSClass<JSList>::StaticMethod("alignListItem", &JSList::SetListItemAlign);
640     JSClass<JSList>::StaticMethod("lanes", &JSList::SetLanes);
641     JSClass<JSList>::StaticMethod("sticky", &JSList::SetSticky);
642     JSClass<JSList>::StaticMethod("contentStartOffset", &JSList::SetContentStartOffset);
643     JSClass<JSList>::StaticMethod("contentEndOffset", &JSList::SetContentEndOffset);
644     JSClass<JSList>::StaticMethod("nestedScroll", &JSList::SetNestedScroll);
645     JSClass<JSList>::StaticMethod("enableScrollInteraction", &JSList::SetScrollEnabled);
646     JSClass<JSList>::StaticMethod("scrollSnapAlign", &JSList::SetScrollSnapAlign);
647     JSClass<JSList>::StaticMethod("friction", &JSList::SetFriction);
648 
649     JSClass<JSList>::StaticMethod("onScroll", &JSList::ScrollCallback);
650     JSClass<JSList>::StaticMethod("onReachStart", &JSList::ReachStartCallback);
651     JSClass<JSList>::StaticMethod("onReachEnd", &JSList::ReachEndCallback);
652     JSClass<JSList>::StaticMethod("onScrollStart", &JSList::ScrollStartCallback);
653     JSClass<JSList>::StaticMethod("onScrollStop", &JSList::ScrollStopCallback);
654     JSClass<JSList>::StaticMethod("onItemDelete", &JSList::ItemDeleteCallback);
655     JSClass<JSList>::StaticMethod("onItemMove", &JSList::ItemMoveCallback);
656     JSClass<JSList>::StaticMethod("onScrollIndex", &JSList::ScrollIndexCallback);
657     JSClass<JSList>::StaticMethod("onScrollBegin", &JSList::ScrollBeginCallback);
658     JSClass<JSList>::StaticMethod("onScrollFrameBegin", &JSList::ScrollFrameBeginCallback);
659 
660     JSClass<JSList>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
661     JSClass<JSList>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
662     JSClass<JSList>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
663     JSClass<JSList>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
664     JSClass<JSList>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
665     JSClass<JSList>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
666     JSClass<JSList>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
667 
668     JSClass<JSList>::StaticMethod("onItemDragStart", &JSList::ItemDragStartCallback);
669     JSClass<JSList>::StaticMethod("onItemDragEnter", &JSList::ItemDragEnterCallback);
670     JSClass<JSList>::StaticMethod("onItemDragMove", &JSList::ItemDragMoveCallback);
671     JSClass<JSList>::StaticMethod("onItemDragLeave", &JSList::ItemDragLeaveCallback);
672     JSClass<JSList>::StaticMethod("onItemDrop", &JSList::ItemDropCallback);
673     JSClass<JSList>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
674 
675     JSClass<JSList>::InheritAndBind<JSContainerBase>(globalObj);
676 }
677 
678 } // namespace OHOS::Ace::Framework
679