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