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::NONE, Axis::NONE, Axis::FREE };
61
ParseJsDimensionArray(const JSRef<JSVal> & jsValue,std::vector<Dimension> & result,std::vector<RefPtr<ResourceObject>> & resObjs)62 bool ParseJsDimensionArray(
63 const JSRef<JSVal>& jsValue, std::vector<Dimension>& result, std::vector<RefPtr<ResourceObject>>& resObjs)
64 {
65 if (!jsValue->IsArray()) {
66 return false;
67 }
68 bool parseOK = true;
69 JSRef<JSArray> array = JSRef<JSArray>::Cast(jsValue);
70 for (size_t i = 0; i < array->Length(); i++) {
71 JSRef<JSVal> value = array->GetValueAt(i);
72 CalcDimension dimension;
73 RefPtr<ResourceObject> resObj;
74 auto parseDimensionOK = JSViewAbstract::ParseJsDimensionVp(value, dimension, resObj);
75 result.emplace_back(static_cast<Dimension>(dimension));
76 resObjs.emplace_back(resObj);
77 if (!parseDimensionOK) {
78 parseOK = false;
79 }
80 }
81 return parseOK;
82 }
83
CheckSnapPaginations(std::vector<Dimension> snapPaginations)84 bool CheckSnapPaginations(std::vector<Dimension> snapPaginations)
85 {
86 CHECK_NULL_RETURN(!snapPaginations.empty(), false);
87 float preValue = (*snapPaginations.begin()).Value();
88 CHECK_NULL_RETURN(!Negative(preValue), false);
89 auto unit = (*snapPaginations.begin()).Unit();
90 for (auto iter = snapPaginations.begin() + 1; iter < snapPaginations.end(); ++iter) {
91 if (Negative((*iter).Value()) || (*iter).Unit() != unit || LessOrEqual((*iter).Value(), preValue)) {
92 return false;
93 }
94 preValue = (*iter).Value();
95 }
96 return true;
97 }
98 } // namespace
99
Create(const JSCallbackInfo & info)100 void JSScroll::Create(const JSCallbackInfo& info)
101 {
102 ScrollModel::GetInstance()->Create();
103 if (info.Length() > 0 && info[0]->IsObject()) {
104 JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
105 if (jsScroller) {
106 jsScroller->SetInstanceId(Container::CurrentId());
107 auto positionController = ScrollModel::GetInstance()->GetOrCreateController();
108 jsScroller->SetController(positionController);
109 // Init scroll bar proxy.
110 auto proxy = jsScroller->GetScrollBarProxy();
111 if (!proxy) {
112 proxy = ScrollModel::GetInstance()->CreateScrollBarProxy();
113 jsScroller->SetScrollBarProxy(proxy);
114 }
115 ScrollModel::GetInstance()->SetScrollBarProxy(proxy);
116 }
117 }
118 JSScrollTheme::ApplyTheme();
119 }
120
SetScrollable(int32_t value)121 void JSScroll::SetScrollable(int32_t value)
122 {
123 if (value < 0 || value >= static_cast<int32_t>(AXIS.size())) {
124 return;
125 }
126 ScrollModel::GetInstance()->SetAxis(AXIS[value]);
127 }
128
SetScrollEnabled(const JSCallbackInfo & args)129 void JSScroll::SetScrollEnabled(const JSCallbackInfo& args)
130 {
131 ScrollModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
132 }
133
OnScrollBeginCallback(const JSCallbackInfo & args)134 void JSScroll::OnScrollBeginCallback(const JSCallbackInfo& args)
135 {
136 if (args[0]->IsFunction()) {
137 auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
138 const Dimension& dx, const Dimension& dy) -> ScrollInfo {
139 ScrollInfo scrollInfo { .dx = dx, .dy = dy };
140 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollInfo);
141 auto params = ConvertToJSValues(dx, dy);
142 auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
143 if (result.IsEmpty()) {
144 return scrollInfo;
145 }
146
147 if (!result->IsObject()) {
148 return scrollInfo;
149 }
150
151 auto resObj = JSRef<JSObject>::Cast(result);
152 auto dxRemainValue = resObj->GetProperty("dxRemain");
153 if (dxRemainValue->IsNumber()) {
154 scrollInfo.dx = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
155 }
156 auto dyRemainValue = resObj->GetProperty("dyRemain");
157 if (dyRemainValue->IsNumber()) {
158 scrollInfo.dy = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
159 }
160 return scrollInfo;
161 };
162 ScrollModel::GetInstance()->SetOnScrollBegin(std::move(onScrollBegin));
163 }
164 args.SetReturnValue(args.This());
165 }
166
OnScrollFrameBeginCallback(const JSCallbackInfo & args)167 void JSScroll::OnScrollFrameBeginCallback(const JSCallbackInfo& args)
168 {
169 if (args[0]->IsFunction()) {
170 auto onScrollFrameBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
171 const Dimension& offset, ScrollState state) -> ScrollFrameResult {
172 OHOS::Ace::ScrollFrameResult scrollRes { .offset = offset };
173 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
174 auto params = ConvertToJSValues(offset, state);
175 auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
176 if (result.IsEmpty()) {
177 return scrollRes;
178 }
179
180 if (!result->IsObject()) {
181 return scrollRes;
182 }
183
184 auto resObj = JSRef<JSObject>::Cast(result);
185 auto dxRemainValue = resObj->GetProperty("offsetRemain");
186 if (dxRemainValue->IsNumber()) {
187 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
188 }
189 return scrollRes;
190 };
191 ScrollModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollFrameBegin));
192 }
193 args.SetReturnValue(args.This());
194 }
195
OnScrollCallback(const JSCallbackInfo & args)196 void JSScroll::OnScrollCallback(const JSCallbackInfo& args)
197 {
198 auto callbackInfo = args[0];
199 if (callbackInfo->IsFunction()) {
200 auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(callbackInfo)](
201 const Dimension& xOffset, const Dimension& yOffset) {
202 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
203 auto params = ConvertToJSValues(xOffset, yOffset);
204 func->Call(JSRef<JSObject>(), params.size(), params.data());
205 };
206 ScrollModel::GetInstance()->SetOnScroll(std::move(onScroll));
207 }
208 }
209
OnWillScrollCallback(const JSCallbackInfo & args)210 void JSScroll::OnWillScrollCallback(const JSCallbackInfo& args)
211 {
212 if (args.Length() <= 0) {
213 return;
214 }
215
216 if (args[0]->IsFunction()) {
217 auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
218 const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState,
219 ScrollSource scrollSource) {
220 auto params = ConvertToJSValues(xOffset, yOffset, scrollState, scrollSource);
221 NG::TwoDimensionScrollResult scrollRes { .xOffset = xOffset, .yOffset = yOffset };
222 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
223 auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
224 if (result.IsEmpty()) {
225 return scrollRes;
226 }
227
228 if (!result->IsObject()) {
229 return scrollRes;
230 }
231
232 auto resObj = JSRef<JSObject>::Cast(result);
233 auto dxRemainValue = resObj->GetProperty("xOffset");
234 if (dxRemainValue->IsNumber()) {
235 scrollRes.xOffset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
236 }
237 auto dyRemainValue = resObj->GetProperty("yOffset");
238 if (dyRemainValue->IsNumber()) {
239 scrollRes.yOffset = Dimension(dyRemainValue->ToNumber<float>(), DimensionUnit::VP);
240 }
241 return scrollRes;
242 };
243 ScrollModel::GetInstance()->SetOnWillScroll(std::move(onScroll));
244 } else {
245 ScrollModel::GetInstance()->SetOnWillScroll(nullptr);
246 }
247 }
248
OnDidScrollCallback(const JSCallbackInfo & args)249 void JSScroll::OnDidScrollCallback(const JSCallbackInfo& args)
250 {
251 if (args.Length() > 0 && args[0]->IsFunction()) {
252 auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
253 const Dimension& xOffset, const Dimension& yOffset, const ScrollState& scrollState) {
254 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
255 auto params = ConvertToJSValues(xOffset, yOffset, scrollState);
256 func->Call(JSRef<JSObject>(), params.size(), params.data());
257 };
258 ScrollModel::GetInstance()->SetOnDidScroll(std::move(onScroll));
259 }
260 }
261
OnScrollEdgeCallback(const JSCallbackInfo & args)262 void JSScroll::OnScrollEdgeCallback(const JSCallbackInfo& args)
263 {
264 if (args[0]->IsFunction()) {
265 auto scrollEdge = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
266 const NG::ScrollEdge& side) {
267 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
268 auto params = ConvertToJSValues(side);
269 func->Call(JSRef<JSObject>(), 1, params.data());
270 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEdge");
271 };
272 ScrollModel::GetInstance()->SetOnScrollEdge(std::move(scrollEdge));
273 }
274 args.SetReturnValue(args.This());
275 }
276
OnScrollEndCallback(const JSCallbackInfo & args)277 void JSScroll::OnScrollEndCallback(const JSCallbackInfo& args)
278 {
279 if (args[0]->IsFunction()) {
280 auto scrollEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
281 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
282 func->Call(JSRef<JSObject>(), 0, nullptr);
283 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollEnd");
284 };
285 ScrollModel::GetInstance()->SetOnScrollEnd(std::move(scrollEnd));
286 }
287 args.SetReturnValue(args.This());
288 }
289
OnScrollStartCallback(const JSCallbackInfo & args)290 void JSScroll::OnScrollStartCallback(const JSCallbackInfo& args)
291 {
292 if (args[0]->IsFunction()) {
293 auto scrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
294 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
295 func->Call(JSRef<JSObject>(), 0, nullptr);
296 };
297 ScrollModel::GetInstance()->SetOnScrollStart(std::move(scrollStart));
298 }
299 args.SetReturnValue(args.This());
300 }
301
OnScrollStopCallback(const JSCallbackInfo & args)302 void JSScroll::OnScrollStopCallback(const JSCallbackInfo& args)
303 {
304 if (args[0]->IsFunction()) {
305 auto scrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
306 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
307 func->Call(JSRef<JSObject>(), 0, nullptr);
308 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onScrollStop");
309 };
310 ScrollModel::GetInstance()->SetOnScrollStop(std::move(scrollStop));
311 }
312 args.SetReturnValue(args.This());
313 }
314
ReachStartCallback(const JSCallbackInfo & args)315 void JSScroll::ReachStartCallback(const JSCallbackInfo& args)
316 {
317 if (args[0]->IsFunction()) {
318 auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
319 func->Call(JSRef<JSObject>());
320 return;
321 };
322 ScrollModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
323 }
324 args.ReturnSelf();
325 }
326
ReachEndCallback(const JSCallbackInfo & args)327 void JSScroll::ReachEndCallback(const JSCallbackInfo& args)
328 {
329 if (args[0]->IsFunction()) {
330 auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
331 func->Call(JSRef<JSObject>());
332 return;
333 };
334 ScrollModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
335 }
336 args.ReturnSelf();
337 }
338
JSBind(BindingTarget globalObj)339 void JSScroll::JSBind(BindingTarget globalObj)
340 {
341 JSClass<JSScroll>::Declare("Scroll");
342 MethodOptions opt = MethodOptions::NONE;
343 JSClass<JSScroll>::StaticMethod("create", &JSScroll::Create, opt);
344 JSClass<JSScroll>::StaticMethod("scrollable", &JSScroll::SetScrollable, opt);
345 JSClass<JSScroll>::StaticMethod("onScrollBegin", &JSScroll::OnScrollBeginCallback, opt);
346 JSClass<JSScroll>::StaticMethod("onScrollFrameBegin", &JSScroll::OnScrollFrameBeginCallback, opt);
347 JSClass<JSScroll>::StaticMethod("onScroll", &JSScroll::OnScrollCallback, opt);
348 JSClass<JSScroll>::StaticMethod("onWillScroll", &JSScroll::OnWillScrollCallback, opt);
349 JSClass<JSScroll>::StaticMethod("onDidScroll", &JSScroll::OnDidScrollCallback, opt);
350 JSClass<JSScroll>::StaticMethod("onScrollEdge", &JSScroll::OnScrollEdgeCallback, opt);
351 JSClass<JSScroll>::StaticMethod("onScrollEnd", &JSScroll::OnScrollEndCallback, opt);
352 JSClass<JSScroll>::StaticMethod("onScrollStart", &JSScroll::OnScrollStartCallback, opt);
353 JSClass<JSScroll>::StaticMethod("onScrollStop", &JSScroll::OnScrollStopCallback, opt);
354 JSClass<JSScroll>::StaticMethod("onReachStart", &JSScroll::ReachStartCallback);
355 JSClass<JSScroll>::StaticMethod("onReachEnd", &JSScroll::ReachEndCallback);
356 JSClass<JSScroll>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
357 JSClass<JSScroll>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
358 JSClass<JSScroll>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
359 JSClass<JSScroll>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
360 JSClass<JSScroll>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
361 JSClass<JSScroll>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
362 JSClass<JSScroll>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
363 JSClass<JSScroll>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
364 JSClass<JSScroll>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
365 JSClass<JSScroll>::StaticMethod("edgeEffect", &JSScroll::SetEdgeEffect, opt);
366 JSClass<JSScroll>::StaticMethod("scrollBar", &JSScroll::SetScrollBar, opt);
367 JSClass<JSScroll>::StaticMethod("scrollBarColor", &JSScroll::SetScrollBarColor, opt);
368 JSClass<JSScroll>::StaticMethod("scrollBarWidth", &JSScroll::SetScrollBarWidth, opt);
369 JSClass<JSScroll>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
370 JSClass<JSScroll>::StaticMethod("width", &JSScroll::JsWidth);
371 JSClass<JSScroll>::StaticMethod("height", &JSScroll::JsHeight);
372 JSClass<JSScroll>::StaticMethod("nestedScroll", &JSScroll::SetNestedScroll);
373 JSClass<JSScroll>::StaticMethod("enableScrollInteraction", &JSScroll::SetScrollEnabled);
374 JSClass<JSScroll>::StaticMethod("friction", &JSScroll::SetFriction);
375 JSClass<JSScroll>::StaticMethod("scrollSnap", &JSScroll::SetScrollSnap);
376 JSClass<JSScroll>::StaticMethod("enablePaging", &JSScroll::SetEnablePaging);
377 JSClass<JSScroll>::StaticMethod("clip", &JSScrollable::JsClip);
378 JSClass<JSScroll>::StaticMethod("initialOffset", &JSScroll::SetInitialOffset);
379 JSClass<JSScroll>::StaticMethod("maxZoomScale", &JSScroll::SetMaxZoomScale);
380 JSClass<JSScroll>::StaticMethod("minZoomScale", &JSScroll::SetMinZoomScale);
381 JSClass<JSScroll>::StaticMethod("zoomScale", &JSScroll::SetZoomScale);
382 JSClass<JSScroll>::StaticMethod("enableBouncesZoom", &JSScroll::SetEnableBouncesZoom);
383 JSClass<JSScroll>::StaticMethod("onDidZoom", &JSScroll::OnDidZoomCallback, opt);
384 JSClass<JSScroll>::StaticMethod("onZoomStart", &JSScroll::OnZoomStartCallback, opt);
385 JSClass<JSScroll>::StaticMethod("onZoomStop", &JSScroll::OnZoomStopCallback, opt);
386 JSClass<JSScroll>::InheritAndBind<JSScrollableBase>(globalObj);
387 }
388
SetScrollBar(const JSCallbackInfo & args)389 void JSScroll::SetScrollBar(const JSCallbackInfo& args)
390 {
391 if (args.Length() < 1) {
392 return;
393 }
394 int32_t displayMode;
395 if (args[0]->IsNull() || args[0]->IsUndefined() || !ParseJsInt32(args[0], displayMode)) {
396 displayMode = static_cast<int32_t>(DisplayMode::AUTO);
397 }
398 ScrollModel::GetInstance()->SetDisplayMode(displayMode);
399 }
400
SetScrollBarWidth(const JSCallbackInfo & args)401 void JSScroll::SetScrollBarWidth(const JSCallbackInfo& args)
402 {
403 auto pipelineContext = PipelineContext::GetCurrentContext();
404 CHECK_NULL_VOID(pipelineContext);
405 auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
406 CHECK_NULL_VOID(theme);
407 CalcDimension scrollBarWidth;
408 if (args.Length() < 1) {
409 return;
410 }
411 if (!ParseJsDimensionVp(args[0], scrollBarWidth) || args[0]->IsNull() || args[0]->IsUndefined() ||
412 (args[0]->IsString() && args[0]->ToString().empty()) || LessNotEqual(scrollBarWidth.Value(), 0.0) ||
413 scrollBarWidth.Unit() == DimensionUnit::PERCENT) {
414 scrollBarWidth = theme->GetNormalWidth();
415 }
416 ScrollModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
417 }
418
SetScrollBarColor(const JSCallbackInfo & args)419 void JSScroll::SetScrollBarColor(const JSCallbackInfo& args)
420 {
421 auto pipelineContext = PipelineContext::GetCurrentContext();
422 CHECK_NULL_VOID(pipelineContext);
423 auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
424 CHECK_NULL_VOID(theme);
425 Color color(theme->GetForegroundColor());
426 RefPtr<ResourceObject> resObj;
427 JSViewAbstract::ParseJsColor(args[0], color, resObj);
428 if (SystemProperties::ConfigChangePerform()) {
429 ScrollModel::GetInstance()->CreateWithResourceObjScrollBarColor(resObj);
430 }
431 ScrollModel::GetInstance()->SetScrollBarColor(color);
432 }
433
SetEdgeEffect(const JSCallbackInfo & args)434 void JSScroll::SetEdgeEffect(const JSCallbackInfo& args)
435 {
436 auto edgeEffect = EdgeEffect::NONE;
437 auto effectEdge = EffectEdge::ALL;
438 if (args.Length() > 0) {
439 edgeEffect = JSScrollable::ParseEdgeEffect(args[0], EdgeEffect::NONE);
440 }
441 auto alwaysEnabled = true;
442 if (args.Length() > 1) {
443 alwaysEnabled = JSScrollable::ParseAlwaysEnable(args[1], true);
444 effectEdge = JSScrollable::ParseEffectEdge(args[1]);
445 }
446 ScrollModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled, effectEdge);
447 }
448
JsWidth(const JSCallbackInfo & info)449 void JSScroll::JsWidth(const JSCallbackInfo& info)
450 {
451 JSViewAbstract::JsWidth(info);
452 ScrollModel::GetInstance()->SetHasWidth(true);
453 }
454
JsHeight(const JSCallbackInfo & info)455 void JSScroll::JsHeight(const JSCallbackInfo& info)
456 {
457 JSViewAbstract::JsHeight(info);
458 ScrollModel::GetInstance()->SetHasHeight(true);
459 }
460
SetNestedScroll(const JSCallbackInfo & args)461 void JSScroll::SetNestedScroll(const JSCallbackInfo& args)
462 {
463 NestedScrollOptions nestedOpt = {
464 .forward = NestedScrollMode::SELF_ONLY,
465 .backward = NestedScrollMode::SELF_ONLY,
466 };
467 if (args.Length() < 1 || !args[0]->IsObject()) {
468 ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
469 return;
470 }
471 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
472 int32_t froward = 0;
473 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
474 if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
475 froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
476 froward = 0;
477 }
478 int32_t backward = 0;
479 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
480 if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
481 backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
482 backward = 0;
483 }
484 nestedOpt.forward = static_cast<NestedScrollMode>(froward);
485 nestedOpt.backward = static_cast<NestedScrollMode>(backward);
486 ScrollModel::GetInstance()->SetNestedScroll(nestedOpt);
487 args.ReturnSelf();
488 }
489
SetFriction(const JSCallbackInfo & info)490 void JSScroll::SetFriction(const JSCallbackInfo& info)
491 {
492 double friction = -1.0;
493 RefPtr<ResourceObject> resObj;
494 if (!JSViewAbstract::ParseJsDouble(info[0], friction, resObj)) {
495 friction = -1.0;
496 }
497 if (SystemProperties::ConfigChangePerform()) {
498 ScrollModel::GetInstance()->CreateWithResourceObjFriction(resObj);
499 }
500 ScrollModel::GetInstance()->SetFriction(friction);
501 }
502
SetScrollSnap(const JSCallbackInfo & args)503 void JSScroll::SetScrollSnap(const JSCallbackInfo& args)
504 {
505 if (args.Length() < 1 || !args[0]->IsObject()) {
506 return;
507 }
508 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
509 auto snapAlignValue = obj->GetProperty("snapAlign");
510 int32_t snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
511 if (snapAlignValue->IsNull() || snapAlignValue->IsUndefined() || !ParseJsInt32(snapAlignValue, snapAlign) ||
512 snapAlign < static_cast<int32_t>(ScrollSnapAlign::NONE) ||
513 snapAlign > static_cast<int32_t>(ScrollSnapAlign::END)) {
514 snapAlign = static_cast<int32_t>(ScrollSnapAlign::NONE);
515 }
516
517 auto paginationValue = obj->GetProperty("snapPagination");
518 CalcDimension intervalSize;
519 RefPtr<ResourceObject> resObj;
520 std::vector<Dimension> snapPaginations;
521 std::vector<RefPtr<ResourceObject>> resObjs;
522 if (!ParseJsDimensionVp(paginationValue, intervalSize, resObj) || intervalSize.IsNegative()) {
523 intervalSize = CalcDimension(0.0);
524 }
525 auto parseArrayOK = ParseJsDimensionArray(paginationValue, snapPaginations, resObjs);
526 if (SystemProperties::ConfigChangePerform()) {
527 ScrollModel::GetInstance()->CreateWithResourceObjIntervalSize(resObj);
528 ScrollModel::GetInstance()->CreateWithResourceObjSnapPaginations(snapPaginations, resObjs);
529 }
530 if (!parseArrayOK || !CheckSnapPaginations(snapPaginations)) {
531 std::vector<Dimension>().swap(snapPaginations);
532 }
533
534 bool enableSnapToStart = true;
535 bool enableSnapToEnd = true;
536 ParseJsBool(obj->GetProperty("enableSnapToStart"), enableSnapToStart);
537 ParseJsBool(obj->GetProperty("enableSnapToEnd"), enableSnapToEnd);
538 std::pair<bool, bool> enableSnapToSide = { enableSnapToStart, enableSnapToEnd };
539 ScrollModel::GetInstance()->SetScrollSnap(
540 static_cast<ScrollSnapAlign>(snapAlign), intervalSize, snapPaginations, enableSnapToSide);
541 }
542
SetEnablePaging(const JSCallbackInfo & args)543 void JSScroll::SetEnablePaging(const JSCallbackInfo& args)
544 {
545 if (args.Length() < 1 || !args[0]->IsBoolean()) {
546 return;
547 }
548 ScrollModel::GetInstance()->SetEnablePaging(args[0]->ToBoolean());
549 }
550
SetInitialOffset(const JSCallbackInfo & args)551 void JSScroll::SetInitialOffset(const JSCallbackInfo& args)
552 {
553 if (args.Length() < 1 || !args[0]->IsObject()) {
554 return;
555 }
556
557 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
558 CalcDimension xOffset;
559 ParseJsDimensionVp(obj->GetProperty("xOffset"), xOffset);
560 CalcDimension yOffset;
561 ParseJsDimensionVp(obj->GetProperty("yOffset"), yOffset);
562 ScrollModel::GetInstance()->SetInitialOffset(NG::OffsetT(xOffset, yOffset));
563 }
564
SetMaxZoomScale(const JSCallbackInfo & args)565 void JSScroll::SetMaxZoomScale(const JSCallbackInfo& args)
566 {
567 if (args.Length() < 1) {
568 return;
569 }
570 double maxZoomScale = 1.0;
571 JSViewAbstract::ParseJsDouble(args[0], maxZoomScale);
572 ScrollModel::GetInstance()->SetMaxZoomScale(maxZoomScale);
573 }
574
SetMinZoomScale(const JSCallbackInfo & args)575 void JSScroll::SetMinZoomScale(const JSCallbackInfo& args)
576 {
577 if (args.Length() < 1) {
578 return;
579 }
580 double minZoomScale = 1.0;
581 JSViewAbstract::ParseJsDouble(args[0], minZoomScale);
582 ScrollModel::GetInstance()->SetMinZoomScale(minZoomScale);
583 }
584
SetZoomScale(const JSCallbackInfo & args)585 void JSScroll::SetZoomScale(const JSCallbackInfo& args)
586 {
587 if (args.Length() < 1) {
588 return;
589 }
590 double zoomScale = 1.0;
591 JSRef<JSVal> changeEventVal;
592 auto scaleValue = args[0];
593 if (scaleValue->IsObject()) {
594 JSRef<JSObject> obj = JSRef<JSObject>::Cast(scaleValue);
595 scaleValue = obj->GetProperty("value");
596 changeEventVal = obj->GetProperty("$value");
597 }
598 if (JSViewAbstract::ParseJsDouble(scaleValue, zoomScale)) {
599 ScrollModel::GetInstance()->SetZoomScale(zoomScale);
600 } else {
601 ScrollModel::GetInstance()->ResetZoomScale();
602 }
603 if (changeEventVal->IsFunction()) {
604 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
605 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
606 auto changeEvent = [execCtx = args.GetExecutionContext(),
607 func = std::move(jsFunc), node = targetNode](float param) {
608 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
609 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(param));
610 PipelineContext::SetCallBackNode(node);
611 func->ExecuteJS(1, &newJSVal);
612 };
613 ScrollModel::GetInstance()->SetZoomScaleChangeEvent(std::move(changeEvent));
614 }
615 }
616
SetEnableBouncesZoom(const JSCallbackInfo & args)617 void JSScroll::SetEnableBouncesZoom(const JSCallbackInfo& args)
618 {
619 if (args.Length() < 1) {
620 return;
621 }
622 bool enableBouncesZoom = true;
623 if (args[0]->IsBoolean()) {
624 enableBouncesZoom = args[0]->ToBoolean();
625 }
626 ScrollModel::GetInstance()->SetEnableBouncesZoom(enableBouncesZoom);
627 }
628
OnDidZoomCallback(const JSCallbackInfo & args)629 void JSScroll::OnDidZoomCallback(const JSCallbackInfo& args)
630 {
631 if (args.Length() > 0 && args[0]->IsFunction()) {
632 auto onZoom = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](float scale) {
633 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
634 auto params = ConvertToJSValues(scale);
635 func->Call(JSRef<JSObject>(), params.size(), params.data());
636 };
637 ScrollModel::GetInstance()->SetOnDidZoom(std::move(onZoom));
638 } else {
639 ScrollModel::GetInstance()->SetOnDidZoom(nullptr);
640 }
641 args.SetReturnValue(args.This());
642 }
643
OnZoomStartCallback(const JSCallbackInfo & args)644 void JSScroll::OnZoomStartCallback(const JSCallbackInfo& args)
645 {
646 if (args[0]->IsFunction()) {
647 auto zoomStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
648 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
649 func->Call(JSRef<JSObject>(), 0, nullptr);
650 };
651 ScrollModel::GetInstance()->SetOnZoomStart(std::move(zoomStart));
652 } else {
653 ScrollModel::GetInstance()->SetOnZoomStart(nullptr);
654 }
655 args.SetReturnValue(args.This());
656 }
657
OnZoomStopCallback(const JSCallbackInfo & args)658 void JSScroll::OnZoomStopCallback(const JSCallbackInfo& args)
659 {
660 if (args[0]->IsFunction()) {
661 auto zoomStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
662 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
663 func->Call(JSRef<JSObject>(), 0, nullptr);
664 };
665 ScrollModel::GetInstance()->SetOnZoomStop(std::move(zoomStop));
666 } else {
667 ScrollModel::GetInstance()->SetOnZoomStop(nullptr);
668 }
669 args.SetReturnValue(args.This());
670 }
671 } // namespace OHOS::Ace::Framework
672