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