1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "bridge/declarative_frontend/jsview/js_grid.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "base/utils/utils.h"
20 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
21 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
22 #include "bridge/declarative_frontend/jsview/js_scroller.h"
23 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
24 #include "bridge/declarative_frontend/jsview/models/grid_model_impl.h"
25 #include "core/common/ace_application_info.h"
26 #include "core/common/container.h"
27 #include "core/components_ng/pattern/grid/grid_model_ng.h"
28 #include "core/components_v2/grid/grid_event.h"
29
30 namespace OHOS::Ace {
31
32 std::unique_ptr<GridModel> GridModel::instance_ = nullptr;
33
GetInstance()34 GridModel* GridModel::GetInstance()
35 {
36 if (!instance_) {
37 #ifdef NG_BUILD
38 instance_.reset(new NG::GridModelNG());
39 #else
40 if (Container::IsCurrentUseNewPipeline()) {
41 instance_.reset(new NG::GridModelNG());
42 } else {
43 instance_.reset(new Framework::GridModelImpl());
44 }
45 #endif
46 }
47 return instance_.get();
48 }
49
50 } // namespace OHOS::Ace
51
52 namespace OHOS::Ace::Framework {
53 namespace {
54
55 const std::vector<DisplayMode> DISPLAY_MODE = { DisplayMode::OFF, DisplayMode::AUTO, DisplayMode::ON };
56 const std::vector<EdgeEffect> EDGE_EFFECT = { EdgeEffect::SPRING, EdgeEffect::FADE, EdgeEffect::NONE };
57 const std::vector<FlexDirection> LAYOUT_DIRECTION = { FlexDirection::ROW, FlexDirection::COLUMN,
58 FlexDirection::ROW_REVERSE, FlexDirection::COLUMN_REVERSE };
59
60 } // namespace
61
Create(const JSCallbackInfo & info)62 void JSGrid::Create(const JSCallbackInfo& info)
63 {
64 RefPtr<ScrollControllerBase> positionController;
65 RefPtr<ScrollProxy> scrollBarProxy;
66 if (info.Length() > 0 && info[0]->IsObject()) {
67 JSScroller* jsScroller = JSRef<JSObject>::Cast(info[0])->Unwrap<JSScroller>();
68 if (jsScroller) {
69 positionController = GridModel::GetInstance()->CreatePositionController();
70 jsScroller->SetController(positionController);
71
72 // Init scroll bar proxy.
73 scrollBarProxy = jsScroller->GetScrollBarProxy();
74 if (!scrollBarProxy) {
75 scrollBarProxy = GridModel::GetInstance()->CreateScrollBarProxy();
76 jsScroller->SetScrollBarProxy(scrollBarProxy);
77 }
78 }
79 }
80 GridModel::GetInstance()->Create(positionController, scrollBarProxy);
81 }
82
PopGrid(const JSCallbackInfo &)83 void JSGrid::PopGrid(const JSCallbackInfo& /*info*/)
84 {
85 GridModel::GetInstance()->Pop();
86 }
87
UseProxy(const JSCallbackInfo & args)88 void JSGrid::UseProxy(const JSCallbackInfo& args)
89 {
90 auto parentGrid = ViewStackProcessor::GetInstance()->GetTopGrid();
91 if (parentGrid == nullptr) {
92 LOGE("no parent Grid");
93 }
94
95 // return true if code path for GridElement and its children will rely on
96 // ElementProxy. Only in this case shallow render functionality can be used
97 // see also GridLayoutComponent::CreateElement() and GridItemElementProxy class
98 LOGD("parent Grid uses proxied code path %{public}s.",
99 (parentGrid ? !parentGrid->UseNonProxiedCodePath() ? "yes" : "false" : "no parent grid (error)"));
100 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(parentGrid ? !parentGrid->UseNonProxiedCodePath() : false)));
101 }
102
SetColumnsTemplate(const std::string & value)103 void JSGrid::SetColumnsTemplate(const std::string& value)
104 {
105 GridModel::GetInstance()->SetColumnsTemplate(value);
106 }
107
SetRowsTemplate(const std::string & value)108 void JSGrid::SetRowsTemplate(const std::string& value)
109 {
110 GridModel::GetInstance()->SetRowsTemplate(value);
111 }
112
SetColumnsGap(const JSCallbackInfo & info)113 void JSGrid::SetColumnsGap(const JSCallbackInfo& info)
114 {
115 if (info.Length() < 1) {
116 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
117 return;
118 }
119 Dimension colGap;
120
121 if (!ParseJsDimensionVp(info[0], colGap) || colGap.Value() < 0) {
122 colGap.SetValue(0.0);
123 }
124
125 GridModel::GetInstance()->SetColumnsGap(colGap);
126 }
127
SetRowsGap(const JSCallbackInfo & info)128 void JSGrid::SetRowsGap(const JSCallbackInfo& info)
129 {
130 if (info.Length() < 1) {
131 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
132 return;
133 }
134 Dimension rowGap;
135
136 if (!ParseJsDimensionVp(info[0], rowGap) || rowGap.Value() < 0) {
137 rowGap.SetValue(0.0);
138 }
139
140 GridModel::GetInstance()->SetRowsGap(rowGap);
141 }
142
JsGridHeight(const JSCallbackInfo & info)143 void JSGrid::JsGridHeight(const JSCallbackInfo& info)
144 {
145 if (info.Length() < 1) {
146 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
147 return;
148 }
149
150 Dimension value;
151 if (!ParseJsDimensionVp(info[0], value)) {
152 LOGE("parse height fail for grid, please check.");
153 return;
154 }
155 if (LessNotEqual(value.Value(), 0.0)) {
156 value.SetValue(0.0);
157 }
158 GridModel::GetInstance()->SetGridHeight(value);
159 }
160
JsOnScrollIndex(const JSCallbackInfo & info)161 void JSGrid::JsOnScrollIndex(const JSCallbackInfo& info)
162 {
163 if (!info[0]->IsFunction()) {
164 LOGE("param not valid, need function");
165 return;
166 }
167
168 auto onScrollIndex = [execCtx = info.GetExecutionContext(), func = JSRef<JSFunc>::Cast(info[0])](
169 const BaseEventInfo* event) {
170 JAVASCRIPT_EXECUTION_SCOPE(execCtx);
171 const auto* eventInfo = TypeInfoHelper::DynamicCast<V2::GridEventInfo>(event);
172 if (!eventInfo) {
173 return;
174 }
175 auto params = ConvertToJSValues(eventInfo->GetScrollIndex());
176 func->Call(JSRef<JSObject>(), static_cast<int>(params.size()), params.data());
177 };
178 GridModel::GetInstance()->SetOnScrollToIndex(std::move(onScrollIndex));
179 }
180
JSBind(BindingTarget globalObj)181 void JSGrid::JSBind(BindingTarget globalObj)
182 {
183 LOGD("JSGrid:Bind");
184 JSClass<JSGrid>::Declare("Grid");
185
186 MethodOptions opt = MethodOptions::NONE;
187 JSClass<JSGrid>::StaticMethod("create", &JSGrid::Create, opt);
188 JSClass<JSGrid>::StaticMethod("pop", &JSGrid::PopGrid, opt);
189 JSClass<JSGrid>::StaticMethod("willUseProxy", &JSGrid::UseProxy, opt);
190 JSClass<JSGrid>::StaticMethod("columnsTemplate", &JSGrid::SetColumnsTemplate, opt);
191 JSClass<JSGrid>::StaticMethod("rowsTemplate", &JSGrid::SetRowsTemplate, opt);
192 JSClass<JSGrid>::StaticMethod("columnsGap", &JSGrid::SetColumnsGap, opt);
193 JSClass<JSGrid>::StaticMethod("rowsGap", &JSGrid::SetRowsGap, opt);
194 JSClass<JSGrid>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
195 JSClass<JSGrid>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
196 JSClass<JSGrid>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
197 JSClass<JSGrid>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
198 JSClass<JSGrid>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
199 JSClass<JSGrid>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
200 JSClass<JSGrid>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
201 JSClass<JSGrid>::StaticMethod("scrollBar", &JSGrid::SetScrollBar, opt);
202 JSClass<JSGrid>::StaticMethod("scrollBarWidth", &JSGrid::SetScrollBarWidth, opt);
203 JSClass<JSGrid>::StaticMethod("scrollBarColor", &JSGrid::SetScrollBarColor, opt);
204 JSClass<JSGrid>::StaticMethod("onScrollIndex", &JSGrid::JsOnScrollIndex);
205 JSClass<JSGrid>::StaticMethod("cachedCount", &JSGrid::SetCachedCount);
206 JSClass<JSGrid>::StaticMethod("editMode", &JSGrid::SetEditMode, opt);
207 JSClass<JSGrid>::StaticMethod("multiSelectable", &JSGrid::SetMultiSelectable, opt);
208 JSClass<JSGrid>::StaticMethod("maxCount", &JSGrid::SetMaxCount, opt);
209 JSClass<JSGrid>::StaticMethod("minCount", &JSGrid::SetMinCount, opt);
210 JSClass<JSGrid>::StaticMethod("cellLength", &JSGrid::CellLength, opt);
211 JSClass<JSGrid>::StaticMethod("layoutDirection", &JSGrid::SetLayoutDirection, opt);
212 JSClass<JSGrid>::StaticMethod("dragAnimation", &JSGrid::SetDragAnimation, opt);
213 JSClass<JSGrid>::StaticMethod("edgeEffect", &JSGrid::SetEdgeEffect, opt);
214 JSClass<JSGrid>::StaticMethod("direction", &JSGrid::SetDirection, opt);
215 JSClass<JSGrid>::StaticMethod("supportAnimation", &JSGrid::SetSupportAnimation, opt);
216 JSClass<JSGrid>::StaticMethod("onItemDragEnter", &JSGrid::JsOnGridDragEnter);
217 JSClass<JSGrid>::StaticMethod("onItemDragMove", &JSGrid::JsOnGridDragMove);
218 JSClass<JSGrid>::StaticMethod("onItemDragLeave", &JSGrid::JsOnGridDragLeave);
219 JSClass<JSGrid>::StaticMethod("onItemDragStart", &JSGrid::JsOnGridDragStart);
220 JSClass<JSGrid>::StaticMethod("height", &JSGrid::JsGridHeight);
221 JSClass<JSGrid>::StaticMethod("onItemDrop", &JSGrid::JsOnGridDrop);
222 JSClass<JSGrid>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
223 JSClass<JSGrid>::Inherit<JSContainerBase>();
224 JSClass<JSGrid>::Inherit<JSViewAbstract>();
225 JSClass<JSGrid>::Bind<>(globalObj);
226 }
227
SetScrollBar(int32_t displayMode)228 void JSGrid::SetScrollBar(int32_t displayMode)
229 {
230 if (displayMode < 0 || displayMode >= static_cast<int32_t>(DISPLAY_MODE.size())) {
231 LOGE("Param is not valid");
232 return;
233 }
234 GridModel::GetInstance()->SetScrollBarMode(displayMode);
235 }
236
SetScrollBarColor(const std::string & color)237 void JSGrid::SetScrollBarColor(const std::string& color)
238 {
239 GridModel::GetInstance()->SetScrollBarColor(color);
240 }
241
SetScrollBarWidth(const std::string & width)242 void JSGrid::SetScrollBarWidth(const std::string& width)
243 {
244 GridModel::GetInstance()->SetScrollBarWidth(width);
245 }
246
SetCachedCount(int32_t cachedCount)247 void JSGrid::SetCachedCount(int32_t cachedCount)
248 {
249 GridModel::GetInstance()->SetCachedCount(cachedCount);
250 }
251
SetEditMode(bool editMode)252 void JSGrid::SetEditMode(bool editMode)
253 {
254 GridModel::GetInstance()->SetEditable(editMode);
255 }
256
SetMaxCount(double maxCount)257 void JSGrid::SetMaxCount(double maxCount)
258 {
259 GridModel::GetInstance()->SetMaxCount(static_cast<int32_t>(maxCount));
260 }
261
SetMinCount(double minCount)262 void JSGrid::SetMinCount(double minCount)
263 {
264 GridModel::GetInstance()->SetMinCount(static_cast<int32_t>(minCount));
265 }
266
CellLength(int32_t cellLength)267 void JSGrid::CellLength(int32_t cellLength)
268 {
269 GridModel::GetInstance()->SetCellLength(cellLength);
270 }
271
SetSupportAnimation(bool supportAnimation)272 void JSGrid::SetSupportAnimation(bool supportAnimation)
273 {
274 GridModel::GetInstance()->SetSupportAnimation(supportAnimation);
275 }
276
SetDragAnimation(bool value)277 void JSGrid::SetDragAnimation(bool value)
278 {
279 GridModel::GetInstance()->SetSupportDragAnimation(value);
280 }
281
SetEdgeEffect(int32_t value)282 void JSGrid::SetEdgeEffect(int32_t value)
283 {
284 if (value < 0 || value >= static_cast<int32_t>(EDGE_EFFECT.size())) {
285 return;
286 }
287 GridModel::GetInstance()->SetEdgeEffect(EDGE_EFFECT[value]);
288 }
289
SetLayoutDirection(int32_t value)290 void JSGrid::SetLayoutDirection(int32_t value)
291 {
292 if (value < 0 || value >= static_cast<int32_t>(LAYOUT_DIRECTION.size())) {
293 LOGE("Param is not valid");
294 return;
295 }
296 GridModel::GetInstance()->SetLayoutDirection(LAYOUT_DIRECTION[value]);
297 }
298
SetDirection(const std::string & dir)299 void JSGrid::SetDirection(const std::string& dir)
300 {
301 bool rightToLeft = false;
302 if (dir == "Ltr") {
303 rightToLeft = false;
304 } else if (dir == "Rtl") {
305 rightToLeft = true;
306 } else {
307 rightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
308 }
309 GridModel::GetInstance()->SetIsRTL(rightToLeft);
310 }
311
JsOnGridDragEnter(const JSCallbackInfo & info)312 void JSGrid::JsOnGridDragEnter(const JSCallbackInfo& info)
313 {
314 if (!info[0]->IsFunction()) {
315 LOGE("fail to bind onItemDragEnter event due to info is not function");
316 return;
317 }
318
319 RefPtr<JsDragFunction> jsOnDragEnterFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
320 auto onItemDragEnter = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragEnterFunc)](
321 const ItemDragInfo& dragInfo) {
322 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
323 ACE_SCORING_EVENT("Grid.onItemDragEnter");
324 func->ItemDragEnterExecute(dragInfo);
325 };
326 GridModel::GetInstance()->SetOnItemDragEnter(std::move(onItemDragEnter));
327 }
328
JsOnGridDragMove(const JSCallbackInfo & info)329 void JSGrid::JsOnGridDragMove(const JSCallbackInfo& info)
330 {
331 if (!info[0]->IsFunction()) {
332 LOGE("fail to bind onItemDragMove event due to info is not function");
333 return;
334 }
335
336 RefPtr<JsDragFunction> jsOnDragMoveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
337 auto onItemDragMove = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragMoveFunc)](
338 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex) {
339 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
340 ACE_SCORING_EVENT("Grid.onItemDragMove");
341 func->ItemDragMoveExecute(dragInfo, itemIndex, insertIndex);
342 };
343 GridModel::GetInstance()->SetOnItemDragMove(std::move(onItemDragMove));
344 }
345
JsOnGridDragLeave(const JSCallbackInfo & info)346 void JSGrid::JsOnGridDragLeave(const JSCallbackInfo& info)
347 {
348 if (!info[0]->IsFunction()) {
349 LOGE("fail to bind onItemDragLeave event due to info is not function");
350 return;
351 }
352
353 RefPtr<JsDragFunction> jsOnDragLeaveFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
354 auto onItemDragLeave = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragLeaveFunc)](
355 const ItemDragInfo& dragInfo, int32_t itemIndex) {
356 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
357 ACE_SCORING_EVENT("Grid.onItemDragLeave");
358 func->ItemDragLeaveExecute(dragInfo, itemIndex);
359 };
360 GridModel::GetInstance()->SetOnItemDragLeave(std::move(onItemDragLeave));
361 }
362
JsOnGridDragStart(const JSCallbackInfo & info)363 void JSGrid::JsOnGridDragStart(const JSCallbackInfo& info)
364 {
365 if (!info[0]->IsFunction()) {
366 LOGE("fail to bind onItemDragStart event due to info is not function");
367 return;
368 }
369
370 auto jsOnDragFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
371 auto onItemDragStart = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragFunc)](
372 const ItemDragInfo& dragInfo, int32_t itemIndex) {
373 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
374 ACE_SCORING_EVENT("Grid.onItemDragStart");
375 auto ret = func->ItemDragStartExecute(dragInfo, itemIndex);
376 if (!ret->IsObject()) {
377 LOGE("builder param is not an object.");
378 return;
379 }
380
381 auto builderObj = JSRef<JSObject>::Cast(ret);
382 auto builder = builderObj->GetProperty("builder");
383 if (!builder->IsFunction()) {
384 LOGE("builder param is not a function.");
385 return;
386 }
387 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
388 CHECK_NULL_VOID(builderFunc);
389 builderFunc->Execute();
390 };
391 GridModel::GetInstance()->SetOnItemDragStart(std::move(onItemDragStart));
392 }
393
JsOnGridDrop(const JSCallbackInfo & info)394 void JSGrid::JsOnGridDrop(const JSCallbackInfo& info)
395 {
396 if (!info[0]->IsFunction()) {
397 LOGE("fail to bind onItemDrop event due to info is not function");
398 return;
399 }
400
401 RefPtr<JsDragFunction> jsOnDropFunc = AceType::MakeRefPtr<JsDragFunction>(JSRef<JSFunc>::Cast(info[0]));
402 auto onItemDrop = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDropFunc)](
403 const ItemDragInfo& dragInfo, int32_t itemIndex, int32_t insertIndex, bool isSuccess) {
404 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
405 ACE_SCORING_EVENT("Grid.onItemDrop");
406 func->ItemDropExecute(dragInfo, itemIndex, insertIndex, isSuccess);
407 };
408 GridModel::GetInstance()->SetOnItemDrop(std::move(onItemDrop));
409 }
410
SetMultiSelectable(bool multiSelectable)411 void JSGrid::SetMultiSelectable(bool multiSelectable)
412 {
413 GridModel::GetInstance()->SetMultiSelectable(multiSelectable);
414 }
415
416 } // namespace OHOS::Ace::Framework
417