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