1 /*
2 * Copyright (c) 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 "frameworks/bridge/declarative_frontend/jsview/js_side_bar.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/log/ace_scoring_log.h"
20 #include "base/log/log.h"
21 #include "core/components/button/button_component.h"
22 #include "core/components/side_bar/render_side_bar_container.h"
23 #include "core/components_ng/base/view_stack_processor.h"
24 #include "core/components_ng/pattern/side_bar/side_bar_container_view.h"
25 #include "frameworks/bridge/declarative_frontend/jsview/js_view_common_def.h"
26 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
27
28 namespace OHOS::Ace::Framework {
29 namespace {
30 constexpr Dimension DEFAULT_CONTROL_BUTTON_WIDTH = 32.0_vp;
31 constexpr Dimension DEFAULT_CONTROL_BUTTON_HEIGHT = 32.0_vp;
32 constexpr Dimension DEFAULT_SIDE_BAR_WIDTH = 200.0_vp;
33 constexpr Dimension DEFAULT_MIN_SIDE_BAR_WIDTH = 200.0_vp;
34 constexpr Dimension DEFAULT_MAX_SIDE_BAR_WIDTH = 280.0_vp;
35
36 enum class WidthType : uint32_t {
37 SIDEBAR_WIDTH = 0,
38 MIN_SIDEBAR_WIDTH,
39 MAX_SIDEBAR_WIDTH,
40 };
41
ParseAndSetWidth(const JSCallbackInfo & info,WidthType widthType)42 void ParseAndSetWidth(const JSCallbackInfo& info, WidthType widthType)
43 {
44 if (info.Length() < 1) {
45 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
46 return;
47 }
48
49 Dimension value;
50 if (!JSViewAbstract::ParseJsDimensionVp(info[0], value)) {
51 return;
52 }
53
54 if (Container::IsCurrentUseNewPipeline()) {
55 switch (widthType) {
56 case WidthType::SIDEBAR_WIDTH:
57 NG::SideBarContainerView::SetSideBarWidth(value.IsNonNegative() ? value : DEFAULT_SIDE_BAR_WIDTH);
58 break;
59 case WidthType::MIN_SIDEBAR_WIDTH:
60 NG::SideBarContainerView::SetMinSideBarWidth(
61 value.IsNonNegative() ? value : DEFAULT_MIN_SIDE_BAR_WIDTH);
62 break;
63 case WidthType::MAX_SIDEBAR_WIDTH:
64 NG::SideBarContainerView::SetMaxSideBarWidth(
65 value.IsNonNegative() ? value : DEFAULT_MAX_SIDE_BAR_WIDTH);
66 break;
67 default:
68 break;
69 }
70 return;
71 }
72
73 if (LessNotEqual(value.Value(), 0.0)) {
74 LOGW("JSSideBar::ParseAndSetWidth info[0] value is less than 0, the default is set to 0.");
75 value.SetValue(0.0);
76 }
77
78 auto stack = ViewStackProcessor::GetInstance();
79 auto component = AceType::DynamicCast<OHOS::Ace::SideBarContainerComponent>(stack->GetMainComponent());
80 if (!component) {
81 LOGE("side bar is null");
82 return;
83 }
84
85 if (value.Unit() == DimensionUnit::PERCENT) {
86 component->SetIsPercentSize(value.Unit() == DimensionUnit::PERCENT);
87 }
88
89 switch (widthType) {
90 case WidthType::SIDEBAR_WIDTH:
91 component->SetSideBarWidth(value);
92 break;
93 case WidthType::MIN_SIDEBAR_WIDTH:
94 component->SetSideBarMinWidth(value);
95 break;
96 case WidthType::MAX_SIDEBAR_WIDTH:
97 component->SetSideBarMaxWidth(value);
98 break;
99 default:
100 break;
101 }
102 }
103
104 } // namespace
105
Create(const JSCallbackInfo & info)106 void JSSideBar::Create(const JSCallbackInfo& info)
107 {
108 if (Container::IsCurrentUseNewPipeline()) {
109 CreateForNG(info);
110 return;
111 }
112
113 SideBarContainerType style = SideBarContainerType::EMBED;
114 if (!info[0]->IsNull()) {
115 if (info[0]->IsBoolean()) {
116 style = static_cast<SideBarContainerType>(info[0]->ToBoolean());
117 } else if (info[0]->IsNumber()) {
118 style = static_cast<SideBarContainerType>(info[0]->ToNumber<int>());
119 } else {
120 LOGE("The arg is wrong");
121 return;
122 }
123 }
124
125 std::list<RefPtr<Component>> children;
126 auto sideBarContainer = AceType::MakeRefPtr<OHOS::Ace::SideBarContainerComponent>(children);
127 ViewStackProcessor::GetInstance()->ClaimElementId(sideBarContainer);
128 sideBarContainer->SetMainStackSize(MainStackSize::MAX);
129 sideBarContainer->SetSideBarContainerType(style);
130
131 auto stack = ViewStackProcessor::GetInstance();
132 stack->Push(sideBarContainer);
133 JSInteractableView::SetFocusable(false);
134 JSInteractableView::SetFocusNode(true);
135 }
136
CreateForNG(const JSCallbackInfo & info)137 void JSSideBar::CreateForNG(const JSCallbackInfo& info)
138 {
139 NG::SideBarContainerView::Create();
140
141 SideBarContainerType style = SideBarContainerType::EMBED;
142 if (!info[0]->IsNull()) {
143 if (info[0]->IsBoolean()) {
144 style = static_cast<SideBarContainerType>(info[0]->ToBoolean());
145 } else if (info[0]->IsNumber()) {
146 style = static_cast<SideBarContainerType>(info[0]->ToNumber<int>());
147 } else {
148 LOGE("JSSideBar::CreateForNG The SideBarContainerType arg is wrong");
149 return;
150 }
151 }
152
153 NG::SideBarContainerView::SetSideBarContainerType(style);
154 }
155
SetShowControlButton(bool isShow)156 void JSSideBar::SetShowControlButton(bool isShow)
157 {
158 if (Container::IsCurrentUseNewPipeline()) {
159 NG::SideBarContainerView::SetShowControlButton(isShow);
160 return;
161 }
162
163 auto stack = ViewStackProcessor::GetInstance();
164 auto component = AceType::DynamicCast<OHOS::Ace::SideBarContainerComponent>(stack->GetMainComponent());
165 if (!component) {
166 LOGE("side bar is null");
167 return;
168 }
169
170 component->SetShowControlButton(isShow);
171 }
172
JsSideBarPosition(const JSCallbackInfo & info)173 void JSSideBar::JsSideBarPosition(const JSCallbackInfo& info)
174 {
175 if (info.Length() < 1) {
176 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
177 return;
178 }
179 SideBarPosition sideBarPosition = SideBarPosition::START;
180 if (info[0]->IsNumber()) {
181 sideBarPosition = static_cast<SideBarPosition>(info[0]->ToNumber<int>());
182 } else {
183 LOGE("The arg is wrong");
184 return;
185 }
186
187 if (Container::IsCurrentUseNewPipeline()) {
188 NG::SideBarContainerView::SetSideBarPosition(sideBarPosition);
189 return;
190 }
191
192 auto stack = ViewStackProcessor::GetInstance();
193 auto component = AceType::DynamicCast<SideBarContainerComponent>(stack->GetMainComponent());
194 if (!component) {
195 LOGE("side bar is null");
196 return;
197 }
198
199 component->SetSideBarPosition(sideBarPosition);
200 }
201
JSBind(BindingTarget globalObj)202 void JSSideBar::JSBind(BindingTarget globalObj)
203 {
204 JSClass<JSSideBar>::Declare("SideBarContainer");
205 MethodOptions opt = MethodOptions::NONE;
206 JSClass<JSSideBar>::StaticMethod("create", &JSSideBar::Create, opt);
207 JSClass<JSSideBar>::StaticMethod("pop", &JSSideBar::Pop);
208 JSClass<JSSideBar>::StaticMethod("showSideBar", &JSSideBar::JsShowSideBar);
209 JSClass<JSSideBar>::StaticMethod("controlButton", &JSSideBar::JsControlButton);
210 JSClass<JSSideBar>::StaticMethod("showControlButton", &JSSideBar::SetShowControlButton);
211 JSClass<JSSideBar>::StaticMethod("onChange", &JSSideBar::OnChange);
212 JSClass<JSSideBar>::StaticMethod("sideBarWidth", &JSSideBar::JsSideBarWidth);
213 JSClass<JSSideBar>::StaticMethod("minSideBarWidth", &JSSideBar::JsMinSideBarWidth);
214 JSClass<JSSideBar>::StaticMethod("maxSideBarWidth", &JSSideBar::JsMaxSideBarWidth);
215 JSClass<JSSideBar>::StaticMethod("autoHide", &JSSideBar::JsAutoHide);
216 JSClass<JSSideBar>::StaticMethod("sideBarPosition", &JSSideBar::JsSideBarPosition);
217 JSClass<JSSideBar>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
218 JSClass<JSSideBar>::StaticMethod("width", SetWidth);
219 JSClass<JSSideBar>::StaticMethod("height", SetHeight);
220 JSClass<JSSideBar>::StaticMethod("size", SetSize);
221 JSClass<JSSideBar>::StaticMethod("width", &JSStack::SetWidth);
222 JSClass<JSSideBar>::StaticMethod("height", &JSStack::SetHeight);
223 JSClass<JSSideBar>::StaticMethod("size", &JSStack::SetSize);
224 JSClass<JSSideBar>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
225 JSClass<JSSideBar>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
226 JSClass<JSSideBar>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
227 JSClass<JSSideBar>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
228 JSClass<JSSideBar>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
229 JSClass<JSSideBar>::Inherit<JSContainerBase>();
230 JSClass<JSSideBar>::Inherit<JSViewAbstract>();
231 JSClass<JSSideBar>::Bind(globalObj);
232 }
233
OnChange(const JSCallbackInfo & info)234 void JSSideBar::OnChange(const JSCallbackInfo& info)
235 {
236 if (Container::IsCurrentUseNewPipeline()) {
237 if (info.Length() < 1 || !info[0]->IsFunction()) {
238 LOGE("JSSideBar::OnChange info param is wrong.");
239 return;
240 }
241
242 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
243 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool isShow) {
244 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
245 ACE_SCORING_EVENT("SideBarContainer.onChange");
246 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isShow));
247 func->ExecuteJS(1, &newJSVal);
248 };
249 NG::SideBarContainerView::SetOnChange(std::move(onChange));
250 return;
251 }
252
253 if (!JSViewBindEvent(&SideBarContainerComponent::SetOnChange, info)) {
254 LOGE("Failed to bind event");
255 }
256 info.ReturnSelf();
257 }
258
JsSideBarWidth(const JSCallbackInfo & info)259 void JSSideBar::JsSideBarWidth(const JSCallbackInfo& info)
260 {
261 ParseAndSetWidth(info, WidthType::SIDEBAR_WIDTH);
262 }
263
JsMaxSideBarWidth(const JSCallbackInfo & info)264 void JSSideBar::JsMaxSideBarWidth(const JSCallbackInfo& info)
265 {
266 ParseAndSetWidth(info, WidthType::MAX_SIDEBAR_WIDTH);
267 }
268
JsMinSideBarWidth(const JSCallbackInfo & info)269 void JSSideBar::JsMinSideBarWidth(const JSCallbackInfo& info)
270 {
271 ParseAndSetWidth(info, WidthType::MIN_SIDEBAR_WIDTH);
272 }
273
JsShowSideBar(bool isShow)274 void JSSideBar::JsShowSideBar(bool isShow)
275 {
276 if (Container::IsCurrentUseNewPipeline()) {
277 NG::SideBarContainerView::SetShowSideBar(isShow);
278 return;
279 }
280
281 auto stack = ViewStackProcessor::GetInstance();
282 auto component = AceType::DynamicCast<OHOS::Ace::SideBarContainerComponent>(stack->GetMainComponent());
283 if (!component) {
284 LOGE("side bar is null");
285 return;
286 }
287 component->SetShowSideBar(isShow);
288 }
289
JsControlButton(const JSCallbackInfo & info)290 void JSSideBar::JsControlButton(const JSCallbackInfo& info)
291 {
292 if (Container::IsCurrentUseNewPipeline()) {
293 JsControlButtonForNG(info);
294 return;
295 }
296
297 auto stack = ViewStackProcessor::GetInstance();
298 auto component = AceType::DynamicCast<OHOS::Ace::SideBarContainerComponent>(stack->GetMainComponent());
299 if (!component) {
300 LOGE("side bar is null");
301 return;
302 }
303
304 if (!info[0]->IsNull() && info[0]->IsObject()) {
305 JSRef<JSObject> value = JSRef<JSObject>::Cast(info[0]);
306 JSRef<JSVal> width = value->GetProperty("width");
307 JSRef<JSVal> height = value->GetProperty("height");
308 JSRef<JSVal> left = value->GetProperty("left");
309 JSRef<JSVal> top = value->GetProperty("top");
310 JSRef<JSVal> icons = value->GetProperty("icons");
311
312 if (!width->IsNull() && width->IsNumber()) {
313 auto controlButtonWidth = width->ToNumber<double>();
314 if (LessNotEqual(controlButtonWidth, 0.0)) {
315 controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH.Value();
316 }
317 component->SetButtonWidth(controlButtonWidth);
318 }
319
320 if (!height->IsNull() && height->IsNumber()) {
321 auto controlButtonHeight = height->ToNumber<double>();
322 if (LessNotEqual(controlButtonHeight, 0.0)) {
323 controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT.Value();
324 }
325 component->SetButtonHeight(controlButtonHeight);
326 }
327
328 if (!left->IsNull() && left->IsNumber()) {
329 component->SetButtonLeft(left->ToNumber<double>());
330 }
331
332 if (!top->IsNull() && top->IsNumber()) {
333 component->SetButtonTop(top->ToNumber<double>());
334 }
335
336 if (!icons->IsNull() && icons->IsObject()) {
337 JSRef<JSObject> iconsVal = JSRef<JSObject>::Cast(icons);
338 JSRef<JSVal> showIcon = iconsVal->GetProperty("shown");
339 JSRef<JSVal> switchingIcon = iconsVal->GetProperty("switching");
340 JSRef<JSVal> hiddenIcon = iconsVal->GetProperty("hidden");
341 std::string showIconStr;
342 if (!showIcon->IsNull() && ParseJsMedia(showIcon, showIconStr)) {
343 component->SetShowIcon(showIconStr);
344 }
345 std::string hiddenIconStr;
346 if (!hiddenIcon->IsNull() && ParseJsMedia(hiddenIcon, hiddenIconStr)) {
347 component->SetHiddenIcon(hiddenIconStr);
348 }
349 std::string switchingIconStr;
350 if (!switchingIcon->IsNull() && ParseJsMedia(switchingIcon, switchingIconStr)) {
351 component->SetSwitchIcon(switchingIconStr);
352 }
353 }
354 }
355 }
356
JsControlButtonForNG(const JSCallbackInfo & info)357 void JSSideBar::JsControlButtonForNG(const JSCallbackInfo& info)
358 {
359 if (info.Length() < 1) {
360 LOGE("JSSideBar::JsControlButtonForNG The arg is wrong, it is supposed to have at least 1 arguments");
361 return;
362 }
363
364 if (!info[0]->IsNull() && info[0]->IsObject()) {
365 JSRef<JSObject> value = JSRef<JSObject>::Cast(info[0]);
366 JSRef<JSVal> width = value->GetProperty("width");
367 JSRef<JSVal> height = value->GetProperty("height");
368 JSRef<JSVal> left = value->GetProperty("left");
369 JSRef<JSVal> top = value->GetProperty("top");
370 JSRef<JSVal> icons = value->GetProperty("icons");
371
372 if (!width->IsNull() && width->IsNumber()) {
373 auto controlButtonWidth = Dimension(width->ToNumber<double>(), DimensionUnit::VP);
374 if (LessNotEqual(controlButtonWidth.Value(), 0.0)) {
375 controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH;
376 }
377 NG::SideBarContainerView::SetControlButtonWidth(controlButtonWidth);
378 }
379
380 if (!height->IsNull() && height->IsNumber()) {
381 auto controlButtonHeight = Dimension(height->ToNumber<double>(), DimensionUnit::VP);
382 if (LessNotEqual(controlButtonHeight.Value(), 0.0)) {
383 controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT;
384 }
385 NG::SideBarContainerView::SetControlButtonHeight(controlButtonHeight);
386 }
387
388 if (!left->IsNull() && left->IsNumber()) {
389 NG::SideBarContainerView::SetControlButtonLeft(Dimension(left->ToNumber<double>(), DimensionUnit::VP));
390 }
391
392 if (!top->IsNull() && top->IsNumber()) {
393 NG::SideBarContainerView::SetControlButtonTop(Dimension(top->ToNumber<double>(), DimensionUnit::VP));
394 }
395
396 if (!icons->IsNull() && icons->IsObject()) {
397 JSRef<JSObject> iconsVal = JSRef<JSObject>::Cast(icons);
398 JSRef<JSVal> showIcon = iconsVal->GetProperty("shown");
399 JSRef<JSVal> switchingIcon = iconsVal->GetProperty("switching");
400 JSRef<JSVal> hiddenIcon = iconsVal->GetProperty("hidden");
401 std::string showIconStr;
402 if (!showIcon->IsNull() && ParseJsMedia(showIcon, showIconStr)) {
403 NG::SideBarContainerView::SetControlButtonShowIconStr(showIconStr);
404 }
405 std::string hiddenIconStr;
406 if (!hiddenIcon->IsNull() && ParseJsMedia(hiddenIcon, hiddenIconStr)) {
407 NG::SideBarContainerView::SetControlButtonHiddenIconStr(hiddenIconStr);
408 }
409 std::string switchingIconStr;
410 if (!switchingIcon->IsNull() && ParseJsMedia(switchingIcon, switchingIconStr)) {
411 NG::SideBarContainerView::SetControlButtonSwitchingIconStr(switchingIconStr);
412 }
413 }
414 }
415 }
416
JsAutoHide(bool autoHide)417 void JSSideBar::JsAutoHide(bool autoHide)
418 {
419 if (Container::IsCurrentUseNewPipeline()) {
420 NG::SideBarContainerView::SetAutoHide(autoHide);
421 return;
422 }
423
424 auto stack = ViewStackProcessor::GetInstance();
425 auto component = AceType::DynamicCast<OHOS::Ace::SideBarContainerComponent>(stack->GetMainComponent());
426 if (!component) {
427 LOGE("side bar is null");
428 return;
429 }
430 component->SetAutoHide(autoHide);
431 }
432
Pop()433 void JSSideBar::Pop()
434 {
435 if (Container::IsCurrentUseNewPipeline()) {
436 NG::SideBarContainerView::Pop();
437 NG::ViewStackProcessor::GetInstance()->PopContainer();
438 return;
439 }
440
441 ViewStackProcessor::GetInstance()->PopContainer();
442 }
443
444 } // namespace OHOS::Ace::Framework
445