1 /*
2 * Copyright (c) 2021 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_navigation.h"
17
18 #include "core/components/navigation_bar/navigation_bar_component_v2.h"
19 #include "core/components/navigation_bar/navigation_container_component.h"
20 #include "core/components/option/option_component.h"
21 #include "frameworks/bridge/declarative_frontend/engine/functions/js_click_function.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23
24 namespace OHOS::Ace::Framework {
25 namespace {
26
TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent & eventInfo)27 JSRef<JSVal> TitleModeChangeEventToJSValue(const NavigationTitleModeChangeEvent& eventInfo)
28 {
29 return JSRef<JSVal>::Make(ToJSValue(eventInfo.IsMiniBar() ? static_cast<int32_t>(NavigationTitleMode::MINI)
30 : static_cast<int32_t>(NavigationTitleMode::FULL)));
31 }
32
ParseToolBarItems(const JSRef<JSArray> & jsArray,std::list<RefPtr<ToolBarItem>> & items)33 void ParseToolBarItems(const JSRef<JSArray>& jsArray, std::list<RefPtr<ToolBarItem>>& items)
34 {
35 auto length = jsArray->Length();
36 for (size_t i = 0; i < length; i++) {
37 auto item = jsArray->GetValueAt(i);
38 if (!item->IsObject()) {
39 LOGE("tool bar item is not object");
40 continue;
41 }
42
43 auto itemObject = JSRef<JSObject>::Cast(item);
44 auto toolBarItem = AceType::MakeRefPtr<ToolBarItem>();
45 auto itemValueObject = itemObject->GetProperty("value");
46 if (itemValueObject->IsString()) {
47 toolBarItem->value = itemValueObject->ToString();
48 }
49
50 auto itemIconObject = itemObject->GetProperty("icon");
51 if (itemIconObject->IsString()) {
52 toolBarItem->icon = itemIconObject->ToString();
53 }
54
55 auto itemActionValue = itemObject->GetProperty("action");
56 if (itemActionValue->IsFunction()) {
57 auto onClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
58 toolBarItem->action = EventMarker(
59 [func = std::move(onClickFunc)]() {
60 ACE_SCORING_EVENT("Navigation.toolBarItemClick");
61 func->Execute();
62 });
63 auto onClickWithParamFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(itemActionValue));
64 toolBarItem->actionWithParam = EventMarker(
65 [func = std::move(onClickWithParamFunc)](const BaseEventInfo* info) {
66 ACE_SCORING_EVENT("Navigation.menuItemButtonClick");
67 func->Execute();
68 });
69 }
70 items.push_back(toolBarItem);
71 }
72 }
73
74 } // namespace
75
Create()76 void JSNavigation::Create()
77 {
78 auto navigationContainer = AceType::MakeRefPtr<NavigationContainerComponent>();
79 ViewStackProcessor::GetInstance()->Push(navigationContainer);
80 }
81
JSBind(BindingTarget globalObj)82 void JSNavigation::JSBind(BindingTarget globalObj)
83 {
84 JSClass<JSNavigation>::Declare("Navigation");
85 MethodOptions opt = MethodOptions::NONE;
86 JSClass<JSNavigation>::StaticMethod("create", &JSNavigation::Create, opt);
87 JSClass<JSNavigation>::StaticMethod("title", &JSNavigation::SetTitle, opt);
88 JSClass<JSNavigation>::StaticMethod("subTitle", &JSNavigation::SetSubTitle, opt);
89 JSClass<JSNavigation>::StaticMethod("titleMode", &JSNavigation::SetTitleMode, opt);
90 JSClass<JSNavigation>::StaticMethod("hideTitleBar", &JSNavigation::SetHideTitleBar, opt);
91 JSClass<JSNavigation>::StaticMethod("hideBackButton", &JSNavigation::SetHideBackButton, opt);
92 JSClass<JSNavigation>::StaticMethod("hideToolBar", &JSNavigation::SetHideToolBar, opt);
93 JSClass<JSNavigation>::StaticMethod("toolBar", &JSNavigation::SetToolBar);
94 JSClass<JSNavigation>::StaticMethod("menus", &JSNavigation::SetMenus);
95 JSClass<JSNavigation>::StaticMethod("menuCount", &JSNavigation::SetMenuCount);
96 // keep compatible, need remove after
97 JSClass<JSNavigation>::StaticMethod("onTitleModeChanged", &JSNavigation::SetOnTitleModeChanged);
98 JSClass<JSNavigation>::StaticMethod("onTitleModeChange", &JSNavigation::SetOnTitleModeChanged);
99 JSClass<JSNavigation>::Inherit<JSContainerBase>();
100 JSClass<JSNavigation>::Inherit<JSViewAbstract>();
101 JSClass<JSNavigation>::Bind(globalObj);
102 }
103
SetTitle(const JSCallbackInfo & info)104 void JSNavigation::SetTitle(const JSCallbackInfo& info)
105 {
106 if (info.Length() < 1) {
107 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
108 return;
109 }
110 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
111 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
112 if (!navigationContainer) {
113 LOGI("component is not navigationContainer.");
114 return;
115 }
116
117 if (info[0]->IsString()) {
118 navigationContainer->GetDeclaration()->title = info[0]->ToString();
119 } else if (info[0]->IsObject()) {
120 auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
121 if (builderObject->IsFunction()) {
122 ScopedViewStackProcessor builderViewStackProcessor;
123 JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
124 ACE_SCORING_EVENT("Navigation.title.builder");
125 jsBuilderFunc.Execute();
126 auto customTile = ViewStackProcessor::GetInstance()->Finish();
127 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
128 auto composedComponent =
129 ViewStackProcessor::GetInstance()->CreateInspectorWrapper("NavigationTitle");
130 composedComponent->SetChild(customTile);
131 navigationContainer->GetDeclaration()->customTitle = composedComponent;
132 #else
133 navigationContainer->GetDeclaration()->customTitle = customTile;
134 #endif
135 }
136 } else {
137 LOGE("arg is not [String|Function].");
138 }
139 }
140
SetTitleMode(int32_t value)141 void JSNavigation::SetTitleMode(int32_t value)
142 {
143 if ((value == static_cast<int32_t>(NavigationTitleMode::FREE)) ||
144 (value == static_cast<int32_t>(NavigationTitleMode::FULL)) ||
145 (value == static_cast<int32_t>(NavigationTitleMode::MINI))) {
146 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
147 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
148 if (navigationContainer) {
149 navigationContainer->GetDeclaration()->titleMode = static_cast<NavigationTitleMode>(value);
150 }
151 } else {
152 LOGE("invalid value for titleMode");
153 }
154 }
155
SetSubTitle(const std::string & subTitle)156 void JSNavigation::SetSubTitle(const std::string& subTitle)
157 {
158 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
159 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
160 if (navigationContainer) {
161 navigationContainer->GetDeclaration()->subTitle = subTitle;
162 }
163 }
164
SetHideTitleBar(bool hide)165 void JSNavigation::SetHideTitleBar(bool hide)
166 {
167 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
168 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
169 if (navigationContainer) {
170 auto declaration = navigationContainer->GetDeclaration();
171 declaration->hideBar = hide;
172 declaration->animationOption = ViewStackProcessor::GetInstance()->GetImplicitAnimationOption();
173 }
174 }
175
SetHideBackButton(bool hide)176 void JSNavigation::SetHideBackButton(bool hide)
177 {
178 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
179 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
180 if (navigationContainer) {
181 navigationContainer->GetDeclaration()->hideBarBackButton = hide;
182 }
183 }
184
SetHideToolBar(bool hide)185 void JSNavigation::SetHideToolBar(bool hide)
186 {
187 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
188 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
189 if (navigationContainer) {
190 auto declaration = navigationContainer->GetDeclaration();
191 declaration->hideToolbar = hide;
192 declaration->animationOption = ViewStackProcessor::GetInstance()->GetImplicitAnimationOption();
193 }
194 }
195
SetToolBar(const JSCallbackInfo & info)196 void JSNavigation::SetToolBar(const JSCallbackInfo& info)
197 {
198 if (info.Length() < 1) {
199 LOGE("The arg is wrong, it is supposed to have at least one argument");
200 return;
201 }
202 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
203 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
204 if (!navigationContainer) {
205 LOGI("component is not navigationContainer.");
206 return;
207 }
208
209 if (!info[0]->IsObject()) {
210 LOGE("arg is not a object.");
211 return;
212 }
213 auto builderFuncParam = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
214 if (builderFuncParam->IsFunction()) {
215 ScopedViewStackProcessor builderViewStackProcessor;
216 JsFunction jsBuilderFunc(builderFuncParam);
217 jsBuilderFunc.Execute();
218 RefPtr<Component> builderGeneratedRootComponent = ViewStackProcessor::GetInstance()->Finish();
219 navigationContainer->GetDeclaration()->toolBarBuilder = builderGeneratedRootComponent;
220 return;
221 }
222
223 auto itemsValue = JSRef<JSObject>::Cast(info[0])->GetProperty("items");
224 if (!itemsValue->IsObject() || !itemsValue->IsArray()) {
225 LOGE("arg format error: not find items");
226 return;
227 }
228 ParseToolBarItems(JSRef<JSArray>::Cast(itemsValue), navigationContainer->GetDeclaration()->toolbarItems);
229 }
230
SetMenus(const JSCallbackInfo & info)231 void JSNavigation::SetMenus(const JSCallbackInfo& info)
232 {
233 if (info.Length() < 1) {
234 LOGE("The arg is wrong, it is supposed to have at least one argument");
235 return;
236 }
237 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
238 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
239 if (!navigationContainer) {
240 LOGI("component is not navigationContainer.");
241 return;
242 }
243
244 if (info[0]->IsArray()) {
245 ParseToolBarItems(JSRef<JSArray>::Cast(info[0]), navigationContainer->GetDeclaration()->menuItems);
246 } else if (info[0]->IsObject()) {
247 auto builderObject = JSRef<JSObject>::Cast(info[0])->GetProperty("builder");
248 if (builderObject->IsFunction()) {
249 ScopedViewStackProcessor builderViewStackProcessor;
250 JsFunction jsBuilderFunc(info.This(), JSRef<JSObject>::Cast(builderObject));
251 {
252 ACE_SCORING_EVENT("Navigation.menu.builder");
253 jsBuilderFunc.Execute();
254 }
255 auto customMenus = ViewStackProcessor::GetInstance()->Finish();
256 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
257 auto composedComponent = ViewStackProcessor::GetInstance()->CreateInspectorWrapper("NavigationMenus");
258 composedComponent->SetChild(customMenus);
259 navigationContainer->GetDeclaration()->customMenus = composedComponent;
260 #else
261 navigationContainer->GetDeclaration()->customMenus = customMenus;
262 #endif
263 }
264 } else {
265 LOGE("arg is not [String|Function].");
266 }
267 }
268
SetMenuCount(int32_t menuCount)269 void JSNavigation::SetMenuCount(int32_t menuCount)
270 {
271 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
272 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
273 if (navigationContainer) {
274 navigationContainer->SetMenuCount(menuCount);
275 }
276 }
277
SetOnTitleModeChanged(const JSCallbackInfo & info)278 void JSNavigation::SetOnTitleModeChanged(const JSCallbackInfo& info)
279 {
280 if (info.Length() < 1) {
281 LOGE("The arg is wrong, it is supposed to have at least one argument");
282 return;
283 }
284 if (info[0]->IsFunction()) {
285 auto changeHandler = AceType::MakeRefPtr<JsEventFunction<NavigationTitleModeChangeEvent, 1>>(
286 JSRef<JSFunc>::Cast(info[0]), TitleModeChangeEventToJSValue);
287 auto eventMarker = EventMarker([executionContext = info.GetExecutionContext(), func = std::move(changeHandler)](
288 const BaseEventInfo* baseInfo) {
289 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
290 auto eventInfo = TypeInfoHelper::DynamicCast<NavigationTitleModeChangeEvent>(baseInfo);
291 if (!eventInfo) {
292 LOGE("HandleChangeEvent eventInfo == nullptr");
293 return;
294 }
295 ACE_SCORING_EVENT("Navigation.onTitleModeChanged");
296 func->Execute(*eventInfo);
297 });
298 auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
299 auto navigationContainer = AceType::DynamicCast<OHOS::Ace::NavigationContainerComponent>(component);
300 if (navigationContainer) {
301 navigationContainer->GetDeclaration()->titleModeChangedEvent = eventMarker;
302 }
303 }
304 info.ReturnSelf();
305 }
306
307 } // namespace OHOS::Ace::Framework
308