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