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