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