• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
18 
19 #include "base/geometry/axis.h"
20 #include "base/log/ace_scoring_log.h"
21 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
22 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
23 #include "bridge/declarative_frontend/jsview/js_scrollable.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/list_model_impl.h"
26 #include "core/common/container.h"
27 #include "core/components_ng/base/view_stack_model.h"
28 #include "core/components_ng/base/view_stack_processor.h"
29 #include "core/components_ng/pattern/list/list_model.h"
30 #include "core/components_ng/pattern/list/list_model_ng.h"
31 #include "core/components_ng/pattern/list/list_position_controller.h"
32 #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
33 
34 namespace OHOS::Ace {
35 
36 std::unique_ptr<ListModel> ListModel::instance_ = nullptr;
37 std::mutex ListModel::mutex_;
38 
GetInstance()39 ListModel* ListModel::GetInstance()
40 {
41     if (!instance_) {
42         std::lock_guard<std::mutex> lock(mutex_);
43         if (!instance_) {
44 #ifdef NG_BUILD
45             instance_.reset(new NG::ListModelNG());
46 #else
47             if (Container::IsCurrentUseNewPipeline()) {
48                 instance_.reset(new NG::ListModelNG());
49             } else {
50                 instance_.reset(new Framework::ListModelImpl());
51             }
52 #endif
53         }
54     }
55     return instance_.get();
56 }
57 
58 } // namespace OHOS::Ace
59 
60 namespace OHOS::Ace::Framework {
61 
62 const std::vector<ScrollSnapAlign> SCROLL_SNAP_ALIGN = { ScrollSnapAlign::NONE, ScrollSnapAlign::START,
63     ScrollSnapAlign::CENTER, ScrollSnapAlign::END };
64 
65 namespace {
66 const std::regex DIMENSION_REGEX(R"(^[-+]?\d+(?:\.\d+)?(?:px|vp|fp|lpx)?$)", std::regex::icase);
67 constexpr ScrollAlign ALIGN_TABLE[] = {
68     ScrollAlign::START,
69     ScrollAlign::CENTER,
70     ScrollAlign::END,
71     ScrollAlign::AUTO,
72 };
73 static constexpr int ARGS_LENGTH = 2;
74 }
75 
76 namespace {
ParseChange(const JSRef<JSObject> & changeObject,const float defaultSize,int32_t & start,int32_t & deleteCount,std::vector<float> & newChildrenSize)77 bool ParseChange(const JSRef<JSObject>& changeObject, const float defaultSize, int32_t& start,
78     int32_t& deleteCount, std::vector<float>& newChildrenSize)
79 {
80     if (!JSViewAbstract::ParseJsInteger<int32_t>(changeObject->GetProperty("start"), start) || start < 0) {
81         return false;
82     }
83     if (!(changeObject->HasProperty("deleteCount"))) {
84         // If only input one parameter, set -1 to deleteCount for deleting elements after index 'start' in the array.
85         deleteCount = -1;
86     } else if (!JSViewAbstract::ParseJsInteger<int32_t>(changeObject->GetProperty("deleteCount"), deleteCount) ||
87         deleteCount < 0) {
88         deleteCount = 0;
89     }
90     auto childrenSizeValue = changeObject->GetProperty("childrenSize");
91     if (childrenSizeValue->IsArray()) {
92         auto childrenSize = JSRef<JSArray>::Cast(childrenSizeValue);
93         auto childrenSizeCount = childrenSize->Length();
94         for (size_t j = 0; j < childrenSizeCount; ++j) {
95             // -1.0: represent default size.
96             double childSize = -1.0;
97             if (!JSViewAbstract::ParseJsDouble(childrenSize->GetValueAt(j), childSize) || Negative(childSize)) {
98                 // -1.0f: represent default size.
99                 newChildrenSize.emplace_back(-1.0f);
100             } else {
101                 newChildrenSize.emplace_back(Dimension(childSize, DimensionUnit::VP).ConvertToPx());
102             }
103         }
104     }
105     return true;
106 }
107 
SyncChildrenSize(const JSRef<JSObject> & childrenSizeObj,RefPtr<NG::ListChildrenMainSize> childrenSize)108 void SyncChildrenSize(const JSRef<JSObject>& childrenSizeObj, RefPtr<NG::ListChildrenMainSize> childrenSize)
109 {
110     auto sizeArray = childrenSizeObj->GetProperty("sizeArray");
111     if (!sizeArray->IsArray()) {
112         return;
113     }
114     childrenSize->ResizeChildrenSize(0);
115     auto childrenSizeJSArray = JSRef<JSArray>::Cast(sizeArray);
116     auto length = childrenSizeJSArray->Length();
117     for (size_t i = 0; i < length; ++i) {
118         // -1.0: represent default size.
119         double childSize = -1.0;
120         if (!JSViewAbstract::ParseJsDouble(childrenSizeJSArray->GetValueAt(i), childSize) || Negative(childSize)) {
121             // -1.0f: represent default size.
122             childrenSize->SyncChildrenSize(-1.0f);
123         } else {
124             childrenSize->SyncChildrenSize(Dimension(childSize, DimensionUnit::VP).ConvertToPx());
125         }
126     }
127     childrenSize->SyncChildrenSizeOver();
128 }
129 } // namespace
130 
SetDirection(int32_t direction)131 void JSList::SetDirection(int32_t direction)
132 {
133     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_THIRTEEN) && direction != 0 &&
134         direction != 1) {
135         direction = 0;
136     }
137     ListModel::GetInstance()->SetListDirection(static_cast<Axis>(direction));
138 }
139 
SetScrollBar(const JSCallbackInfo & info)140 void JSList::SetScrollBar(const JSCallbackInfo& info)
141 {
142     auto displayMode = JSScrollable::ParseDisplayMode(info, ListModel::GetInstance()->GetDisplayMode());
143     ListModel::GetInstance()->SetScrollBar(displayMode);
144 }
145 
SetScrollBarColor(const JSCallbackInfo & info)146 void JSList::SetScrollBarColor(const JSCallbackInfo& info)
147 {
148     RefPtr<ResourceObject> resObj;
149     auto scrollBarColor = JSScrollable::ParseBarColor(info, resObj);
150     if (!scrollBarColor.empty()) {
151         ListModel::GetInstance()->SetScrollBarColor(scrollBarColor);
152     }
153     if (SystemProperties::ConfigChangePerform()) {
154         ListModel::GetInstance()->CreateWithResourceObjScrollBarColor(resObj);
155     }
156 }
157 
SetScrollBarWidth(const JSCallbackInfo & scrollWidth)158 void JSList::SetScrollBarWidth(const JSCallbackInfo& scrollWidth)
159 {
160     auto scrollBarWidth = JSScrollable::ParseBarWidth(scrollWidth);
161     if (!scrollBarWidth.empty()) {
162         ListModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
163     }
164 }
165 
SetEdgeEffect(const JSCallbackInfo & info)166 void JSList::SetEdgeEffect(const JSCallbackInfo& info)
167 {
168     auto edgeEffect = EdgeEffect::SPRING;
169     auto effectEdge = EffectEdge::ALL;
170     if (info.Length() > 0) {
171         edgeEffect = JSScrollable::ParseEdgeEffect(info[0], EdgeEffect::SPRING);
172     }
173     auto alwaysEnabled = false;
174     if (info.Length() > 1) {
175         alwaysEnabled = JSScrollable::ParseAlwaysEnable(info[1], false);
176         effectEdge = JSScrollable::ParseEffectEdge(info[1]);
177     }
178     ListModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled, effectEdge);
179 }
180 
SetEditMode(bool editMode)181 void JSList::SetEditMode(bool editMode)
182 {
183     ListModel::GetInstance()->SetEditMode(editMode);
184 }
185 
SetCachedCount(const JSCallbackInfo & info)186 void JSList::SetCachedCount(const JSCallbackInfo& info)
187 {
188     int32_t cachedCount = 1;
189     ParseJsInteger<int32_t>(info[0], cachedCount);
190     cachedCount = cachedCount < 0 ? 1 : cachedCount;
191     bool show = false;
192     // 2: represent 2 params.
193     if (info.Length() == 2) {
194         show = info[1]->ToBoolean();
195     }
196     ListModel::GetInstance()->SetCachedCount(cachedCount, show);
197 }
198 
SetScroller(RefPtr<JSScroller> scroller)199 void JSList::SetScroller(RefPtr<JSScroller> scroller)
200 {
201     if (scroller) {
202         RefPtr<ScrollControllerBase> listController = ListModel::GetInstance()->CreateScrollController();
203         scroller->SetController(listController);
204 
205         // Init scroll bar proxy.
206         auto proxy = scroller->GetScrollBarProxy();
207         if (!proxy) {
208             if (Container::IsCurrentUseNewPipeline()) {
209                 proxy = AceType::MakeRefPtr<NG::ScrollBarProxy>();
210             } else {
211                 proxy = AceType::MakeRefPtr<ScrollBarProxy>();
212             }
213             scroller->SetScrollBarProxy(proxy);
214         }
215         ListModel::GetInstance()->SetScroller(listController, proxy);
216     }
217 }
218 
Create(const JSCallbackInfo & args)219 void JSList::Create(const JSCallbackInfo& args)
220 {
221     ListModel::GetInstance()->Create();
222     if (args.Length() < 1) {
223         return;
224     }
225     JSRef<JSVal> arg0 = args[0];
226     if (arg0->IsObject()) {
227         JSRef<JSObject> obj = JSRef<JSObject>::Cast(arg0);
228         JSRef<JSVal> spaceValue = obj->GetProperty("space");
229         if (!spaceValue->IsNull()) {
230             CalcDimension space;
231             ConvertFromJSValue(spaceValue, space);
232             ListModel::GetInstance()->SetSpace(space);
233         }
234         int32_t initialIndex = 0;
235         if (ConvertFromJSValue(obj->GetProperty("initialIndex"), initialIndex) && initialIndex >= 0) {
236             ListModel::GetInstance()->SetInitialIndex(initialIndex);
237         }
238         JSRef<JSVal> scrollerValue = obj->GetProperty("scroller");
239         if (scrollerValue->IsObject()) {
240             void* scroller = JSRef<JSObject>::Cast(scrollerValue)->Unwrap<JSScroller>();
241             RefPtr<JSScroller> jsScroller = Referenced::Claim(reinterpret_cast<JSScroller*>(scroller));
242             jsScroller->SetInstanceId(Container::CurrentId());
243             SetScroller(jsScroller);
244         }
245     }
246 }
247 
SetChildrenMainSize(const JSCallbackInfo & args)248 void JSList::SetChildrenMainSize(const JSCallbackInfo& args)
249 {
250     if (args.Length() != 1 || !(args[0]->IsObject())) {
251         ListModel::GetInstance()->ResetListChildrenMainSize();
252         return;
253     }
254     SetChildrenMainSize(JSRef<JSObject>::Cast(args[0]));
255 }
256 
SetChildrenMainSize(const JSRef<JSObject> & childrenSizeObj)257 void JSList::SetChildrenMainSize(const JSRef<JSObject>& childrenSizeObj)
258 {
259     double defaultSize = 0.0f;
260     if (!ParseJsDouble(childrenSizeObj->GetProperty("childDefaultSize"), defaultSize) || !NonNegative(defaultSize)) {
261         TAG_LOGW(AceLogTag::ACE_LIST, "JSList input parameter defaultSize check failed.");
262         return;
263     }
264     auto listChildrenMainSize = ListModel::GetInstance()->GetOrCreateListChildrenMainSize();
265     CHECK_NULL_VOID(listChildrenMainSize);
266     listChildrenMainSize->UpdateDefaultSize(Dimension(defaultSize, DimensionUnit::VP).ConvertToPx());
267 
268     if (listChildrenMainSize->NeedSync()) {
269         SyncChildrenSize(childrenSizeObj, listChildrenMainSize);
270     } else {
271         auto changes = childrenSizeObj->GetProperty("changeArray");
272         if (!changes->IsArray()) {
273             return;
274         }
275         auto changeArray = JSRef<JSArray>::Cast(changes);
276         auto length = changeArray->Length();
277         for (size_t i = 0; i < length; ++i) {
278             auto change = changeArray->GetValueAt(i);
279             if (!change->IsObject()) {
280                 continue;
281             }
282             auto changeObject = JSRef<JSObject>::Cast(change);
283             int32_t start = 0;
284             int32_t deleteCount = 0;
285             std::vector<float> newChildrenSize;
286             if (!ParseChange(changeObject, defaultSize, start, deleteCount, newChildrenSize)) {
287                 SyncChildrenSize(childrenSizeObj, listChildrenMainSize);
288                 break;
289             }
290             listChildrenMainSize->ChangeData(start, deleteCount, newChildrenSize);
291         }
292     }
293     auto clearFunc = childrenSizeObj->GetProperty("clearChanges");
294     if (!clearFunc->IsFunction()) {
295         return;
296     }
297     auto func = JSRef<JSFunc>::Cast(clearFunc);
298     JSRef<JSVal>::Cast(func->Call(childrenSizeObj));
299 }
300 
SetChainAnimation(const JSCallbackInfo & args)301 void JSList::SetChainAnimation(const JSCallbackInfo& args)
302 {
303     ListModel::GetInstance()->SetChainAnimation(args[0]->IsBoolean() ? args[0]->ToBoolean() : false);
304 }
305 
SetChainAnimationOptions(const JSCallbackInfo & info)306 void JSList::SetChainAnimationOptions(const JSCallbackInfo& info)
307 {
308     if (info.Length() < 1) {
309         return;
310     }
311 
312     if (info[0]->IsObject()) {
313         RefPtr<ListTheme> listTheme = GetTheme<ListTheme>();
314         CHECK_NULL_VOID(listTheme);
315         ChainAnimationOptions options = {
316             .minSpace = listTheme->GetChainMinSpace(),
317             .maxSpace = listTheme->GetChainMaxSpace(),
318             .conductivity = listTheme->GetChainConductivity(),
319             .intensity = listTheme->GetChainIntensity(),
320             .edgeEffect = 0,
321             .stiffness = listTheme->GetChainStiffness(),
322             .damping = listTheme->GetChainDamping(),
323         };
324         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
325         ParseJsDimensionVp(jsObj->GetProperty("minSpace"), options.minSpace);
326         ParseJsDimensionVp(jsObj->GetProperty("maxSpace"), options.maxSpace);
327         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("conductivity"), options.conductivity);
328         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("intensity"), options.intensity);
329         JSViewAbstract::ParseJsInt32(jsObj->GetProperty("edgeEffect"), options.edgeEffect);
330         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("stiffness"), options.stiffness);
331         JSViewAbstract::ParseJsDouble(jsObj->GetProperty("damping"), options.damping);
332         ListModel::GetInstance()->SetChainAnimationOptions(options);
333     }
334 }
335 
JsWidth(const JSCallbackInfo & info)336 void JSList::JsWidth(const JSCallbackInfo& info)
337 {
338     JSViewAbstract::JsWidth(info);
339     ListModel::GetInstance()->SetHasWidth(true);
340 }
341 
JsHeight(const JSCallbackInfo & info)342 void JSList::JsHeight(const JSCallbackInfo& info)
343 {
344     JSViewAbstract::JsHeight(info);
345     ListModel::GetInstance()->SetHasHeight(true);
346 }
347 
SetListItemAlign(int32_t itemAlignment)348 void JSList::SetListItemAlign(int32_t itemAlignment)
349 {
350     ListModel::GetInstance()->SetListItemAlign(static_cast<V2::ListItemAlign>(itemAlignment));
351 }
352 
SetLanes(const JSCallbackInfo & info)353 void JSList::SetLanes(const JSCallbackInfo& info)
354 {
355     if (info.Length() < 1) {
356         return;
357     }
358 
359     if (info.Length() >= 2 && !(info[1]->IsNull())) { /* 2: parameter count */
360         CalcDimension laneGutter;
361         RefPtr<ResourceObject> resObjLaneGutter;
362         if (JSViewAbstract::ParseJsDimensionVp(info[1], laneGutter, resObjLaneGutter)) {
363             if (laneGutter.IsNegative()) {
364                 laneGutter.Reset();
365             }
366         }
367         if (SystemProperties::ConfigChangePerform()) {
368             ListModel::GetInstance()->CreateWithResourceObjLaneGutter(resObjLaneGutter);
369         }
370         ListModel::GetInstance()->SetLaneGutter(laneGutter);
371     }
372 
373     int32_t laneNum = 1;
374     if (ParseJsInteger<int32_t>(info[0], laneNum)) {
375         // when [lanes] is set, [laneConstrain_] of list component will be reset to std::nullopt
376         ListModel::GetInstance()->SetLanes(laneNum);
377         ListModel::GetInstance()->SetLaneConstrain(-1.0_vp, -1.0_vp);
378         return;
379     }
380     RefPtr<ResourceObject> resObjMinLengthValue;
381     RefPtr<ResourceObject> resObjMaxLengthValue;
382     if (info[0]->IsObject()) {
383         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
384         auto minLengthParam = jsObj->GetProperty("minLength");
385         auto maxLengthParam = jsObj->GetProperty("maxLength");
386         if (minLengthParam->IsNull() || maxLengthParam->IsNull()) {
387             TAG_LOGW(AceLogTag::ACE_LIST, "minLength and maxLength are not both set");
388             if (SystemProperties::ConfigChangePerform()) {
389                 ListModel::GetInstance()->CreateWithResourceObjLaneConstrain(nullptr, nullptr);
390             }
391             return;
392         }
393         CalcDimension minLengthValue;
394         CalcDimension maxLengthValue;
395         if (!ParseJsDimensionVp(minLengthParam, minLengthValue, resObjMinLengthValue)
396             || !ParseJsDimensionVp(maxLengthParam, maxLengthValue, resObjMaxLengthValue)) {
397             ListModel::GetInstance()->SetLanes(1);
398             ListModel::GetInstance()->SetLaneConstrain(-1.0_vp, -1.0_vp);
399             return;
400         }
401         ListModel::GetInstance()->SetLaneConstrain(minLengthValue, maxLengthValue);
402     }
403     ListModel::GetInstance()->SetLanes(1);
404     ListModel::GetInstance()->CreateWithResourceObjLaneConstrain(resObjMinLengthValue, resObjMaxLengthValue);
405 }
406 
SetSticky(int32_t sticky)407 void JSList::SetSticky(int32_t sticky)
408 {
409     ListModel::GetInstance()->SetSticky(static_cast<V2::StickyStyle>(sticky));
410 }
411 
SetContentStartOffset(const JSCallbackInfo & info)412 void JSList::SetContentStartOffset(const JSCallbackInfo& info)
413 {
414     double value = 0.0;
415     ParseJsDouble(info[0], value);
416     ListModel::GetInstance()->SetContentStartOffset(value);
417 }
418 
SetContentEndOffset(const JSCallbackInfo & info)419 void JSList::SetContentEndOffset(const JSCallbackInfo& info)
420 {
421     double value = 0.0;
422     ParseJsDouble(info[0], value);
423     ListModel::GetInstance()->SetContentEndOffset(value);
424 }
425 
SetScrollSnapAlign(int32_t scrollSnapAlign)426 void JSList::SetScrollSnapAlign(int32_t scrollSnapAlign)
427 {
428     ScrollSnapAlign param;
429     if (scrollSnapAlign < 0 || scrollSnapAlign >= static_cast<int32_t>(SCROLL_SNAP_ALIGN.size())) {
430         param = ScrollSnapAlign::NONE;
431     } else {
432         param = ScrollSnapAlign(scrollSnapAlign);
433     }
434     ListModel::GetInstance()->SetScrollSnapAlign(param);
435 }
436 
SetDivider(const JSCallbackInfo & args)437 void JSList::SetDivider(const JSCallbackInfo& args)
438 {
439     V2::ItemDivider divider;
440     if (args.Length() >= 1 && args[0]->IsObject()) {
441         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
442         RefPtr<ResourceObject> resObjStrokeWidth;
443         RefPtr<ResourceObject> resObjColor;
444         RefPtr<ResourceObject> resObjStartMargin;
445         RefPtr<ResourceObject> resObjEndMargin;
446         bool needReset = obj->GetProperty("strokeWidth")->IsString() &&
447                          !std::regex_match(obj->GetProperty("strokeWidth")->ToString(), DIMENSION_REGEX);
448         if (needReset ||
449             !ConvertFromJSValue(obj->GetProperty("strokeWidth"), divider.strokeWidth, resObjStrokeWidth)) {
450             divider.strokeWidth = 0.0_vp;
451         }
452         bool setByUser = false;
453         if (!ConvertFromJSValue(obj->GetProperty("color"), divider.color, resObjColor)) {
454             // Failed to get color from param, using default color defined in theme
455             RefPtr<ListTheme> listTheme = GetTheme<ListTheme>();
456             if (listTheme) {
457                 divider.color = listTheme->GetDividerColor();
458                 setByUser = false;
459             }
460         } else {
461             setByUser = true;
462         }
463         ListModel::GetInstance()->SetDividerColorByUser(setByUser);
464 
465         needReset = obj->GetProperty("startMargin")->IsString() &&
466                     !std::regex_match(obj->GetProperty("startMargin")->ToString(), DIMENSION_REGEX);
467         if (needReset ||
468             !ConvertFromJSValue(obj->GetProperty("startMargin"), divider.startMargin, resObjStartMargin)) {
469             divider.startMargin = 0.0_vp;
470         }
471 
472         needReset = obj->GetProperty("endMargin")->IsString() &&
473                     !std::regex_match(obj->GetProperty("endMargin")->ToString(), DIMENSION_REGEX);
474         if (needReset || !ConvertFromJSValue(obj->GetProperty("endMargin"), divider.endMargin, resObjEndMargin)) {
475             divider.endMargin = 0.0_vp;
476         }
477 
478         if (SystemProperties::ConfigChangePerform()) {
479             ListModel::GetInstance()->ParseResObjDividerStrokeWidth(resObjStrokeWidth);
480             ListModel::GetInstance()->ParseResObjDividerColor(resObjColor);
481             ListModel::GetInstance()->ParseResObjDividerStartMargin(resObjStartMargin);
482             ListModel::GetInstance()->ParseResObjDividerEndMargin(resObjEndMargin);
483         }
484     }
485     ListModel::GetInstance()->SetDivider(divider);
486     args.ReturnSelf();
487 }
488 
SetNestedScroll(const JSCallbackInfo & args)489 void JSList::SetNestedScroll(const JSCallbackInfo& args)
490 {
491     NestedScrollOptions nestedOpt = {
492         .forward = NestedScrollMode::SELF_ONLY,
493         .backward = NestedScrollMode::SELF_ONLY,
494     };
495     if (args.Length() < 1 || !args[0]->IsObject()) {
496         ListModel::GetInstance()->SetNestedScroll(nestedOpt);
497         return;
498     }
499     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
500     int32_t froward = 0;
501     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
502     if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
503         froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
504         froward = 0;
505     }
506     int32_t backward = 0;
507     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
508     if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
509         backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
510         backward = 0;
511     }
512     nestedOpt.forward = static_cast<NestedScrollMode>(froward);
513     nestedOpt.backward = static_cast<NestedScrollMode>(backward);
514     ListModel::GetInstance()->SetNestedScroll(nestedOpt);
515     args.ReturnSelf();
516 }
517 
SetScrollEnabled(const JSCallbackInfo & args)518 void JSList::SetScrollEnabled(const JSCallbackInfo& args)
519 {
520     ListModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
521 }
522 
ScrollCallback(const JSCallbackInfo & args)523 void JSList::ScrollCallback(const JSCallbackInfo& args)
524 {
525     if (args[0]->IsFunction()) {
526         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
527                             const CalcDimension& scrollOffset, const ScrollState& scrollState) {
528             auto params = ConvertToJSValues(scrollOffset, scrollState);
529             func->Call(JSRef<JSObject>(), params.size(), params.data());
530             return;
531         };
532         ListModel::GetInstance()->SetOnScroll(std::move(onScroll));
533     }
534     args.ReturnSelf();
535 }
536 
SetFriction(const JSCallbackInfo & info)537 void JSList::SetFriction(const JSCallbackInfo& info)
538 {
539     double friction = -1.0;
540     RefPtr<ResourceObject> resObj;
541     if (!JSViewAbstract::ParseJsDouble(info[0], friction, resObj)) {
542         friction = -1.0;
543     }
544     if (SystemProperties::ConfigChangePerform()) {
545         ListModel::GetInstance()->CreateWithResourceObjFriction(resObj);
546     }
547     ListModel::GetInstance()->SetFriction(friction);
548 }
549 
SetFocusWrapMode(const JSCallbackInfo & args)550 void JSList::SetFocusWrapMode(const JSCallbackInfo& args)
551 {
552     if (args.Length() < 1) {
553         return;
554     }
555     auto focusWrapMode = static_cast<int32_t>(FocusWrapMode::DEFAULT);
556     if (!JSViewAbstract::ParseJsInt32(args[0], focusWrapMode) ||
557         focusWrapMode < static_cast<int32_t>(FocusWrapMode::DEFAULT) ||
558         focusWrapMode > static_cast<int32_t>(FocusWrapMode::WRAP_WITH_ARROW)) {
559         focusWrapMode = static_cast<int32_t>(FocusWrapMode::DEFAULT);
560     }
561     ListModel::GetInstance()->SetFocusWrapMode(static_cast<FocusWrapMode>(focusWrapMode));
562 }
563 
MaintainVisibleContentPosition(const JSCallbackInfo & args)564 void JSList::MaintainVisibleContentPosition(const JSCallbackInfo& args)
565 {
566     bool enabled = false;
567     JSRef<JSVal> arg0 = args[0];
568     if (arg0->IsBoolean()) {
569         enabled = arg0->ToBoolean();
570     }
571     ListModel::GetInstance()->SetMaintainVisibleContentPosition(enabled);
572 }
573 
SetStackFromEnd(const JSCallbackInfo & args)574 void JSList::SetStackFromEnd(const JSCallbackInfo& args)
575 {
576     bool enabled = false;
577     JSRef<JSVal> arg0 = args[0];
578     if (arg0->IsBoolean()) {
579         enabled = arg0->ToBoolean();
580     }
581     ListModel::GetInstance()->SetStackFromEnd(enabled);
582 }
583 
SetSyncLoad(const JSCallbackInfo & args)584 void JSList::SetSyncLoad(const JSCallbackInfo& args)
585 {
586     bool enabled = true;
587     JSRef<JSVal> arg0 = args[0];
588     if (arg0->IsBoolean()) {
589         enabled = arg0->ToBoolean();
590     }
591     ListModel::GetInstance()->SetSyncLoad(enabled);
592 }
593 
ReachStartCallback(const JSCallbackInfo & args)594 void JSList::ReachStartCallback(const JSCallbackInfo& args)
595 {
596     if (args.Length() <= 0) {
597         return;
598     }
599     if (args[0]->IsFunction()) {
600         auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
601             func->Call(JSRef<JSObject>());
602             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onReachStart");
603             return;
604         };
605         ListModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
606     } else {
607         ListModel::GetInstance()->SetOnReachStart(nullptr);
608     }
609     args.ReturnSelf();
610 }
611 
ReachEndCallback(const JSCallbackInfo & args)612 void JSList::ReachEndCallback(const JSCallbackInfo& args)
613 {
614     if (args.Length() <= 0) {
615         return;
616     }
617     if (args[0]->IsFunction()) {
618         auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
619             func->Call(JSRef<JSObject>());
620             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onReachEnd");
621             return;
622         };
623         ListModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
624     } else {
625         ListModel::GetInstance()->SetOnReachEnd(nullptr);
626     }
627     args.ReturnSelf();
628 }
629 
ScrollStartCallback(const JSCallbackInfo & args)630 void JSList::ScrollStartCallback(const JSCallbackInfo& args)
631 {
632     if (args.Length() <= 0) {
633         return;
634     }
635     if (args[0]->IsFunction()) {
636         auto onScrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
637             func->Call(JSRef<JSObject>());
638             return;
639         };
640         ListModel::GetInstance()->SetOnScrollStart(std::move(onScrollStart));
641     } else {
642         ListModel::GetInstance()->SetOnScrollStart(nullptr);
643     }
644     args.ReturnSelf();
645 }
646 
ScrollStopCallback(const JSCallbackInfo & args)647 void JSList::ScrollStopCallback(const JSCallbackInfo& args)
648 {
649     if (args.Length() <= 0) {
650         return;
651     }
652     if (args[0]->IsFunction()) {
653         auto onScrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
654             func->Call(JSRef<JSObject>());
655             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollStop");
656             return;
657         };
658         ListModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
659     } else {
660         ListModel::GetInstance()->SetOnScrollStop(nullptr);
661     }
662     args.ReturnSelf();
663 }
664 
ItemDeleteCallback(const JSCallbackInfo & args)665 void JSList::ItemDeleteCallback(const JSCallbackInfo& args)
666 {
667     if (args[0]->IsFunction()) {
668         auto onItemDelete = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
669                                 int32_t index) -> bool {
670             auto params = ConvertToJSValues(index);
671             func->Call(JSRef<JSObject>(), params.size(), params.data());
672             return true;
673         };
674         ListModel::GetInstance()->SetOnItemDelete(std::move(onItemDelete));
675     }
676     args.ReturnSelf();
677 }
678 
ItemMoveCallback(const JSCallbackInfo & args)679 void JSList::ItemMoveCallback(const JSCallbackInfo& args)
680 {
681     if (args[0]->IsFunction()) {
682         auto onItemMove = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
683                               int32_t start, int32_t end) -> bool {
684             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
685             auto params = ConvertToJSValues(start, end);
686             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
687             if (!result.IsEmpty() && result->IsBoolean()) {
688                 return result->ToBoolean();
689             }
690             return true;
691         };
692         ListModel::GetInstance()->SetOnItemMove(std::move(onItemMove));
693     }
694     args.ReturnSelf();
695 }
696 
ScrollIndexCallback(const JSCallbackInfo & args)697 void JSList::ScrollIndexCallback(const JSCallbackInfo& args)
698 {
699     if (args[0]->IsFunction()) {
700         auto onScrollIndex = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
701                                  const int32_t start, const int32_t end, const int32_t center) {
702             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
703             auto params = ConvertToJSValues(start, end, center);
704             func->Call(JSRef<JSObject>(), params.size(), params.data());
705             return;
706         };
707         ListModel::GetInstance()->SetOnScrollIndex(std::move(onScrollIndex));
708     }
709     args.ReturnSelf();
710 }
711 
ScrollVisibleContentChangeCallback(const JSCallbackInfo & args)712 void JSList::ScrollVisibleContentChangeCallback(const JSCallbackInfo& args)
713 {
714     if (args[0]->IsFunction()) {
715         auto onScrollVisibleContentChange = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
716                                  const ListItemIndex start, const ListItemIndex end) {
717             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
718 
719             JSRef<JSObject> startInfo = JSRef<JSObject>::New();
720             SetListItemIndex(startInfo, start);
721             JSRef<JSVal> startParam = JSRef<JSObject>::Cast(startInfo);
722 
723             JSRef<JSObject> endInfo = JSRef<JSObject>::New();
724             SetListItemIndex(endInfo, end);
725             JSRef<JSVal> endParam = JSRef<JSObject>::Cast(endInfo);
726 
727             JSRef<JSVal> params[] = { startParam, endParam };
728             func->Call(JSRef<JSObject>(), 2, params);
729             return;
730         };
731         ListModel::GetInstance()->SetOnScrollVisibleContentChange(std::move(onScrollVisibleContentChange));
732     }
733     args.ReturnSelf();
734 }
735 
SetListItemIndex(JSRef<JSObject> listItemInfo,ListItemIndex indexInfo)736 void JSList::SetListItemIndex(JSRef<JSObject> listItemInfo, ListItemIndex indexInfo)
737 {
738     listItemInfo->SetProperty<int32_t>("index", indexInfo.index);
739     if (indexInfo.indexInGroup != -1) {
740         listItemInfo->SetProperty<int32_t>("itemIndexInGroup", indexInfo.indexInGroup);
741     }
742     if (indexInfo.area != -1) {
743         listItemInfo->SetProperty<int32_t>("itemGroupArea", indexInfo.area);
744     }
745 }
746 
ItemDragStartCallback(const JSCallbackInfo & info)747 void JSList::ItemDragStartCallback(const JSCallbackInfo& info)
748 {
749     if (!info[0]->IsFunction()) {
750         return;
751     }
752 
753     RefPtr<JsDragFunction> jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
754     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
755     auto onItemDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc), node = frameNode](
756                                const ItemDragInfo& dragInfo, int32_t itemIndex) -> RefPtr<AceType> {
757         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, nullptr);
758         auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
759         if (!ret->IsObject()) {
760             return nullptr;
761         }
762 
763         auto builderObj = JSRef<JSObject>::Cast(ret);
764         auto builder = builderObj->GetProperty("builder");
765         if (!builder->IsFunction()) {
766             return nullptr;
767         }
768         auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
769         if (!builderFunc) {
770             return nullptr;
771         }
772         // use another VSP instance while executing the builder function
773         ViewStackModel::GetInstance()->NewScope();
774         {
775             ACE_SCORING_EVENT("List.onItemDragStart.builder");
776             PipelineContext::SetCallBackNode(node);
777             builderFunc->Execute();
778         }
779         return ViewStackModel::GetInstance()->Finish();
780     };
781     ListModel::GetInstance()->SetOnItemDragStart(std::move(onItemDragStart));
782 }
783 
ItemDragEnterCallback(const JSCallbackInfo & info)784 void JSList::ItemDragEnterCallback(const JSCallbackInfo& info)
785 {
786     if (!info[0]->IsFunction()) {
787         return;
788     }
789     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
790     RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
791     auto onItemDragEnter = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc),
792                                node = frameNode](const ItemDragInfo& dragInfo) {
793         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
794         ACE_SCORING_EVENT("List.onItemDragEnter");
795         PipelineContext::SetCallBackNode(node);
796         func->ItemDragEnterExecute(dragInfo);
797     };
798     ListModel::GetInstance()->SetOnItemDragEnter(std::move(onItemDragEnter));
799 }
800 
ItemDragMoveCallback(const JSCallbackInfo & info)801 void JSList::ItemDragMoveCallback(const JSCallbackInfo& info)
802 {
803     if (!info[0]->IsFunction()) {
804         return;
805     }
806 
807     RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
808     auto onItemDragMove = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
809                               const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
810         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
811         ACE_SCORING_EVENT("List.onItemDragMove");
812         func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
813     };
814     ListModel::GetInstance()->SetOnItemDragMove(std::move(onItemDragMove));
815 }
816 
ItemDragLeaveCallback(const JSCallbackInfo & info)817 void JSList::ItemDragLeaveCallback(const JSCallbackInfo& info)
818 {
819     if (!info[0]->IsFunction()) {
820         return;
821     }
822 
823     RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
824     auto onItemDragLeave = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
825                                const ItemDragInfo& dragInfo, int32_t itemIndex) {
826         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
827         ACE_SCORING_EVENT("List.onItemDragLeave");
828         func->ItemDragLeaveExecute(dragInfo, itemIndex);
829     };
830     ListModel::GetInstance()->SetOnItemDragLeave(std::move(onItemDragLeave));
831 }
832 
ItemDropCallback(const JSCallbackInfo & info)833 void JSList::ItemDropCallback(const JSCallbackInfo& info)
834 {
835     if (!info[0]->IsFunction()) {
836         return;
837     }
838 
839     RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
840     auto onItemDrop = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
841                           const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
842         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
843         ACE_SCORING_EVENT("List.onItemDrop");
844         func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
845         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "List.onItemDrop");
846     };
847     ListModel::GetInstance()->SetOnItemDrop(onItemDrop);
848 }
849 
SetMultiSelectable(bool multiSelectable)850 void JSList::SetMultiSelectable(bool multiSelectable)
851 {
852     ListModel::GetInstance()->SetMultiSelectable(multiSelectable);
853 }
854 
ScrollBeginCallback(const JSCallbackInfo & args)855 void JSList::ScrollBeginCallback(const JSCallbackInfo& args)
856 {
857     if (args[0]->IsFunction()) {
858         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
859                                  const CalcDimension& dx, const CalcDimension& dy) -> ScrollInfo {
860             ScrollInfo scrollInfo { .dx = dx, .dy = dy };
861             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
862             auto params = ConvertToJSValues(dx, dy);
863             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
864             if (result.IsEmpty()) {
865                 return scrollInfo;
866             }
867 
868             if (!result->IsObject()) {
869                 return scrollInfo;
870             }
871 
872             auto resObj = JSRef<JSObject>::Cast(result);
873             auto dxRemainValue = resObj->GetProperty("dxRemain");
874             if (dxRemainValue->IsNumber()) {
875                 scrollInfo.dx = CalcDimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
876             }
877             auto dyRemainValue = resObj->GetProperty("dyRemain");
878             if (dyRemainValue->IsNumber()) {
879                 scrollInfo.dy = CalcDimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
880             }
881             return scrollInfo;
882         };
883         ListModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
884     }
885 }
886 
ScrollFrameBeginCallback(const JSCallbackInfo & args)887 void JSList::ScrollFrameBeginCallback(const JSCallbackInfo& args)
888 {
889     if (args[0]->IsFunction()) {
890         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
891                                  const Dimension& offset, const ScrollState& state) -> ScrollFrameResult {
892             ScrollFrameResult scrollRes { .offset = offset };
893             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
894             auto params = ConvertToJSValues(offset, state);
895             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
896             if (result.IsEmpty()) {
897                 return scrollRes;
898             }
899 
900             if (!result->IsObject()) {
901                 return scrollRes;
902             }
903 
904             auto resObj = JSRef<JSObject>::Cast(result);
905             auto dxRemainValue = resObj->GetProperty("offsetRemain");
906             if (dxRemainValue->IsNumber()) {
907                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
908             }
909             return scrollRes;
910         };
911         ListModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollBegin));
912     }
913 }
914 
JSBind(BindingTarget globalObj)915 void JSList::JSBind(BindingTarget globalObj)
916 {
917     JSClass<JSList>::Declare("List");
918     JSClass<JSList>::StaticMethod("create", &JSList::Create);
919     JSClass<JSList>::StaticMethod("width", &JSList::JsWidth);
920     JSClass<JSList>::StaticMethod("height", &JSList::JsHeight);
921     JSClass<JSList>::StaticMethod("clip", &JSScrollable::JsClip);
922     JSClass<JSList>::StaticMethod("listDirection", &JSList::SetDirection);
923     JSClass<JSList>::StaticMethod("scrollBar", &JSList::SetScrollBar);
924     JSClass<JSList>::StaticMethod("scrollBarWidth", &JSList::SetScrollBarWidth);
925     JSClass<JSList>::StaticMethod("scrollBarColor", &JSList::SetScrollBarColor);
926     JSClass<JSList>::StaticMethod("edgeEffect", &JSList::SetEdgeEffect);
927     JSClass<JSList>::StaticMethod("divider", &JSList::SetDivider);
928     JSClass<JSList>::StaticMethod("editMode", &JSList::SetEditMode);
929     JSClass<JSList>::StaticMethod("cachedCount", &JSList::SetCachedCount);
930     JSClass<JSList>::StaticMethod("chainAnimation", &JSList::SetChainAnimation);
931     JSClass<JSList>::StaticMethod("chainAnimationOptions", &JSList::SetChainAnimationOptions);
932     JSClass<JSList>::StaticMethod("childrenMainSize", &JSList::SetChildrenMainSize);
933     JSClass<JSList>::StaticMethod("multiSelectable", &JSList::SetMultiSelectable);
934     JSClass<JSList>::StaticMethod("alignListItem", &JSList::SetListItemAlign);
935     JSClass<JSList>::StaticMethod("lanes", &JSList::SetLanes);
936     JSClass<JSList>::StaticMethod("sticky", &JSList::SetSticky);
937     JSClass<JSList>::StaticMethod("contentStartOffset", &JSList::SetContentStartOffset);
938     JSClass<JSList>::StaticMethod("contentEndOffset", &JSList::SetContentEndOffset);
939     JSClass<JSList>::StaticMethod("nestedScroll", &JSList::SetNestedScroll);
940     JSClass<JSList>::StaticMethod("enableScrollInteraction", &JSList::SetScrollEnabled);
941     JSClass<JSList>::StaticMethod("scrollSnapAlign", &JSList::SetScrollSnapAlign);
942     JSClass<JSList>::StaticMethod("friction", &JSList::SetFriction);
943     JSClass<JSList>::StaticMethod("focusWrapMode", &JSList::SetFocusWrapMode);
944     JSClass<JSList>::StaticMethod("maintainVisibleContentPosition", &JSList::MaintainVisibleContentPosition);
945     JSClass<JSList>::StaticMethod("stackFromEnd", &JSList::SetStackFromEnd);
946     JSClass<JSList>::StaticMethod("syncLoad", &JSList::SetSyncLoad);
947     JSClass<JSList>::StaticMethod("onScroll", &JSList::ScrollCallback);
948     JSClass<JSList>::StaticMethod("onReachStart", &JSList::ReachStartCallback);
949     JSClass<JSList>::StaticMethod("onReachEnd", &JSList::ReachEndCallback);
950     JSClass<JSList>::StaticMethod("onScrollStart", &JSList::ScrollStartCallback);
951     JSClass<JSList>::StaticMethod("onScrollStop", &JSList::ScrollStopCallback);
952     JSClass<JSList>::StaticMethod("onItemDelete", &JSList::ItemDeleteCallback);
953     JSClass<JSList>::StaticMethod("onItemMove", &JSList::ItemMoveCallback);
954     JSClass<JSList>::StaticMethod("onScrollIndex", &JSList::ScrollIndexCallback);
955     JSClass<JSList>::StaticMethod("onScrollVisibleContentChange", &JSList::ScrollVisibleContentChangeCallback);
956     JSClass<JSList>::StaticMethod("onScrollBegin", &JSList::ScrollBeginCallback);
957     JSClass<JSList>::StaticMethod("onScrollFrameBegin", &JSList::ScrollFrameBeginCallback);
958     JSClass<JSList>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
959     JSClass<JSList>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
960     JSClass<JSList>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
961     JSClass<JSList>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
962     JSClass<JSList>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
963     JSClass<JSList>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
964     JSClass<JSList>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
965     JSClass<JSList>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
966     JSClass<JSList>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
967 
968     JSClass<JSList>::StaticMethod("onItemDragStart", &JSList::ItemDragStartCallback);
969     JSClass<JSList>::StaticMethod("onItemDragEnter", &JSList::ItemDragEnterCallback);
970     JSClass<JSList>::StaticMethod("onItemDragMove", &JSList::ItemDragMoveCallback);
971     JSClass<JSList>::StaticMethod("onItemDragLeave", &JSList::ItemDragLeaveCallback);
972     JSClass<JSList>::StaticMethod("onItemDrop", &JSList::ItemDropCallback);
973     JSClass<JSList>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
974 
975     JSClass<JSList>::InheritAndBind<JSScrollableBase>(globalObj);
976 }
977 
JSBind(BindingTarget globalObj)978 void JSListScroller::JSBind(BindingTarget globalObj)
979 {
980     JSClass<JSListScroller>::Declare("ListScroller");
981     JSClass<JSListScroller>::CustomMethod("getItemRectInGroup", &JSListScroller::GetItemRectInGroup);
982     JSClass<JSListScroller>::CustomMethod("scrollToItemInGroup", &JSListScroller::ScrollToItemInGroup);
983     JSClass<JSListScroller>::CustomMethod("closeAllSwipeActions", &JSListScroller::CloseAllSwipeActions);
984     JSClass<JSListScroller>::CustomMethod("getVisibleListContentInfo", &JSListScroller::GetVisibleListContentInfo);
985     JSClass<JSListScroller>::InheritAndBind<JSScroller>(globalObj, JSListScroller::Constructor,
986         JSListScroller::Destructor);
987 }
988 
Constructor(const JSCallbackInfo & args)989 void JSListScroller::Constructor(const JSCallbackInfo& args)
990 {
991     auto scroller = Referenced::MakeRefPtr<JSListScroller>();
992     scroller->IncRefCount();
993     args.SetReturnValue(Referenced::RawPtr(scroller));
994 }
995 
Destructor(JSListScroller * scroller)996 void JSListScroller::Destructor(JSListScroller* scroller)
997 {
998     if (scroller != nullptr) {
999         scroller->DecRefCount();
1000     }
1001 }
1002 
GetItemRectInGroup(const JSCallbackInfo & args)1003 void JSListScroller::GetItemRectInGroup(const JSCallbackInfo& args)
1004 {
1005     int32_t index = -1;
1006     int32_t indexInGroup = -1;
1007     // Parameter passed into function must be 2.
1008     if (args.Length() != 2 || !ConvertFromJSValue(args[0], index) || !ConvertFromJSValue(args[1], indexInGroup)) {
1009         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1010         return;
1011     }
1012     auto scrollController = GetController().Upgrade();
1013     if (scrollController) {
1014         ContainerScope scope(GetInstanceId());
1015         auto rectObj = CreateRectangle(scrollController->GetItemRectInGroup(index, indexInGroup));
1016         JSRef<JSVal> rect = JSRef<JSObject>::Cast(rectObj);
1017         args.SetReturnValue(rect);
1018     } else {
1019         JSException::Throw(ERROR_CODE_NAMED_ROUTE_ERROR, "%s", "Controller not bound to component.");
1020     }
1021 }
1022 
GetVisibleListContentInfo(const JSCallbackInfo & args)1023 void JSListScroller::GetVisibleListContentInfo(const JSCallbackInfo& args)
1024 {
1025     if (args.Length() != ARGS_LENGTH) {
1026         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter length failed.");
1027         return;
1028     }
1029 
1030     Dimension xOffset;
1031     Dimension yOffset;
1032     if (!ConvertFromJSValue(args[0], xOffset) ||
1033         !ConvertFromJSValue(args[1], yOffset)) {
1034         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1035         return;
1036     }
1037     auto scrollController =  GetController().Upgrade();
1038     if (!scrollController) {
1039         JSException::Throw(ERROR_CODE_NAMED_ROUTE_ERROR, "%s", "Controller not bound to component.");
1040         return;
1041     }
1042 
1043     ContainerScope scope(GetInstanceId());
1044     auto deltaX = xOffset.Value();
1045     auto deltaY = yOffset.Value();
1046     auto container = Container::Current();
1047     if (container) {
1048         auto context = container->GetPipelineContext();
1049         if (context) {
1050             deltaX = context->NormalizeToPx(xOffset);
1051             deltaY = context->NormalizeToPx(yOffset);
1052             JSRef<JSObject> retObj = JSRef<JSObject>::New();
1053             auto itemGroup = scrollController->GetItemIndexInGroup(deltaX, deltaY);
1054             retObj->SetProperty<int32_t>("index", itemGroup.index);
1055             if (itemGroup.area == -1) {
1056                 retObj->SetProperty("itemGroupArea", JSVal::Undefined());
1057             } else {
1058                 retObj->SetProperty<int32_t>("itemGroupArea", itemGroup.area);
1059             }
1060 
1061             if (itemGroup.indexInGroup == -1) {
1062                 retObj->SetProperty("itemIndexInGroup", JSVal::Undefined());
1063             } else {
1064                 retObj->SetProperty<int32_t>("itemIndexInGroup", itemGroup.indexInGroup);
1065             }
1066 
1067             args.SetReturnValue(retObj);
1068         }
1069     }
1070     return;
1071 }
1072 
ScrollToItemInGroup(const JSCallbackInfo & args)1073 void JSListScroller::ScrollToItemInGroup(const JSCallbackInfo& args)
1074 {
1075     int32_t index = 0;
1076     int32_t indexInGroup = 0;
1077     bool smooth = false;
1078     ScrollAlign align = ScrollAlign::NONE;
1079 
1080     if (args.Length() < 1) {
1081         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1082         return;
1083     }
1084 
1085     auto scrollController = GetController().Upgrade();
1086     if (!scrollController) {
1087         JSException::Throw(ERROR_CODE_NAMED_ROUTE_ERROR, "%s", "Controller not bound to component.");
1088         return;
1089     }
1090 
1091     if (!ConvertFromJSValue(args[0], index)) {
1092         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1093         return;
1094     }
1095     if (index < 0) {
1096         return;
1097     }
1098 
1099     if (args.Length() >= 2) { // 2 is param count
1100         if (!ConvertFromJSValue(args[1], indexInGroup)) {
1101             JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1102             return;
1103         }
1104         if (indexInGroup < 0) {
1105             return;
1106         }
1107     }
1108 
1109     if (args.Length() >= 3) { // 3 is param count
1110         if (!args[2]->IsBoolean()) { // 2 is the param index of smooth
1111             JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1112             return;
1113         }
1114         smooth = args[2]->ToBoolean(); // 2 is the param index of smooth
1115     }
1116 
1117     if (args.Length() == 4) { // 4 is param count
1118         if (!ConvertFromJSValue(args[3], ALIGN_TABLE, align)) { // 3 is param count of align
1119             JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1120             return;
1121         }
1122     }
1123 
1124     ContainerScope scope(GetInstanceId());
1125     scrollController->JumpToItemInGroup(index, indexInGroup, smooth, align, SCROLL_FROM_JUMP);
1126 }
1127 
CloseAllSwipeActions(const JSCallbackInfo & args)1128 void JSListScroller::CloseAllSwipeActions(const JSCallbackInfo& args)
1129 {
1130     if (args.Length() != 0 && args.Length() != 1) {
1131         JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "too many parameters.");
1132         return;
1133     }
1134     OnFinishFunc onFinishCallBack;
1135     if (args.Length() == 1) {
1136         if (!args[0]->IsObject()) {
1137             JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "options param must be object.");
1138             return;
1139         }
1140         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
1141         auto onFinishProperty = obj->GetProperty("onFinish");
1142         if (onFinishProperty->IsFunction()) {
1143             RefPtr<JsFunction> jsOnFinishFunc =
1144                 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onFinishProperty));
1145                 onFinishCallBack = [execCtx = args.GetExecutionContext(),
1146                                        func = std::move(jsOnFinishFunc)]() {
1147                     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1148                     func->Execute();
1149                     return;
1150                 };
1151         } else {
1152             JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "onFinish param must be function.");
1153             return;
1154         }
1155     }
1156     auto scrollController = GetController().Upgrade();
1157     if (!scrollController) {
1158         JSException::Throw(ERROR_CODE_NAMED_ROUTE_ERROR, "%s", "Controller not bound to component.");
1159         return;
1160     }
1161     ContainerScope scope(GetInstanceId());
1162     scrollController->CloseAllSwipeActions(std::move(onFinishCallBack));
1163 }
1164 } // namespace OHOS::Ace::Framework
1165