• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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