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