1 /*
2 * Copyright (c) 2021-2022 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_grid.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "base/utils/utils.h"
20 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
21 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
22 #include "bridge/declarative_frontend/jsview/js_scroller.h"
23 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
24 #include "bridge/declarative_frontend/jsview/models/grid_model_impl.h"
25 #include "core/common/ace_application_info.h"
26 #include "core/common/container.h"
27 #include "core/components_ng/pattern/grid/grid_model_ng.h"
28
29 namespace OHOS::Ace {
30
31 std::unique_ptr<GridModel> GridModel::instance_ = nullptr;
32 std::mutex GridModel::mutex_;
33
GetInstance()34 GridModel* GridModel::GetInstance()
35 {
36 if (!instance_) {
37 std::lock_guard<std::mutex> lock(mutex_);
38 if (!instance_) {
39 #ifdef NG_BUILD
40 instance_.reset(new NG::GridModelNG());
41 #else
42 if (Container::IsCurrentUseNewPipeline()) {
43 instance_.reset(new NG::GridModelNG());
44 } else {
45 instance_.reset(new Framework::GridModelImpl());
46 }
47 #endif
48 }
49 }
50 return instance_.get();
51 }
52
53 } // namespace OHOS::Ace
54
55 namespace OHOS::Ace::Framework {
56 namespace {
57
58 const std::vector<DisplayMode> DISPLAY_MODE = { DisplayMode::OFF, DisplayMode::AUTO, DisplayMode::ON };
59 const std::vector<EdgeEffect> EDGE_EFFECT = { EdgeEffect::SPRING, EdgeEffect::FADE, EdgeEffect::NONE };
60 const std::vector<FlexDirection> LAYOUT_DIRECTION = { FlexDirection::ROW, FlexDirection::COLUMN,
61 FlexDirection::ROW_REVERSE, FlexDirection::COLUMN_REVERSE };
62 const size_t GRID_ITEM_SIZE_RESULT_LENGTH = 2;
63
64 } // namespace
65
ParseGridItemSize(const JSRef<JSVal> & value,GridItemSize & gridItemSize)66 void ParseGridItemSize(const JSRef<JSVal>& value, GridItemSize& gridItemSize)
67 {
68 if (value->IsArray()) {
69 JSRef<JSArray> array = JSRef<JSArray>::Cast(value);
70 auto length = array->Length();
71 if (length != GRID_ITEM_SIZE_RESULT_LENGTH) {
72 LOGE("info is invalid");
73 return;
74 }
75 JSRef<JSVal> rows = array->GetValueAt(0);
76 if (rows->IsNumber()) {
77 gridItemSize.rows = rows->ToNumber<int32_t>();
78 }
79 JSRef<JSVal> columns = array->GetValueAt(1);
80 if (columns->IsNumber()) {
81 gridItemSize.columns = columns->ToNumber<int32_t>();
82 }
83 LOGD("regularSize type: rows:%{public}d, columns:%{public}d", gridItemSize.rows, gridItemSize.columns);
84 }
85 }
86
SetGridLayoutOptions(const JSCallbackInfo & info)87 void SetGridLayoutOptions(const JSCallbackInfo& info)
88 {
89 if (!(info.Length() > 1 && info[1]->IsObject())) {
90 return;
91 }
92 GridLayoutOptions option;
93 auto obj = JSRef<JSObject>::Cast(info[1]);
94 auto value = obj->GetProperty("regularSize");
95 ParseGridItemSize(value, option.regularSize);
96
97 // only support regularSize(1, 1)
98 option.regularSize.rows = 1;
99 option.regularSize.columns = 1;
100
101 auto indexes = obj->GetProperty("irregularIndexes");
102 if (indexes->IsArray()) {
103 JSRef<JSArray> array = JSRef<JSArray>::Cast(indexes);
104 auto length = array->Length();
105 for (size_t i = 0; i < length; i++) {
106 JSRef<JSVal> index = array->GetValueAt(i);
107 if (!index->IsNumber()) {
108 continue;
109 }
110 auto indexNum = index->ToNumber<int32_t>();
111 if (indexNum >= 0) {
112 option.irregularIndexes.emplace(indexNum);
113 }
114 LOGD("irregularIndexes emplace_back:%{public}d", indexNum);
115 }
116 }
117 auto getSizeByIndex = obj->GetProperty("onGetIrregularSizeByIndex");
118 if (getSizeByIndex->IsFunction()) {
119 auto onGetIrregularSizeByIndex = [execCtx = info.GetExecutionContext(),
120 func = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(),
121 JSRef<JSFunc>::Cast(getSizeByIndex))](int32_t index) {
122 GridItemSize gridItemSize;
123 JSRef<JSVal> itemIndex = JSRef<JSVal>::Make(ToJSValue(index));
124 auto result = func->ExecuteJS(1, &itemIndex);
125 if (!result->IsArray()) {
126 return gridItemSize;
127 }
128 ParseGridItemSize(result, gridItemSize);
129 return gridItemSize;
130 };
131 option.getSizeByIndex = std::move(onGetIrregularSizeByIndex);
132 }
133 GridModel::GetInstance()->SetLayoutOptions(option);
134 }
135
Create(const JSCallbackInfo & info)136 void JSGrid::Create(const JSCallbackInfo& info)
137 {
138 RefPtr<ScrollControllerBase> positionController;
139 RefPtr<ScrollProxy> scrollBarProxy;
140 if (info.Length() > 0 && info[0]->IsObject()) {
141 JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
142 if (jsScroller) {
143 positionController = GridModel::GetInstance()->CreatePositionController();
144 jsScroller->SetController(positionController);
145
146 // Init scroll bar proxy.
147 scrollBarProxy = jsScroller->GetScrollBarProxy();
148 if (!scrollBarProxy) {
149 scrollBarProxy = GridModel::GetInstance()->CreateScrollBarProxy();
150 jsScroller->SetScrollBarProxy(scrollBarProxy);
151 }
152 }
153 }
154 GridModel::GetInstance()->Create(positionController, scrollBarProxy);
155
156 SetGridLayoutOptions(info);
157 }
158
PopGrid(const JSCallbackInfo &)159 void JSGrid::PopGrid(const JSCallbackInfo& /* info */)
160 {
161 GridModel::GetInstance()->Pop();
162 }
163
UseProxy(const JSCallbackInfo & args)164 void JSGrid::UseProxy(const JSCallbackInfo& args)
165 {
166 #ifdef NG_BUILD
167 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
168 #else
169 auto parentGrid = ViewStackProcessor::GetInstance()->GetTopGrid();
170
171 // return true if code path for GridElement and its children will rely on
172 // ElementProxy. Only in this case shallow render functionality can be used
173 // see also GridLayoutComponent::CreateElement() and GridItemElementProxy class
174 LOGD("parent Grid uses proxied code path %{public}s.",
175 (parentGrid ? !parentGrid->UseNonProxiedCodePath() ? "yes" : "false" : "no parent grid (error)"));
176 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(parentGrid ? !parentGrid->UseNonProxiedCodePath() : false)));
177 #endif
178 }
179
SetColumnsTemplate(const std::string & value)180 void JSGrid::SetColumnsTemplate(const std::string& value)
181 {
182 GridModel::GetInstance()->SetColumnsTemplate(value);
183 }
184
SetRowsTemplate(const std::string & value)185 void JSGrid::SetRowsTemplate(const std::string& value)
186 {
187 GridModel::GetInstance()->SetRowsTemplate(value);
188 }
189
SetColumnsGap(const JSCallbackInfo & info)190 void JSGrid::SetColumnsGap(const JSCallbackInfo& info)
191 {
192 if (info.Length() < 1) {
193 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
194 return;
195 }
196 CalcDimension colGap;
197
198 if (!ParseJsDimensionVp(info[0], colGap) || colGap.Value() < 0) {
199 colGap.SetValue(0.0);
200 }
201
202 GridModel::GetInstance()->SetColumnsGap(colGap);
203 }
204
SetRowsGap(const JSCallbackInfo & info)205 void JSGrid::SetRowsGap(const JSCallbackInfo& info)
206 {
207 if (info.Length() < 1) {
208 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
209 return;
210 }
211 CalcDimension rowGap;
212
213 if (!ParseJsDimensionVp(info[0], rowGap) || rowGap.Value() < 0) {
214 rowGap.SetValue(0.0);
215 }
216
217 GridModel::GetInstance()->SetRowsGap(rowGap);
218 }
219
JsGridHeight(const JSCallbackInfo & info)220 void JSGrid::JsGridHeight(const JSCallbackInfo& info)
221 {
222 if (info.Length() < 1) {
223 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
224 return;
225 }
226
227 CalcDimension value;
228 if (!ParseJsDimensionVp(info[0], value)) {
229 LOGE("parse height fail for grid, please check.");
230 return;
231 }
232 if (LessNotEqual(value.Value(), 0.0)) {
233 value.SetValue(0.0);
234 }
235 GridModel::GetInstance()->SetGridHeight(value);
236 }
237
JsOnScrollBarUpdate(const JSCallbackInfo & info)238 void JSGrid::JsOnScrollBarUpdate(const JSCallbackInfo& info)
239 {
240 if (!info[0]->IsFunction()) {
241 return;
242 }
243
244 auto onScrollBarUpdate = [execCtx = info.GetExecutionContext(),
245 func = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(),
246 JSRef<JSFunc>::Cast(info[0]))](int32_t index, const Dimension& offset) {
247 JSRef<JSVal> itemIndex = JSRef<JSVal>::Make(ToJSValue(index));
248 JSRef<JSVal> itemOffset = ConvertToJSValue(offset);
249 JSRef<JSVal> params[2] = { itemIndex, itemOffset };
250 auto result = func->ExecuteJS(2, params);
251 if (result->IsObject()) {
252 JSRef<JSObject> obj = JSRef<JSObject>::Cast(result);
253
254 Dimension totalOffset_;
255 Dimension totalLength_;
256 if (!ConvertFromJSValue(obj->GetProperty("totalOffset"), totalOffset_) ||
257 !ConvertFromJSValue(obj->GetProperty("totalLength"), totalLength_)) {
258 return std::pair<float, float>(0, 0);
259 } else {
260 return std::pair<float, float>(totalOffset_.ConvertToPx(), totalLength_.ConvertToPx());
261 }
262 }
263 return std::pair<float, float>(0, 0);
264 };
265 GridModel::GetInstance()->SetOnScrollBarUpdate(std::move(onScrollBarUpdate));
266 }
267
SetScrollEnabled(const JSCallbackInfo & args)268 void JSGrid::SetScrollEnabled(const JSCallbackInfo& args)
269 {
270 GridModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
271 }
272
JSBind(BindingTarget globalObj)273 void JSGrid::JSBind(BindingTarget globalObj)
274 {
275 LOGD("JSGrid:Bind");
276 JSClass<JSGrid>::Declare("Grid");
277
278 MethodOptions opt = MethodOptions::NONE;
279 JSClass<JSGrid>::StaticMethod("create", &JSGrid::Create, opt);
280 JSClass<JSGrid>::StaticMethod("pop", &JSGrid::PopGrid, opt);
281 JSClass<JSGrid>::StaticMethod("willUseProxy", &JSGrid::UseProxy, opt);
282 JSClass<JSGrid>::StaticMethod("columnsTemplate", &JSGrid::SetColumnsTemplate, opt);
283 JSClass<JSGrid>::StaticMethod("rowsTemplate", &JSGrid::SetRowsTemplate, opt);
284 JSClass<JSGrid>::StaticMethod("columnsGap", &JSGrid::SetColumnsGap, opt);
285 JSClass<JSGrid>::StaticMethod("rowsGap", &JSGrid::SetRowsGap, opt);
286 JSClass<JSGrid>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
287 JSClass<JSGrid>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
288 JSClass<JSGrid>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
289 JSClass<JSGrid>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
290 JSClass<JSGrid>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
291 JSClass<JSGrid>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
292 JSClass<JSGrid>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
293 JSClass<JSGrid>::StaticMethod("scrollBar", &JSGrid::SetScrollBar, opt);
294 JSClass<JSGrid>::StaticMethod("scrollBarWidth", &JSGrid::SetScrollBarWidth, opt);
295 JSClass<JSGrid>::StaticMethod("scrollBarColor", &JSGrid::SetScrollBarColor, opt);
296
297 JSClass<JSGrid>::StaticMethod("onScrollBarUpdate", &JSGrid::JsOnScrollBarUpdate);
298 JSClass<JSGrid>::StaticMethod("cachedCount", &JSGrid::SetCachedCount);
299 JSClass<JSGrid>::StaticMethod("editMode", &JSGrid::SetEditMode, opt);
300 JSClass<JSGrid>::StaticMethod("multiSelectable", &JSGrid::SetMultiSelectable, opt);
301 JSClass<JSGrid>::StaticMethod("maxCount", &JSGrid::SetMaxCount, opt);
302 JSClass<JSGrid>::StaticMethod("minCount", &JSGrid::SetMinCount, opt);
303 JSClass<JSGrid>::StaticMethod("cellLength", &JSGrid::CellLength, opt);
304 JSClass<JSGrid>::StaticMethod("layoutDirection", &JSGrid::SetLayoutDirection, opt);
305 JSClass<JSGrid>::StaticMethod("dragAnimation", &JSGrid::SetDragAnimation, opt);
306 JSClass<JSGrid>::StaticMethod("edgeEffect", &JSGrid::SetEdgeEffect, opt);
307 JSClass<JSGrid>::StaticMethod("direction", &JSGrid::SetDirection, opt);
308 JSClass<JSGrid>::StaticMethod("supportAnimation", &JSGrid::SetSupportAnimation, opt);
309 JSClass<JSGrid>::StaticMethod("onItemDragEnter", &JSGrid::JsOnGridDragEnter);
310 JSClass<JSGrid>::StaticMethod("onItemDragMove", &JSGrid::JsOnGridDragMove);
311 JSClass<JSGrid>::StaticMethod("onItemDragLeave", &JSGrid::JsOnGridDragLeave);
312 JSClass<JSGrid>::StaticMethod("onItemDragStart", &JSGrid::JsOnGridDragStart);
313 JSClass<JSGrid>::StaticMethod("height", &JSGrid::JsGridHeight);
314 JSClass<JSGrid>::StaticMethod("onItemDrop", &JSGrid::JsOnGridDrop);
315 JSClass<JSGrid>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
316 JSClass<JSGrid>::StaticMethod("nestedScroll", &JSGrid::SetNestedScroll);
317 JSClass<JSGrid>::StaticMethod("enableScrollInteraction", &JSGrid::SetScrollEnabled);
318 JSClass<JSGrid>::StaticMethod("friction", &JSGrid::SetFriction);
319
320 JSClass<JSGrid>::StaticMethod("onScroll", &JSGrid::JsOnScroll);
321 JSClass<JSGrid>::StaticMethod("onReachStart", &JSGrid::JsOnReachStart);
322 JSClass<JSGrid>::StaticMethod("onReachEnd", &JSGrid::JsOnReachEnd);
323 JSClass<JSGrid>::StaticMethod("onScrollStart", &JSGrid::JsOnScrollStart);
324 JSClass<JSGrid>::StaticMethod("onScrollStop", &JSGrid::JsOnScrollStop);
325 JSClass<JSGrid>::StaticMethod("onScrollIndex", &JSGrid::JsOnScrollIndex);
326 JSClass<JSGrid>::StaticMethod("onScrollFrameBegin", &JSGrid::JsOnScrollFrameBegin);
327
328 JSClass<JSGrid>::InheritAndBind<JSContainerBase>(globalObj);
329 }
330
SetScrollBar(const JSCallbackInfo & info)331 void JSGrid::SetScrollBar(const JSCallbackInfo& info)
332 {
333 int32_t displayMode = 1;
334 if (!info[0]->IsUndefined() && info[0]->IsNumber()) {
335 ParseJsInt32(info[0], displayMode);
336 if (displayMode < 0 || displayMode >= static_cast<int32_t>(DISPLAY_MODE.size())) {
337 LOGE("Param is not valid");
338 return;
339 }
340 }
341 GridModel::GetInstance()->SetScrollBarMode(displayMode);
342 }
343
SetScrollBarColor(const std::string & color)344 void JSGrid::SetScrollBarColor(const std::string& color)
345 {
346 if (!color.empty() && color != "undefined") {
347 GridModel::GetInstance()->SetScrollBarColor(color);
348 return;
349 }
350 auto pipelineContext = PipelineContext::GetCurrentContext();
351 CHECK_NULL_VOID_NOLOG(pipelineContext);
352 auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
353 CHECK_NULL_VOID_NOLOG(theme);
354 Color defaultColor(theme->GetForegroundColor());
355 GridModel::GetInstance()->SetScrollBarColor(defaultColor.ColorToString());
356 }
357
SetScrollBarWidth(const JSCallbackInfo & scrollWidth)358 void JSGrid::SetScrollBarWidth(const JSCallbackInfo& scrollWidth)
359 {
360 auto pipelineContext = PipelineContext::GetCurrentContext();
361 CHECK_NULL_VOID_NOLOG(pipelineContext);
362 auto theme = pipelineContext->GetTheme<ScrollBarTheme>();
363 CHECK_NULL_VOID_NOLOG(theme);
364 CalcDimension scrollBarWidth;
365 if (scrollWidth.Length() < 1) {
366 LOGE("scrollWidth is invalid");
367 return;
368 }
369 if (!ParseJsDimensionVp(scrollWidth[0], scrollBarWidth) || scrollWidth[0]->IsNull() ||
370 scrollWidth[0]->IsUndefined() || (scrollWidth[0]->IsString() && scrollWidth[0]->ToString().empty()) ||
371 LessNotEqual(scrollBarWidth.Value(), 0.0) || scrollBarWidth.Unit() == DimensionUnit::PERCENT) {
372 scrollBarWidth = theme->GetNormalWidth();
373 }
374 GridModel::GetInstance()->SetScrollBarWidth(scrollBarWidth.ToString());
375 }
376
SetCachedCount(const JSCallbackInfo & info)377 void JSGrid::SetCachedCount(const JSCallbackInfo& info)
378 {
379 int32_t cachedCount = 1;
380 auto jsValue = info[0];
381
382 if (!jsValue->IsUndefined() && jsValue->IsNumber()) {
383 ParseJsInt32(jsValue, cachedCount);
384 if (cachedCount < 0) {
385 cachedCount = 1;
386 }
387 }
388
389 GridModel::GetInstance()->SetCachedCount(cachedCount);
390 }
391
SetEditMode(const JSCallbackInfo & info)392 void JSGrid::SetEditMode(const JSCallbackInfo& info)
393 {
394 // undefined means false to EditMode
395 bool editMode = false;
396 if (!info[0]->IsUndefined() && info[0]->IsBoolean()) {
397 ParseJsBool(info[0], editMode);
398 }
399 GridModel::GetInstance()->SetEditable(editMode);
400 }
401
SetMaxCount(const JSCallbackInfo & info)402 void JSGrid::SetMaxCount(const JSCallbackInfo& info)
403 {
404 int32_t maxCount = Infinity<int32_t>();
405 if (!info[0]->IsUndefined() && info[0]->IsNumber()) {
406 ParseJsInt32(info[0], maxCount);
407 if (maxCount < 1) {
408 maxCount = Infinity<int32_t>();
409 }
410 }
411 GridModel::GetInstance()->SetMaxCount(maxCount);
412 }
413
SetMinCount(const JSCallbackInfo & info)414 void JSGrid::SetMinCount(const JSCallbackInfo& info)
415 {
416 int32_t minCount = 1;
417 if (!info[0]->IsUndefined() && info[0]->IsNumber()) {
418 ParseJsInt32(info[0], minCount);
419 if (minCount < 1) {
420 minCount = 1;
421 }
422 }
423 GridModel::GetInstance()->SetMinCount(minCount);
424 }
425
CellLength(int32_t cellLength)426 void JSGrid::CellLength(int32_t cellLength)
427 {
428 GridModel::GetInstance()->SetCellLength(cellLength);
429 }
430
SetSupportAnimation(bool supportAnimation)431 void JSGrid::SetSupportAnimation(bool supportAnimation)
432 {
433 GridModel::GetInstance()->SetSupportAnimation(supportAnimation);
434 }
435
SetDragAnimation(bool value)436 void JSGrid::SetDragAnimation(bool value)
437 {
438 GridModel::GetInstance()->SetSupportDragAnimation(value);
439 }
440
SetEdgeEffect(const JSCallbackInfo & info)441 void JSGrid::SetEdgeEffect(const JSCallbackInfo& info)
442 {
443 if (info.Length() < 1) {
444 LOGE("args is invalid");
445 return;
446 }
447 int32_t edgeEffect;
448 if (info[0]->IsNull() || info[0]->IsUndefined() || !ParseJsInt32(info[0], edgeEffect) ||
449 edgeEffect < static_cast<int32_t>(EdgeEffect::SPRING) || edgeEffect > static_cast<int32_t>(EdgeEffect::NONE)) {
450 edgeEffect = static_cast<int32_t>(EdgeEffect::NONE);
451 }
452 GridModel::GetInstance()->SetEdgeEffect(static_cast<EdgeEffect>(edgeEffect));
453 }
454
SetLayoutDirection(int32_t value)455 void JSGrid::SetLayoutDirection(int32_t value)
456 {
457 if (value < 0 || value >= static_cast<int32_t>(LAYOUT_DIRECTION.size())) {
458 LOGE("Param is not valid");
459 return;
460 }
461 GridModel::GetInstance()->SetLayoutDirection(LAYOUT_DIRECTION[value]);
462 }
463
SetDirection(const std::string & dir)464 void JSGrid::SetDirection(const std::string& dir)
465 {
466 TextDirection direction;
467 if (dir == "Ltr") {
468 direction = TextDirection::LTR;
469 } else if (dir == "Rtl") {
470 direction = TextDirection::RTL;
471 } else {
472 direction = TextDirection::AUTO;
473 }
474 GridModel::GetInstance()->SetIsRTL(direction);
475 }
476
JsOnGridDragEnter(const JSCallbackInfo & info)477 void JSGrid::JsOnGridDragEnter(const JSCallbackInfo& info)
478 {
479 if (!info[0]->IsFunction()) {
480 LOGE("fail to bind onItemDragEnter event due to info is not function");
481 return;
482 }
483
484 RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
485 auto onItemDragEnter = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc)](
486 const ItemDragInfo& dragInfo) {
487 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
488 ACE_SCORING_EVENT("Grid.onItemDragEnter");
489 func->ItemDragEnterExecute(dragInfo);
490 };
491 GridModel::GetInstance()->SetOnItemDragEnter(std::move(onItemDragEnter));
492 }
493
JsOnGridDragMove(const JSCallbackInfo & info)494 void JSGrid::JsOnGridDragMove(const JSCallbackInfo& info)
495 {
496 if (!info[0]->IsFunction()) {
497 LOGE("fail to bind onItemDragMove event due to info is not function");
498 return;
499 }
500
501 RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
502 auto onItemDragMove = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
503 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
504 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
505 ACE_SCORING_EVENT("Grid.onItemDragMove");
506 func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
507 };
508 GridModel::GetInstance()->SetOnItemDragMove(std::move(onItemDragMove));
509 }
510
JsOnGridDragLeave(const JSCallbackInfo & info)511 void JSGrid::JsOnGridDragLeave(const JSCallbackInfo& info)
512 {
513 if (!info[0]->IsFunction()) {
514 LOGE("fail to bind onItemDragLeave event due to info is not function");
515 return;
516 }
517
518 RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
519 auto onItemDragLeave = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
520 const ItemDragInfo& dragInfo, int32_t itemIndex) {
521 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
522 ACE_SCORING_EVENT("Grid.onItemDragLeave");
523 func->ItemDragLeaveExecute(dragInfo, itemIndex);
524 };
525 GridModel::GetInstance()->SetOnItemDragLeave(std::move(onItemDragLeave));
526 }
527
JsOnGridDragStart(const JSCallbackInfo & info)528 void JSGrid::JsOnGridDragStart(const JSCallbackInfo& info)
529 {
530 if (!info[0]->IsFunction()) {
531 LOGE("fail to bind onItemDragStart event due to info is not function");
532 return;
533 }
534
535 auto jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
536 auto onItemDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc)](
537 const ItemDragInfo& dragInfo, int32_t itemIndex) {
538 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
539 ACE_SCORING_EVENT("Grid.onItemDragStart");
540 auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
541 if (!ret->IsObject()) {
542 LOGE("builder param is not an object.");
543 return;
544 }
545
546 auto builderObj = JSRef<JSObject>::Cast(ret);
547 auto builder = builderObj->GetProperty("builder");
548 if (!builder->IsFunction()) {
549 LOGE("builder param is not a function.");
550 return;
551 }
552 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
553 CHECK_NULL_VOID(builderFunc);
554 builderFunc->Execute();
555 };
556 GridModel::GetInstance()->SetOnItemDragStart(std::move(onItemDragStart));
557 }
558
JsOnGridDrop(const JSCallbackInfo & info)559 void JSGrid::JsOnGridDrop(const JSCallbackInfo& info)
560 {
561 if (!info[0]->IsFunction()) {
562 LOGE("fail to bind onItemDrop event due to info is not function");
563 return;
564 }
565
566 RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
567 auto onItemDrop = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
568 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
569 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
570 ACE_SCORING_EVENT("Grid.onItemDrop");
571 func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
572 };
573 GridModel::GetInstance()->SetOnItemDrop(std::move(onItemDrop));
574 }
575
SetMultiSelectable(bool multiSelectable)576 void JSGrid::SetMultiSelectable(bool multiSelectable)
577 {
578 GridModel::GetInstance()->SetMultiSelectable(multiSelectable);
579 }
580
SetNestedScroll(const JSCallbackInfo & args)581 void JSGrid::SetNestedScroll(const JSCallbackInfo& args)
582 {
583 NestedScrollOptions nestedOpt = {
584 .forward = NestedScrollMode::SELF_ONLY,
585 .backward = NestedScrollMode::SELF_ONLY,
586 };
587 if (args.Length() < 1 || !args[0]->IsObject()) {
588 GridModel::GetInstance()->SetNestedScroll(nestedOpt);
589 LOGW("Invalid params");
590 return;
591 }
592 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
593 int32_t froward = 0;
594 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
595 if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
596 froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
597 LOGW("ScrollFroward params invalid");
598 froward = 0;
599 }
600 int32_t backward = 0;
601 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
602 if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
603 backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
604 LOGW("ScrollFroward params invalid");
605 backward = 0;
606 }
607 nestedOpt.forward = static_cast<NestedScrollMode>(froward);
608 nestedOpt.backward = static_cast<NestedScrollMode>(backward);
609 GridModel::GetInstance()->SetNestedScroll(nestedOpt);
610 args.ReturnSelf();
611 }
612
SetFriction(const JSCallbackInfo & info)613 void JSGrid::SetFriction(const JSCallbackInfo& info)
614 {
615 double friction = -1.0;
616 if (!JSViewAbstract::ParseJsDouble(info[0], friction)) {
617 LOGW("Friction params invalid,can not convert to double");
618 friction = -1.0;
619 }
620 GridModel::GetInstance()->SetFriction(friction);
621 }
622
JsOnScroll(const JSCallbackInfo & args)623 void JSGrid::JsOnScroll(const JSCallbackInfo& args)
624 {
625 if (args[0]->IsFunction()) {
626 auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
627 const CalcDimension& scrollOffset, const ScrollState& scrollState) {
628 auto params = ConvertToJSValues(scrollOffset, scrollState);
629 func->Call(JSRef<JSObject>(), params.size(), params.data());
630 return;
631 };
632 GridModel::GetInstance()->SetOnScroll(std::move(onScroll));
633 }
634 args.ReturnSelf();
635 }
636
JsOnScrollStart(const JSCallbackInfo & args)637 void JSGrid::JsOnScrollStart(const JSCallbackInfo& args)
638 {
639 if (args[0]->IsFunction()) {
640 auto onScrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
641 func->Call(JSRef<JSObject>());
642 return;
643 };
644 GridModel::GetInstance()->SetOnScrollStart(std::move(onScrollStart));
645 }
646 args.ReturnSelf();
647 }
648
JsOnScrollStop(const JSCallbackInfo & args)649 void JSGrid::JsOnScrollStop(const JSCallbackInfo& args)
650 {
651 if (args[0]->IsFunction()) {
652 auto onScrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
653 func->Call(JSRef<JSObject>());
654 return;
655 };
656 GridModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
657 }
658 args.ReturnSelf();
659 }
660
JsOnScrollIndex(const JSCallbackInfo & args)661 void JSGrid::JsOnScrollIndex(const JSCallbackInfo& args)
662 {
663 if (args[0]->IsFunction()) {
664 auto onScrollIndex = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
665 const int32_t first, const int32_t last) {
666 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
667 auto params = ConvertToJSValues(first, last);
668 func->Call(JSRef<JSObject>(), params.size(), params.data());
669 return;
670 };
671 GridModel::GetInstance()->SetOnScrollIndex(std::move(onScrollIndex));
672 }
673 args.ReturnSelf();
674 }
675
JsOnScrollFrameBegin(const JSCallbackInfo & args)676 void JSGrid::JsOnScrollFrameBegin(const JSCallbackInfo& args)
677 {
678 if (args[0]->IsFunction()) {
679 auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
680 const Dimension& offset, const ScrollState& state) -> ScrollFrameResult {
681 ScrollFrameResult scrollRes { .offset = offset };
682 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
683 auto params = ConvertToJSValues(offset, state);
684 auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
685 if (result.IsEmpty()) {
686 LOGE("Error calling onScrollFrameBegin, result is empty.");
687 return scrollRes;
688 }
689
690 if (!result->IsObject()) {
691 LOGE("Error calling onScrollFrameBegin, result is not object.");
692 return scrollRes;
693 }
694
695 auto resObj = JSRef<JSObject>::Cast(result);
696 auto dxRemainValue = resObj->GetProperty("offsetRemain");
697 if (dxRemainValue->IsNumber()) {
698 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
699 }
700 return scrollRes;
701 };
702 GridModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollBegin));
703 }
704 }
705
JsOnReachStart(const JSCallbackInfo & args)706 void JSGrid::JsOnReachStart(const JSCallbackInfo& args)
707 {
708 if (args[0]->IsFunction()) {
709 auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
710 func->Call(JSRef<JSObject>());
711 return;
712 };
713 GridModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
714 }
715 args.ReturnSelf();
716 }
717
JsOnReachEnd(const JSCallbackInfo & args)718 void JSGrid::JsOnReachEnd(const JSCallbackInfo& args)
719 {
720 if (args[0]->IsFunction()) {
721 auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
722 func->Call(JSRef<JSObject>());
723 return;
724 };
725 GridModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
726 }
727 args.ReturnSelf();
728 }
729
730 } // namespace OHOS::Ace::Framework
731