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