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