• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_menu_item.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/jsview/models/menu_item_model_impl.h"
20 #include "core/components_ng/base/view_stack_model.h"
21 #include "core/components_ng/pattern/menu/menu_item/menu_item_model.h"
22 #include "core/components_ng/pattern/menu/menu_item/menu_item_model_ng.h"
23 
24 namespace OHOS::Ace {
25 std::unique_ptr<MenuItemModel> MenuItemModel::instance_ = nullptr;
26 std::mutex MenuItemModel::mutex_;
27 
GetInstance()28 MenuItemModel* MenuItemModel::GetInstance()
29 {
30     if (!instance_) {
31         std::lock_guard<std::mutex> lock(mutex_);
32         if (!instance_) {
33 #ifdef NG_BUILD
34             instance_.reset(new NG::MenuItemModelNG());
35 #else
36             if (Container::IsCurrentUseNewPipeline()) {
37                 instance_.reset(new NG::MenuItemModelNG());
38             } else {
39                 instance_.reset(new Framework::MenuItemModelImpl());
40             }
41 #endif
42         }
43     }
44     return instance_.get();
45 }
46 } // namespace OHOS::Ace
47 
48 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)49 void JSMenuItem::Create(const JSCallbackInfo& info)
50 {
51     if (info.Length() < 1 || (!info[0]->IsObject() && !info[0]->IsFunction())) {
52         LOGW("JSMenuItem The arg is wrong");
53         return;
54     }
55     // custom menu item
56     if (info[0]->IsFunction()) {
57         auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
58         CHECK_NULL_VOID(builderFunc);
59         RefPtr<NG::UINode> customNode;
60         {
61             ViewStackModel::GetInstance()->NewScope();
62             builderFunc->Execute();
63             customNode = AceType::DynamicCast<NG::UINode>(ViewStackModel::GetInstance()->Finish());
64         }
65         CHECK_NULL_VOID(customNode);
66         MenuItemModel::GetInstance()->Create(customNode);
67     } else {
68         auto menuItemObj = JSRef<JSObject>::Cast(info[0]);
69 
70         std::string startIconPath;
71         std::string contentStr;
72         std::string endIconPath;
73         std::string labelStr;
74         MenuItemProperties menuItemProps;
75 
76         auto startIcon = menuItemObj->GetProperty("startIcon");
77         auto content = menuItemObj->GetProperty("content");
78         auto endIcon = menuItemObj->GetProperty("endIcon");
79         auto label = menuItemObj->GetProperty("labelInfo");
80 
81         if (ParseJsMedia(startIcon, startIconPath)) {
82             menuItemProps.startIcon = startIconPath;
83         } else {
84             LOGI("startIcon is null");
85         }
86 
87         if (!ParseJsString(content, contentStr)) {
88             LOGI("content is null");
89         }
90         menuItemProps.content = contentStr;
91 
92         if (ParseJsMedia(endIcon, endIconPath)) {
93             menuItemProps.endIcon = endIconPath;
94         } else {
95             LOGI("endIcon is null");
96         }
97 
98         if (ParseJsString(label, labelStr)) {
99             menuItemProps.labelInfo = labelStr;
100         } else {
101             LOGI("labelInfo is null");
102         }
103 
104         auto builder = menuItemObj->GetProperty("builder");
105         if (!builder.IsEmpty() && builder->IsFunction()) {
106             auto subBuilderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
107             CHECK_NULL_VOID(subBuilderFunc);
108             auto subBuildFunc = [execCtx = info.GetExecutionContext(), func = std::move(subBuilderFunc)]() {
109                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
110                 ACE_SCORING_EVENT("MenuItem SubBuilder");
111                 func->ExecuteJS();
112             };
113             menuItemProps.buildFunc = std::move(subBuildFunc);
114         }
115         MenuItemModel::GetInstance()->Create(menuItemProps);
116     }
117 }
118 
JSBind(BindingTarget globalObj)119 void JSMenuItem::JSBind(BindingTarget globalObj)
120 {
121     JSClass<JSMenuItem>::Declare("MenuItem");
122     MethodOptions opt = MethodOptions::NONE;
123     JSClass<JSMenuItem>::StaticMethod("create", &JSMenuItem::Create, opt);
124 
125     JSClass<JSMenuItem>::StaticMethod("selected", &JSMenuItem::IsSelected, opt);
126     JSClass<JSMenuItem>::StaticMethod("selectIcon", &JSMenuItem::SelectIcon, opt);
127     JSClass<JSMenuItem>::StaticMethod("onChange", &JSMenuItem::OnChange, opt);
128     JSClass<JSMenuItem>::StaticMethod("contentFont", &JSMenuItem::ContentFont, opt);
129     JSClass<JSMenuItem>::StaticMethod("contentFontColor", &JSMenuItem::ContentFontColor, opt);
130     JSClass<JSMenuItem>::StaticMethod("labelFont", &JSMenuItem::LabelFont, opt);
131     JSClass<JSMenuItem>::StaticMethod("labelFontColor", &JSMenuItem::LabelFontColor, opt);
132     JSClass<JSMenuItem>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
133     JSClass<JSMenuItem>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
134     JSClass<JSMenuItem>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
135     JSClass<JSMenuItem>::InheritAndBind<JSViewAbstract>(globalObj);
136 }
137 
ParseIsSelectedObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)138 void ParseIsSelectedObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
139 {
140     CHECK_NULL_VOID(changeEventVal->IsFunction());
141 
142     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
143     auto onSelected = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool selected) {
144         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
145         ACE_SCORING_EVENT("MenuItem.SelectedChangeEvent");
146         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(selected));
147         func->ExecuteJS(1, &newJSVal);
148     };
149     MenuItemModel::GetInstance()->SetSelectedChangeEvent(std::move(onSelected));
150 }
151 
IsSelected(const JSCallbackInfo & info)152 void JSMenuItem::IsSelected(const JSCallbackInfo& info)
153 {
154     if (info.Length() < 1 || info.Length() > 2) {
155         LOGE("The arg is wrong, it is supposed to have 1 or 2 arguments");
156         return;
157     }
158 
159     bool isSelected = false;
160     if (info.Length() > 0 && info[0]->IsBoolean()) {
161         isSelected = info[0]->ToBoolean();
162     }
163     MenuItemModel::GetInstance()->SetSelected(isSelected);
164     if (info.Length() > 1 && info[1]->IsFunction()) {
165         ParseIsSelectedObject(info, info[1]);
166     }
167 }
168 
SelectIcon(const JSCallbackInfo & info)169 void JSMenuItem::SelectIcon(const JSCallbackInfo& info)
170 {
171     bool isShow = false;
172     std::string icon;
173     if (info.Length() < 1) {
174         LOGW("The arg is wrong, it is supposed to have at least 1 arguments");
175     } else {
176         if (info[0]->IsBoolean()) {
177             isShow = info[0]->ToBoolean();
178         } else if (info[0]->IsString()) {
179             icon = info[0]->ToString();
180             isShow = true;
181         } else if (ParseJsMedia(info[0], icon)) {
182             isShow = true;
183         } else {
184             LOGW("can not parse select icon.");
185         }
186     }
187     MenuItemModel::GetInstance()->SetSelectIcon(isShow);
188     MenuItemModel::GetInstance()->SetSelectIconSrc(icon);
189 }
190 
OnChange(const JSCallbackInfo & info)191 void JSMenuItem::OnChange(const JSCallbackInfo& info)
192 {
193     if (info.Length() < 1 || !info[0]->IsFunction()) {
194         LOGE("The arg is wrong, it is supposed to have atleast 1 argument.");
195         return;
196     }
197     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
198     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool selected) {
199         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
200         ACE_SCORING_EVENT("MenuItem.onChange");
201         JSRef<JSVal> params[1];
202         params[0] = JSRef<JSVal>::Make(ToJSValue(selected));
203         func->ExecuteJS(1, params);
204     };
205     MenuItemModel::GetInstance()->SetOnChange(std::move(onChange));
206     info.ReturnSelf();
207 }
208 
ContentFont(const JSCallbackInfo & info)209 void JSMenuItem::ContentFont(const JSCallbackInfo& info)
210 {
211     CalcDimension fontSize;
212     std::string weight;
213     if (info.Length() < 1 || !info[0]->IsObject()) {
214         LOGW("The argv is wrong, it is supposed to have at least 1 object argument");
215     } else {
216         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
217         JSRef<JSVal> size = obj->GetProperty("size");
218         if (!size->IsNull()) {
219             ParseJsDimensionFp(size, fontSize);
220             if (fontSize.Unit() == DimensionUnit::PERCENT) {
221                 // set zero for abnormal value
222                 fontSize = CalcDimension();
223             }
224         }
225 
226         auto jsWeight = obj->GetProperty("weight");
227         if (!jsWeight->IsNull()) {
228             if (jsWeight->IsNumber()) {
229                 weight = std::to_string(jsWeight->ToNumber<int32_t>());
230             } else {
231                 ParseJsString(jsWeight, weight);
232             }
233         }
234 
235         auto jsStyle = obj->GetProperty("style");
236         if (!jsStyle->IsNull()) {
237             if (jsStyle->IsNumber()) {
238                 MenuItemModel::GetInstance()->SetFontStyle(static_cast<FontStyle>(jsStyle->ToNumber<int32_t>()));
239             } else {
240                 std::string style;
241                 ParseJsString(jsStyle, style);
242                 MenuItemModel::GetInstance()->SetFontStyle(ConvertStrToFontStyle(style));
243             }
244         }
245 
246         auto jsFamily = obj->GetProperty("family");
247         if (!jsFamily->IsNull() && jsFamily->IsString()) {
248             auto familyVal = jsFamily->ToString();
249             auto fontFamilies = ConvertStrToFontFamilies(familyVal);
250             MenuItemModel::GetInstance()->SetFontFamily(fontFamilies);
251         }
252     }
253     MenuItemModel::GetInstance()->SetFontSize(fontSize);
254     MenuItemModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(weight));
255 }
256 
ContentFontColor(const JSCallbackInfo & info)257 void JSMenuItem::ContentFontColor(const JSCallbackInfo& info)
258 {
259     std::optional<Color> color = std::nullopt;
260     if (info.Length() < 1) {
261         LOGW("The argv is wrong, it is supposed to have at least 1 argument");
262     } else {
263         Color textColor;
264         if (ParseJsColor(info[0], textColor)) {
265             color = textColor;
266         }
267     }
268     MenuItemModel::GetInstance()->SetFontColor(color);
269 }
270 
LabelFont(const JSCallbackInfo & info)271 void JSMenuItem::LabelFont(const JSCallbackInfo& info)
272 {
273     CalcDimension fontSize;
274     std::string weight;
275     if (info.Length() < 1 || !info[0]->IsObject()) {
276         LOGW("The argv is wrong, it is supposed to have at least 1 object argument");
277     } else {
278         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
279         JSRef<JSVal> size = obj->GetProperty("size");
280         if (!size->IsNull()) {
281             ParseJsDimensionFp(size, fontSize);
282             if (fontSize.Unit() == DimensionUnit::PERCENT) {
283                 // set zero for abnormal value
284                 fontSize = CalcDimension();
285             }
286         }
287 
288         auto jsWeight = obj->GetProperty("weight");
289         if (!jsWeight->IsNull()) {
290             if (jsWeight->IsNumber()) {
291                 weight = std::to_string(jsWeight->ToNumber<int32_t>());
292             } else {
293                 ParseJsString(jsWeight, weight);
294             }
295         }
296 
297         auto jsStyle = obj->GetProperty("style");
298         if (!jsStyle->IsNull()) {
299             if (jsStyle->IsNumber()) {
300                 MenuItemModel::GetInstance()->SetLabelFontStyle(static_cast<FontStyle>(jsStyle->ToNumber<int32_t>()));
301             } else {
302                 std::string style;
303                 ParseJsString(jsStyle, style);
304                 MenuItemModel::GetInstance()->SetLabelFontStyle(ConvertStrToFontStyle(style));
305             }
306         }
307 
308         auto jsFamily = obj->GetProperty("family");
309         if (!jsFamily->IsNull() && jsFamily->IsString()) {
310             auto familyVal = jsFamily->ToString();
311             auto fontFamilies = ConvertStrToFontFamilies(familyVal);
312             MenuItemModel::GetInstance()->SetLabelFontFamily(fontFamilies);
313         }
314     }
315     MenuItemModel::GetInstance()->SetLabelFontSize(fontSize);
316     MenuItemModel::GetInstance()->SetLabelFontWeight(ConvertStrToFontWeight(weight));
317 }
318 
LabelFontColor(const JSCallbackInfo & info)319 void JSMenuItem::LabelFontColor(const JSCallbackInfo& info)
320 {
321     std::optional<Color> color = std::nullopt;
322     if (info.Length() < 1) {
323         LOGW("The argv is wrong, it is supposed to have at least 1 argument");
324     } else {
325         Color textColor;
326         if (ParseJsColor(info[0], textColor)) {
327             color = textColor;
328         }
329     }
330     MenuItemModel::GetInstance()->SetLabelFontColor(color);
331 }
332 } // namespace OHOS::Ace::Framework
333