• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/declarative_frontend/jsview/js_scroll.h"
17 
18 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
19 
20 #include "base/utils/utils.h"
21 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_scroll_theme.h"
22 #include "bridge/declarative_frontend/jsview/js_scrollable.h"
23 #include "bridge/declarative_frontend/jsview/js_scroller.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/scroll_model_impl.h"
26 #include "core/common/container.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components/scroll/scrollable.h"
29 #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
30 #include "core/components_ng/pattern/scroll/scroll_model_ng.h"
31 
32 namespace OHOS::Ace {
33 
34 std::unique_ptr<ScrollModel> ScrollModel::instance_ = nullptr;
35 std::mutex ScrollModel::mutex_;
36 
GetInstance()37 ScrollModel* ScrollModel::GetInstance()
38 {
39     if (!instance_) {
40         std::lock_guard<std::mutex> lock(mutex_);
41         if (!instance_) {
42 #ifdef NG_BUILD
43             instance_.reset(new NG::ScrollModelNG());
44 #else
45             if (Container::IsCurrentUseNewPipeline()) {
46                 instance_.reset(new NG::ScrollModelNG());
47             } else {
48                 instance_.reset(new Framework::ScrollModelImpl());
49             }
50 #endif
51         }
52     }
53     return instance_.get();
54 }
55 
56 } // namespace OHOS::Ace
57 
58 namespace OHOS::Ace::Framework {
59 namespace {
60 const std::vector<Axis> AXIS = { Axis::VERTICAL, Axis::HORIZONTAL, Axis::FREE, Axis::NONE };
61 
ParseJsDimensionArray(const JSRef<JSVal> & jsValue,std::vector<Dimension> & result)62 bool ParseJsDimensionArray(const JSRef<JSVal>& jsValue, std::vector<Dimension>& result)
63 {
64     if (!jsValue->IsArray()) {
65         return false;
66     }
67     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsValue);
68     for (size_t i = 0; i < array->Length(); i++) {
69         JSRef<JSVal> value = array->GetValueAt(i);
70         CalcDimension dimension;
71         if (JSViewAbstract::ParseJsDimensionVp(value, dimension)) {
72             result.emplace_back(static_cast<Dimension>(dimension));
73         } else {
74             return false;
75         }
76     }
77     return true;
78 }
79 
CheckSnapPaginations(std::vector<Dimension> snapPaginations)80 bool CheckSnapPaginations(std::vector<Dimension> snapPaginations)
81 {
82     CHECK_NULL_RETURN(!snapPaginations.empty(), false);
83     float preValue = (*snapPaginations.begin()).Value();
84     CHECK_NULL_RETURN(!Negative(preValue), false);
85     auto unit = (*snapPaginations.begin()).Unit();
86     for (auto iter = snapPaginations.begin() + 1; iter < snapPaginations.end(); ++iter) {
87         if (Negative((*iter).Value()) || (*iter).Unit() != unit || LessOrEqual((*iter).Value(), preValue)) {
88             return false;
89         }
90         preValue = (*iter).Value();
91     }
92     return true;
93 }
94 } // namespace
95 
Create(const JSCallbackInfo & info)96 void JSScroll::Create(const JSCallbackInfo& info)
97 {
98     ScrollModel::GetInstance()->Create();
99     if (info.Length() > 0 && info[0]->IsObject()) {
100         JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
101         if (jsScroller) {
102             jsScroller->SetInstanceId(Container::CurrentId());
103             auto positionController = ScrollModel::GetInstance()->GetOrCreateController();
104             jsScroller->SetController(positionController);
105             // Init scroll bar proxy.
106             auto proxy = jsScroller->GetScrollBarProxy();
107             if (!proxy) {
108                 proxy = ScrollModel::GetInstance()->CreateScrollBarProxy();
109                 jsScroller->SetScrollBarProxy(proxy);
110             }
111             ScrollModel::GetInstance()->SetScrollBarProxy(proxy);
112         }
113     }
114     // init scroll bar
115     std::pair<bool, Color> barColor;
116     barColor.first = false;
117     std::pair<bool, Dimension> barWidth;
118     barWidth.first = false;
119     ScrollModel::GetInstance()->InitScrollBar(GetTheme<ScrollBarTheme>(), barColor, barWidth, EdgeEffect::NONE);
120     JSScrollTheme::ApplyTheme();
121 }
122 
SetScrollable(int32_t value)123 void JSScroll::SetScrollable(int32_t value)
124 {
125     if (value < 0 || value >= static_cast<int32_t>(AXIS.size())) {
126         return;
127     }
128     ScrollModel::GetInstance()->SetAxis(AXIS[value]);
129 }
130 
SetScrollEnabled(const JSCallbackInfo & args)131 void JSScroll::SetScrollEnabled(const JSCallbackInfo& args)
132 {
133     ScrollModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
134 }
135 
OnScrollBeginCallback(const JSCallbackInfo & args)136 void JSScroll::OnScrollBeginCallback(const JSCallbackInfo& args)
137 {
138     if (args[0]->IsFunction()) {
139         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
140                                  const Dimension& dx, const Dimension& dy) -> ScrollInfo {
141             ScrollInfo scrollInfo { .dx = dx, .dy = dy };
142             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
143             auto params = ConvertToJSValues(dx, dy);
144             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
145             if (result.IsEmpty()) {
146                 return scrollInfo;
147             }
148 
149             if (!result->IsObject()) {
150                 return scrollInfo;
151             }
152 
153             auto resObj = JSRef<JSObject>::Cast(result);
154             auto dxRemainValue = resObj->GetProperty("dxRemain");
155             if (dxRemainValue->IsNumber()) {
156                 scrollInfo.dx = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
157             }
158             auto dyRemainValue = resObj->GetProperty("dyRemain");
159             if (dyRemainValue->IsNumber()) {
160                 scrollInfo.dy = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
161             }
162             return scrollInfo;
163         };
164         ScrollModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
165     }
166     args.SetReturnValue(args.This());
167 }
168 
OnScrollFrameBeginCallback(const JSCallbackInfo & args)169 void JSScroll::OnScrollFrameBeginCallback(const JSCallbackInfo& args)
170 {
171     if (args[0]->IsFunction()) {
172         auto onScrollFrameBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
173                                       const Dimension& offset, ScrollState state) -> ScrollFrameResult {
174             OHOS::Ace::ScrollFrameResult scrollRes { .offset = offset };
175             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
176             auto params = ConvertToJSValues(offset, state);
177             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
178             if (result.IsEmpty()) {
179                 return scrollRes;
180             }
181 
182             if (!result->IsObject()) {
183                 return scrollRes;
184             }
185 
186             auto resObj = JSRef<JSObject>::Cast(result);
187             auto dxRemainValue = resObj->GetProperty("offsetRemain");
188             if (dxRemainValue->IsNumber()) {
189                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
190             }
191             return scrollRes;
192         };
193         ScrollModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollFrameBegin));
194     }
195     args.SetReturnValue(args.This());
196 }
197 
OnScrollCallback(const JSCallbackInfo & args)198 void JSScroll::OnScrollCallback(const JSCallbackInfo& args)
199 {
200     auto callbackInfo = args[0];
201     if (callbackInfo->IsFunction()) {
202         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(callbackInfo)](
203                             const Dimension& xOffset, const Dimension& yOffset) {
204             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
205             auto params = ConvertToJSValues(xOffset, yOffset);
206             func->Call(JSRef<JSObject>(), params.size(), params.data());
207         };
208         ScrollModel::GetInstance()->SetOnScroll(std::move(onScroll));
209     }
210 }
211 
OnWillScrollCallback(const JSCallbackInfo & args)212 void JSScroll::OnWillScrollCallback(const JSCallbackInfo& args)
213 {
214     if (args.Length() <= 0) {
215         return;
216     }
217 
218     if (args[0]->IsFunction()) {
219         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
220                             const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState,
221                             ScrollSource scrollSource) {
222             auto params = ConvertToJSValues(xOffset, yOffset, scrollState, scrollSource);
223             NG::TwoDimensionScrollResult scrollRes { .xOffset = xOffset, .yOffset = yOffset };
224             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
225             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
226             if (result.IsEmpty()) {
227                 return scrollRes;
228             }
229 
230             if (!result->IsObject()) {
231                 return scrollRes;
232             }
233 
234             auto resObj = JSRef<JSObject>::Cast(result);
235             auto dxRemainValue = resObj->GetProperty("xOffset");
236             if (dxRemainValue->IsNumber()) {
237                 scrollRes.xOffset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
238             }
239             auto dyRemainValue = resObj->GetProperty("yOffset");
240             if (dyRemainValue->IsNumber()) {
241                 scrollRes.yOffset = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
242             }
243             return scrollRes;
244         };
245         ScrollModel::GetInstance()->SetOnWillScroll(std::move(onScroll));
246     } else {
247         ScrollModel::GetInstance()->SetOnWillScroll(nullptr);
248     }
249 }
250 
OnDidScrollCallback(const JSCallbackInfo & args)251 void JSScroll::OnDidScrollCallback(const JSCallbackInfo& args)
252 {
253     if (args.Length() > 0 && args[0]->IsFunction()) {
254         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
255                             const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState) {
256             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
257             auto params = ConvertToJSValues(xOffset, yOffset, scrollState);
258             func->Call(JSRef<JSObject>(), params.size(), params.data());
259         };
260         ScrollModel::GetInstance()->SetOnDidScroll(std::move(onScroll));
261     }
262 }
263 
OnScrollEdgeCallback(const JSCallbackInfo & args)264 void JSScroll::OnScrollEdgeCallback(const JSCallbackInfo& args)
265 {
266     if (args[0]->IsFunction()) {
267         auto scrollEdge = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
268                               const NG::ScrollEdge& side) {
269             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
270             auto params = ConvertToJSValues(side);
271             func->Call(JSRef<JSObject>(), 1, params.data());
272             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEdge");
273         };
274         ScrollModel::GetInstance()->SetOnScrollEdge(std::move(scrollEdge));
275     }
276     args.SetReturnValue(args.This());
277 }
278 
OnScrollEndCallback(const JSCallbackInfo & args)279 void JSScroll::OnScrollEndCallback(const JSCallbackInfo& args)
280 {
281     if (args[0]->IsFunction()) {
282         auto scrollEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
283             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
284             func->Call(JSRef<JSObject>(), 0, nullptr);
285             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEnd");
286         };
287         ScrollModel::GetInstance()->SetOnScrollEnd(std::move(scrollEnd));
288     }
289     args.SetReturnValue(args.This());
290 }
291 
OnScrollStartCallback(const JSCallbackInfo & args)292 void JSScroll::OnScrollStartCallback(const JSCallbackInfo& args)
293 {
294     if (args[0]->IsFunction()) {
295         auto scrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
296             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
297             func->Call(JSRef<JSObject>(), 0, nullptr);
298         };
299         ScrollModel::GetInstance()->SetOnScrollStart(std::move(scrollStart));
300     }
301     args.SetReturnValue(args.This());
302 }
303 
OnScrollStopCallback(const JSCallbackInfo & args)304 void JSScroll::OnScrollStopCallback(const JSCallbackInfo& args)
305 {
306     if (args[0]->IsFunction()) {
307         auto scrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
308             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
309             func->Call(JSRef<JSObject>(), 0, nullptr);
310             UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollStop");
311         };
312         ScrollModel::GetInstance()->SetOnScrollStop(std::move(scrollStop));
313     }
314     args.SetReturnValue(args.This());
315 }
316 
ReachStartCallback(const JSCallbackInfo & args)317 void JSScroll::ReachStartCallback(const JSCallbackInfo& args)
318 {
319     if (args[0]->IsFunction()) {
320         auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
321             func->Call(JSRef<JSObject>());
322             return;
323         };
324         ScrollModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
325     }
326     args.ReturnSelf();
327 }
328 
ReachEndCallback(const JSCallbackInfo & args)329 void JSScroll::ReachEndCallback(const JSCallbackInfo& args)
330 {
331     if (args[0]->IsFunction()) {
332         auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
333             func->Call(JSRef<JSObject>());
334             return;
335         };
336         ScrollModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
337     }
338     args.ReturnSelf();
339 }
340 
JSBind(BindingTarget globalObj)341 void JSScroll::JSBind(BindingTarget globalObj)
342 {
343     JSClass<JSScroll>::Declare("Scroll");
344     MethodOptions opt = MethodOptions::NONE;
345     JSClass<JSScroll>::StaticMethod("create", &JSScroll::Create, opt);
346     JSClass<JSScroll>::StaticMethod("scrollable", &JSScroll::SetScrollable, opt);
347     JSClass<JSScroll>::StaticMethod("onScrollBegin", &JSScroll::OnScrollBeginCallback, opt);
348     JSClass<JSScroll>::StaticMethod("onScrollFrameBegin", &JSScroll::OnScrollFrameBeginCallback, opt);
349     JSClass<JSScroll>::StaticMethod("onScroll", &JSScroll::OnScrollCallback, opt);
350     JSClass<JSScroll>::StaticMethod("onWillScroll", &JSScroll::OnWillScrollCallback, opt);
351     JSClass<JSScroll>::StaticMethod("onDidScroll", &JSScroll::OnDidScrollCallback, opt);
352     JSClass<JSScroll>::StaticMethod("onScrollEdge", &JSScroll::OnScrollEdgeCallback, opt);
353     JSClass<JSScroll>::StaticMethod("onScrollEnd", &JSScroll::OnScrollEndCallback, opt);
354     JSClass<JSScroll>::StaticMethod("onScrollStart", &JSScroll::OnScrollStartCallback, opt);
355     JSClass<JSScroll>::StaticMethod("onScrollStop", &JSScroll::OnScrollStopCallback, opt);
356     JSClass<JSScroll>::StaticMethod("onReachStart", &JSScroll::ReachStartCallback);
357     JSClass<JSScroll>::StaticMethod("onReachEnd", &JSScroll::ReachEndCallback);
358     JSClass<JSScroll>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
359     JSClass<JSScroll>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
360     JSClass<JSScroll>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
361     JSClass<JSScroll>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
362     JSClass<JSScroll>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
363     JSClass<JSScroll>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
364     JSClass<JSScroll>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
365     JSClass<JSScroll>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
366     JSClass<JSScroll>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
367     JSClass<JSScroll>::StaticMethod("edgeEffect", &JSScroll::SetEdgeEffect, opt);
368     JSClass<JSScroll>::StaticMethod("scrollBar", &JSScroll::SetScrollBar, opt);
369     JSClass<JSScroll>::StaticMethod("scrollBarColor", &JSScroll::SetScrollBarColor, opt);
370     JSClass<JSScroll>::StaticMethod("scrollBarWidth", &JSScroll::SetScrollBarWidth, opt);
371     JSClass<JSScroll>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
372     JSClass<JSScroll>::StaticMethod("width", &JSScroll::JsWidth);
373     JSClass<JSScroll>::StaticMethod("height", &JSScroll::JsHeight);
374     JSClass<JSScroll>::StaticMethod("nestedScroll", &JSScroll::SetNestedScroll);
375     JSClass<JSScroll>::StaticMethod("enableScrollInteraction", &JSScroll::SetScrollEnabled);
376     JSClass<JSScroll>::StaticMethod("friction", &JSScroll::SetFriction);
377     JSClass<JSScroll>::StaticMethod("scrollSnap", &JSScroll::SetScrollSnap);
378     JSClass<JSScroll>::StaticMethod("enablePaging", &JSScroll::SetEnablePaging);
379     JSClass<JSScroll>::StaticMethod("clip", &JSScrollable::JsClip);
380     JSClass<JSScroll>::StaticMethod("initialOffset", &JSScroll::SetInitialOffset);
381     JSClass<JSScroll>::InheritAndBind<JSScrollableBase>(globalObj);
382 }
383 
SetScrollBar(const JSCallbackInfo & args)384 void JSScroll::SetScrollBar(const JSCallbackInfo& args)
385 {
386     if (args.Length() < 1) {
387         return;
388     }
389     int32_t displayMode;
390     if (args[0]->IsNull() || args[0]->IsUndefined() || !ParseJsInt32(args[0], displayMode)) {
391         displayMode = static_cast<int32_t>(DisplayMode::AUTO);
392     }
393     ScrollModel::GetInstance()->SetDisplayMode(displayMode);
394 }
395 
SetScrollBarWidth(const JSCallbackInfo & args)396 void JSScroll::SetScrollBarWidth(const JSCallbackInfo& args)
397 {
398     auto pipelineContext = PipelineContext::GetCurrentContext();
399     CHECK_NULL_VOID(pipelineContext);
400     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
401     CHECK_NULL_VOID(theme);
402     CalcDimension scrollBarWidth;
403     if (args.Length() < 1) {
404         return;
405     }
406     if (!ParseJsDimensionVp(args[0], scrollBarWidth) || args[0]->IsNull() || args[0]->IsUndefined() ||
407         (args[0]->IsString() && args[0]->ToString().empty()) || LessNotEqual(scrollBarWidth.Value(), 0.0) ||
408         scrollBarWidth.Unit() == DimensionUnit::PERCENT) {
409         scrollBarWidth = theme->GetNormalWidth();
410     }
411     ScrollModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
412 }
413 
SetScrollBarColor(const JSCallbackInfo & args)414 void JSScroll::SetScrollBarColor(const JSCallbackInfo& args)
415 {
416     auto pipelineContext = PipelineContext::GetCurrentContext();
417     CHECK_NULL_VOID(pipelineContext);
418     auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
419     CHECK_NULL_VOID(theme);
420     Color color(theme->GetForegroundColor());
421     JSViewAbstract::ParseJsColor(args[0], color);
422     ScrollModel::GetInstance()->SetScrollBarColor(color);
423 }
424 
SetEdgeEffect(const JSCallbackInfo & args)425 void JSScroll::SetEdgeEffect(const JSCallbackInfo& args)
426 {
427     auto edgeEffect = EdgeEffect::NONE;
428     auto effectEdge = EffectEdge::ALL;
429     if (args.Length() > 0) {
430         edgeEffect = JSScrollable::ParseEdgeEffect(args[0], EdgeEffect::NONE);
431     }
432     auto alwaysEnabled = true;
433     if (args.Length() > 1) {
434         alwaysEnabled = JSScrollable::ParseAlwaysEnable(args[1], true);
435         effectEdge = JSScrollable::ParseEffectEdge(args[1]);
436     }
437     ScrollModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled, effectEdge);
438 }
439 
JsWidth(const JSCallbackInfo & info)440 void JSScroll::JsWidth(const JSCallbackInfo& info)
441 {
442     JSViewAbstract::JsWidth(info);
443     ScrollModel::GetInstance()->SetHasWidth(true);
444 }
445 
JsHeight(const JSCallbackInfo & info)446 void JSScroll::JsHeight(const JSCallbackInfo& info)
447 {
448     JSViewAbstract::JsHeight(info);
449     ScrollModel::GetInstance()->SetHasHeight(true);
450 }
451 
SetNestedScroll(const JSCallbackInfo & args)452 void JSScroll::SetNestedScroll(const JSCallbackInfo& args)
453 {
454     NestedScrollOptions nestedOpt = {
455         .forward = NestedScrollMode::SELF_ONLY,
456         .backward = NestedScrollMode::SELF_ONLY,
457     };
458     if (args.Length() < 1 || !args[0]->IsObject()) {
459         ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
460         return;
461     }
462     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
463     int32_t froward = 0;
464     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
465     if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
466         froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
467         froward = 0;
468     }
469     int32_t backward = 0;
470     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
471     if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
472         backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
473         backward = 0;
474     }
475     nestedOpt.forward = static_cast<NestedScrollMode>(froward);
476     nestedOpt.backward = static_cast<NestedScrollMode>(backward);
477     ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
478     args.ReturnSelf();
479 }
480 
SetFriction(const JSCallbackInfo & info)481 void JSScroll::SetFriction(const JSCallbackInfo& info)
482 {
483     double friction = -1.0;
484     if (!JSViewAbstract::ParseJsDouble(info[0], friction)) {
485         friction = -1.0;
486     }
487     ScrollModel::GetInstance()->SetFriction(friction);
488 }
489 
SetScrollSnap(const JSCallbackInfo & args)490 void JSScroll::SetScrollSnap(const JSCallbackInfo& args)
491 {
492     if (args.Length() < 1 || !args[0]->IsObject()) {
493         return;
494     }
495     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
496     auto snapAlignValue = obj->GetProperty("snapAlign");
497     int32_t snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
498     if (snapAlignValue->IsNull() || snapAlignValue->IsUndefined() || !ParseJsInt32(snapAlignValue, snapAlign) ||
499         snapAlign < static_cast<int32_t>(ScrollSnapAlign::NONE) ||
500         snapAlign > static_cast<int32_t>(ScrollSnapAlign::END)) {
501         snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
502     }
503 
504     auto paginationValue = obj->GetProperty("snapPagination");
505     CalcDimension intervalSize;
506     std::vector<Dimension> snapPaginations;
507     if (!ParseJsDimensionVp(paginationValue, intervalSize) || intervalSize.IsNegative()) {
508         intervalSize = CalcDimension(0.0);
509     }
510     if (!ParseJsDimensionArray(paginationValue, snapPaginations) || !CheckSnapPaginations(snapPaginations)) {
511         std::vector<Dimension>().swap(snapPaginations);
512     }
513 
514     bool enableSnapToStart = true;
515     bool enableSnapToEnd = true;
516     ParseJsBool(obj->GetProperty("enableSnapToStart"), enableSnapToStart);
517     ParseJsBool(obj->GetProperty("enableSnapToEnd"), enableSnapToEnd);
518     std::pair<bool, bool> enableSnapToSide = { enableSnapToStart, enableSnapToEnd };
519     ScrollModel::GetInstance()->SetScrollSnap(
520         static_cast<ScrollSnapAlign>(snapAlign), intervalSize, snapPaginations, enableSnapToSide);
521 }
522 
SetEnablePaging(const JSCallbackInfo & args)523 void JSScroll::SetEnablePaging(const JSCallbackInfo& args)
524 {
525     if (args.Length() < 1 || !args[0]->IsBoolean()) {
526         return;
527     }
528     ScrollModel::GetInstance()->SetEnablePaging(args[0]->ToBoolean());
529 }
530 
SetInitialOffset(const JSCallbackInfo & args)531 void JSScroll::SetInitialOffset(const JSCallbackInfo& args)
532 {
533     if (args.Length() < 1 || !args[0]->IsObject()) {
534         return;
535     }
536 
537     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
538     CalcDimension xOffset;
539     ParseJsDimensionVp(obj->GetProperty("xOffset"), xOffset);
540     CalcDimension yOffset;
541     ParseJsDimensionVp(obj->GetProperty("yOffset"), yOffset);
542     ScrollModel::GetInstance()->SetInitialOffset(NG::OffsetT(xOffset, yOffset));
543 }
544 } // namespace OHOS::Ace::Framework
545