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
437 GridModel::GetInstance()->SetCachedCount(cachedCount);
438 }
439
SetEditMode(const JSCallbackInfo & info)440 void JSGrid::SetEditMode(const JSCallbackInfo& info)
441 {
442 // undefined means false to EditMode
443 bool editMode = false;
444 if (!info[0]->IsUndefined() && info[0]->IsBoolean()) {
445 ParseJsBool(info[0], editMode);
446 }
447 GridModel::GetInstance()->SetEditable(editMode);
448 }
449
SetMaxCount(const JSCallbackInfo & info)450 void JSGrid::SetMaxCount(const JSCallbackInfo& info)
451 {
452 int32_t maxCount = Infinity<int32_t>();
453 if (!info[0]->IsUndefined() && info[0]->IsNumber()) {
454 ParseJsInt32(info[0], maxCount);
455 if (maxCount < 1) {
456 maxCount = Infinity<int32_t>();
457 }
458 }
459 GridModel::GetInstance()->SetMaxCount(maxCount);
460 }
461
SetMinCount(const JSCallbackInfo & info)462 void JSGrid::SetMinCount(const JSCallbackInfo& info)
463 {
464 int32_t minCount = 1;
465 if (!info[0]->IsUndefined() && info[0]->IsNumber()) {
466 ParseJsInt32(info[0], minCount);
467 if (minCount < 1) {
468 minCount = 1;
469 }
470 }
471 GridModel::GetInstance()->SetMinCount(minCount);
472 }
473
CellLength(int32_t cellLength)474 void JSGrid::CellLength(int32_t cellLength)
475 {
476 GridModel::GetInstance()->SetCellLength(cellLength);
477 }
478
SetSupportAnimation(bool supportAnimation)479 void JSGrid::SetSupportAnimation(bool supportAnimation)
480 {
481 GridModel::GetInstance()->SetSupportAnimation(supportAnimation);
482 }
483
SetDragAnimation(bool value)484 void JSGrid::SetDragAnimation(bool value)
485 {
486 GridModel::GetInstance()->SetSupportDragAnimation(value);
487 }
488
SetEdgeEffect(const JSCallbackInfo & info)489 void JSGrid::SetEdgeEffect(const JSCallbackInfo& info)
490 {
491 auto edgeEffect = EdgeEffect::NONE;
492 if (info.Length() > 0) {
493 edgeEffect = JSScrollable::ParseEdgeEffect(info[0], EdgeEffect::NONE);
494 }
495 auto alwaysEnabled = false;
496 if (info.Length() > 1) {
497 alwaysEnabled = JSScrollable::ParseAlwaysEnable(info[1], false);
498 }
499 GridModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled);
500 }
501
SetLayoutDirection(int32_t value)502 void JSGrid::SetLayoutDirection(int32_t value)
503 {
504 if (value < 0 || value >= static_cast<int32_t>(LAYOUT_DIRECTION.size())) {
505 return;
506 }
507 GridModel::GetInstance()->SetLayoutDirection(LAYOUT_DIRECTION[value]);
508 }
509
SetDirection(const std::string & dir)510 void JSGrid::SetDirection(const std::string& dir)
511 {
512 TextDirection direction;
513 if (dir == "Ltr") {
514 direction = TextDirection::LTR;
515 } else if (dir == "Rtl") {
516 direction = TextDirection::RTL;
517 } else {
518 direction = TextDirection::AUTO;
519 }
520 GridModel::GetInstance()->SetIsRTL(direction);
521 }
522
JsOnGridDragEnter(const JSCallbackInfo & info)523 void JSGrid::JsOnGridDragEnter(const JSCallbackInfo& info)
524 {
525 if (!info[0]->IsFunction()) {
526 return;
527 }
528
529 RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
530 auto onItemDragEnter = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc)](
531 const ItemDragInfo& dragInfo) {
532 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
533 ACE_SCORING_EVENT("Grid.onItemDragEnter");
534 func->ItemDragEnterExecute(dragInfo);
535 };
536 GridModel::GetInstance()->SetOnItemDragEnter(std::move(onItemDragEnter));
537 }
538
JsOnGridDragMove(const JSCallbackInfo & info)539 void JSGrid::JsOnGridDragMove(const JSCallbackInfo& info)
540 {
541 if (!info[0]->IsFunction()) {
542 return;
543 }
544
545 RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
546 auto onItemDragMove = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
547 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
548 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
549 ACE_SCORING_EVENT("Grid.onItemDragMove");
550 func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
551 };
552 GridModel::GetInstance()->SetOnItemDragMove(std::move(onItemDragMove));
553 }
554
JsOnGridDragLeave(const JSCallbackInfo & info)555 void JSGrid::JsOnGridDragLeave(const JSCallbackInfo& info)
556 {
557 if (!info[0]->IsFunction()) {
558 return;
559 }
560
561 RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
562 auto onItemDragLeave = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
563 const ItemDragInfo& dragInfo, int32_t itemIndex) {
564 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
565 ACE_SCORING_EVENT("Grid.onItemDragLeave");
566 func->ItemDragLeaveExecute(dragInfo, itemIndex);
567 };
568 GridModel::GetInstance()->SetOnItemDragLeave(std::move(onItemDragLeave));
569 }
570
JsOnGridDragStart(const JSCallbackInfo & info)571 void JSGrid::JsOnGridDragStart(const JSCallbackInfo& info)
572 {
573 if (!info[0]->IsFunction()) {
574 return;
575 }
576
577 auto jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
578 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
579 auto onItemDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc), node = targetNode](
580 const ItemDragInfo& dragInfo, int32_t itemIndex) {
581 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
582 ACE_SCORING_EVENT("Grid.onItemDragStart");
583 auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
584 if (!ret->IsObject()) {
585 return;
586 }
587
588 auto builderObj = JSRef<JSObject>::Cast(ret);
589 auto builder = builderObj->GetProperty("builder");
590 if (!builder->IsFunction()) {
591 return;
592 }
593 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
594 CHECK_NULL_VOID(builderFunc);
595 PipelineContext::SetCallBackNode(node);
596 builderFunc->Execute();
597 };
598 GridModel::GetInstance()->SetOnItemDragStart(std::move(onItemDragStart));
599 }
600
JsOnGridDrop(const JSCallbackInfo & info)601 void JSGrid::JsOnGridDrop(const JSCallbackInfo& info)
602 {
603 if (!info[0]->IsFunction()) {
604 return;
605 }
606
607 RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
608 auto onItemDrop = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
609 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
610 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
611 ACE_SCORING_EVENT("Grid.onItemDrop");
612 func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
613 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
614 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Grid.onItemDrop");
615 #endif
616 };
617 GridModel::GetInstance()->SetOnItemDrop(std::move(onItemDrop));
618 }
619
SetMultiSelectable(bool multiSelectable)620 void JSGrid::SetMultiSelectable(bool multiSelectable)
621 {
622 GridModel::GetInstance()->SetMultiSelectable(multiSelectable);
623 }
624
SetNestedScroll(const JSCallbackInfo & args)625 void JSGrid::SetNestedScroll(const JSCallbackInfo& args)
626 {
627 NestedScrollOptions nestedOpt = {
628 .forward = NestedScrollMode::SELF_ONLY,
629 .backward = NestedScrollMode::SELF_ONLY,
630 };
631 if (args.Length() < 1 || !args[0]->IsObject()) {
632 GridModel::GetInstance()->SetNestedScroll(nestedOpt);
633 return;
634 }
635 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
636 int32_t froward = 0;
637 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
638 if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
639 froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
640 froward = 0;
641 }
642 int32_t backward = 0;
643 JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
644 if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
645 backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
646 backward = 0;
647 }
648 nestedOpt.forward = static_cast<NestedScrollMode>(froward);
649 nestedOpt.backward = static_cast<NestedScrollMode>(backward);
650 GridModel::GetInstance()->SetNestedScroll(nestedOpt);
651 args.ReturnSelf();
652 }
653
SetFriction(const JSCallbackInfo & info)654 void JSGrid::SetFriction(const JSCallbackInfo& info)
655 {
656 double friction = -1.0;
657 if (!JSViewAbstract::ParseJsDouble(info[0], friction)) {
658 friction = -1.0;
659 }
660 GridModel::GetInstance()->SetFriction(friction);
661 }
662
SetAlignItems(const JSCallbackInfo & info)663 void JSGrid::SetAlignItems(const JSCallbackInfo& info)
664 {
665 if (info.Length() < 1) {
666 GridModel::GetInstance()->SetAlignItems(GridItemAlignment::DEFAULT);
667 return;
668 }
669
670 if (info[0]->IsNumber()) {
671 auto itemAlign = static_cast<GridItemAlignment>(info[0]->ToNumber<int32_t>());
672 if (itemAlign < GridItemAlignment::DEFAULT || itemAlign > GridItemAlignment::STRETCH) {
673 itemAlign = GridItemAlignment::DEFAULT;
674 }
675 GridModel::GetInstance()->SetAlignItems(itemAlign);
676 } else {
677 GridModel::GetInstance()->SetAlignItems(GridItemAlignment::DEFAULT);
678 }
679 }
680
JsOnScroll(const JSCallbackInfo & args)681 void JSGrid::JsOnScroll(const JSCallbackInfo& args)
682 {
683 if (args[0]->IsFunction()) {
684 auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
685 const CalcDimension& scrollOffset, const ScrollState& scrollState) {
686 auto params = ConvertToJSValues(scrollOffset, scrollState);
687 func->Call(JSRef<JSObject>(), params.size(), params.data());
688 return;
689 };
690 GridModel::GetInstance()->SetOnScroll(std::move(onScroll));
691 }
692 args.ReturnSelf();
693 }
694
JsOnScrollStart(const JSCallbackInfo & args)695 void JSGrid::JsOnScrollStart(const JSCallbackInfo& args)
696 {
697 if (args[0]->IsFunction()) {
698 auto onScrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
699 func->Call(JSRef<JSObject>());
700 return;
701 };
702 GridModel::GetInstance()->SetOnScrollStart(std::move(onScrollStart));
703 }
704 args.ReturnSelf();
705 }
706
JsOnScrollStop(const JSCallbackInfo & args)707 void JSGrid::JsOnScrollStop(const JSCallbackInfo& args)
708 {
709 if (args[0]->IsFunction()) {
710 auto onScrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
711 func->Call(JSRef<JSObject>());
712 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
713 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Grid.onScrollStop");
714 #endif
715 return;
716 };
717 GridModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
718 }
719 args.ReturnSelf();
720 }
721
JsOnScrollIndex(const JSCallbackInfo & args)722 void JSGrid::JsOnScrollIndex(const JSCallbackInfo& args)
723 {
724 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
725 JsOnScrollToIndex(args);
726 return;
727 }
728
729 if (args[0]->IsFunction()) {
730 auto onScrollIndex = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
731 const int32_t first, const int32_t last) {
732 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
733 auto params = ConvertToJSValues(first, last);
734 func->Call(JSRef<JSObject>(), params.size(), params.data());
735 return;
736 };
737 GridModel::GetInstance()->SetOnScrollIndex(std::move(onScrollIndex));
738 }
739 args.ReturnSelf();
740 }
741
JsOnScrollFrameBegin(const JSCallbackInfo & args)742 void JSGrid::JsOnScrollFrameBegin(const JSCallbackInfo& args)
743 {
744 if (args[0]->IsFunction()) {
745 auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
746 const Dimension& offset, const ScrollState& state) -> ScrollFrameResult {
747 ScrollFrameResult scrollRes { .offset = offset };
748 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
749 auto params = ConvertToJSValues(offset, state);
750 auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
751 if (result.IsEmpty()) {
752 return scrollRes;
753 }
754
755 if (!result->IsObject()) {
756 return scrollRes;
757 }
758
759 auto resObj = JSRef<JSObject>::Cast(result);
760 auto dxRemainValue = resObj->GetProperty("offsetRemain");
761 if (dxRemainValue->IsNumber()) {
762 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
763 }
764 return scrollRes;
765 };
766 GridModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollBegin));
767 }
768 }
769
JsOnReachStart(const JSCallbackInfo & args)770 void JSGrid::JsOnReachStart(const JSCallbackInfo& args)
771 {
772 if (args[0]->IsFunction()) {
773 auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
774 func->Call(JSRef<JSObject>());
775 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
776 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Grid.onReachStart");
777 #endif
778 return;
779 };
780 GridModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
781 }
782 args.ReturnSelf();
783 }
784
JsOnReachEnd(const JSCallbackInfo & args)785 void JSGrid::JsOnReachEnd(const JSCallbackInfo& args)
786 {
787 if (args[0]->IsFunction()) {
788 auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
789 func->Call(JSRef<JSObject>());
790 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
791 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Grid.onReachEnd");
792 #endif
793 return;
794 };
795 GridModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
796 }
797 args.ReturnSelf();
798 }
799
800 } // namespace OHOS::Ace::Framework
801