• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/declarative_frontend/jsview/js_grid.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "base/utils/utils.h"
20 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
21 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
22 #include "bridge/declarative_frontend/jsview/js_scroller.h"
23 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
24 #include "bridge/declarative_frontend/jsview/models/grid_model_impl.h"
25 #include "core/common/ace_application_info.h"
26 #include "core/common/container.h"
27 #include "core/components_ng/pattern/grid/grid_model_ng.h"
28 #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