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