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