• 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 #include "frameworks/bridge/declarative_frontend/jsview/dialog/js_alert_dialog.h"
16 
17 #include <sstream>
18 #include <string>
19 #include <vector>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/models/alert_dialog_model_impl.h"
23 #include "core/common/container.h"
24 #include "core/components_ng/base/view_stack_processor.h"
25 #include "core/components_ng/pattern/dialog/alert_dialog_model_ng.h"
26 #include "frameworks/bridge/common/utils/engine_helper.h"
27 #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h"
28 
29 namespace OHOS::Ace {
30 std::unique_ptr<AlertDialogModel> AlertDialogModel::instance_ = nullptr;
31 std::mutex AlertDialogModel::mutex_;
GetInstance()32 AlertDialogModel* AlertDialogModel::GetInstance()
33 {
34     if (!instance_) {
35         std::lock_guard<std::mutex> lock(mutex_);
36         if (!instance_) {
37 #ifdef NG_BUILD
38             instance_.reset(new NG::AlertDialogModelNG());
39 #else
40             if (Container::IsCurrentUseNewPipeline()) {
41                 instance_.reset(new NG::AlertDialogModelNG());
42             } else {
43                 instance_.reset(new Framework::AlertDialogModelImpl());
44             }
45 #endif
46         }
47     }
48     return instance_.get();
49 }
50 
51 } // namespace OHOS::Ace
52 namespace OHOS::Ace::Framework {
53 namespace {
54 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
55     DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
56     DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
57     DialogAlignment::BOTTOM_END };
58 const std::vector<DialogButtonDirection> DIALOG_BUTTONS_DIRECTION = { DialogButtonDirection::AUTO,
59     DialogButtonDirection::HORIZONTAL, DialogButtonDirection::VERTICAL };
60 } // namespace
61 
SetParseStyle(ButtonInfo & buttonInfo,const int32_t styleValue)62 void SetParseStyle(ButtonInfo& buttonInfo, const int32_t styleValue)
63 {
64     if (styleValue >= static_cast<int32_t>(DialogButtonStyle::DEFAULT) &&
65         styleValue <= static_cast<int32_t>(DialogButtonStyle::HIGHTLIGHT)) {
66         buttonInfo.dlgButtonStyle = static_cast<DialogButtonStyle>(styleValue);
67     }
68 }
69 
ParseButtonObj(const JSCallbackInfo & args,DialogProperties & properties,JSRef<JSVal> jsVal,const std::string & property)70 void ParseButtonObj(
71     const JSCallbackInfo& args, DialogProperties& properties, JSRef<JSVal> jsVal, const std::string& property)
72 {
73     if (!jsVal->IsObject()) {
74         return;
75     }
76     auto objInner = JSRef<JSObject>::Cast(jsVal);
77     auto value = objInner->GetProperty("value");
78     std::string buttonValue;
79     ButtonInfo buttonInfo;
80     if (JSAlertDialog::ParseJsString(value, buttonValue)) {
81         buttonInfo.text = buttonValue;
82     }
83 
84     // Parse enabled
85     auto enabledValue = objInner->GetProperty("enabled");
86     if (enabledValue->IsBoolean()) {
87         buttonInfo.enabled = enabledValue->ToBoolean();
88     }
89 
90     // Parse defaultFocus
91     auto defaultFocusValue = objInner->GetProperty("defaultFocus");
92     if (defaultFocusValue->IsBoolean()) {
93         buttonInfo.defaultFocus = defaultFocusValue->ToBoolean();
94     }
95 
96     // Parse style
97     auto style = objInner->GetProperty("style");
98     if (style->IsNumber()) {
99         auto styleValue = style->ToNumber<int32_t>();
100         SetParseStyle(buttonInfo, styleValue);
101     }
102 
103     auto fontColorValue = objInner->GetProperty("fontColor");
104     Color textColor;
105     if (JSAlertDialog::ParseJsColor(fontColorValue, textColor)) {
106         buttonInfo.textColor = textColor.ColorToString();
107     }
108 
109     auto backgroundColorValue = objInner->GetProperty("backgroundColor");
110     Color backgroundColor;
111     if (JSAlertDialog::ParseJsColor(backgroundColorValue, backgroundColor)) {
112         buttonInfo.isBgColorSetted = true;
113         buttonInfo.bgColor = backgroundColor;
114     }
115 
116     auto actionValue = objInner->GetProperty("action");
117     if (actionValue->IsFunction()) {
118         WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
119         auto actionFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(actionValue));
120         auto eventFunc = [execCtx = args.GetExecutionContext(), func = std::move(actionFunc), property,
121                             node = frameNode]() {
122             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
123             ACE_SCORING_EVENT("AlertDialog.[" + property + "].onAction");
124             auto pipelineContext = PipelineContext::GetCurrentContextSafely();
125             CHECK_NULL_VOID(pipelineContext);
126             pipelineContext->UpdateCurrentActiveNode(node);
127             func->Execute();
128         };
129         AlertDialogModel::GetInstance()->SetParseButtonObj(eventFunc, buttonInfo, properties, property);
130     }
131 
132     if (buttonInfo.IsValid()) {
133         properties.buttons.emplace_back(buttonInfo);
134     }
135 }
136 
ParseButtonArray(const JSCallbackInfo & args,DialogProperties & properties,JSRef<JSObject> obj,const std::string & property)137 void ParseButtonArray(
138     const JSCallbackInfo& args, DialogProperties& properties, JSRef<JSObject> obj, const std::string& property)
139 {
140     auto jsVal = obj->GetProperty(property.c_str());
141     if (!jsVal->IsArray()) {
142         return;
143     }
144     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsVal);
145     size_t length = array->Length();
146     if (length <= 0) {
147         return;
148     }
149     for (size_t i = 0; i < length; i++) {
150         JSRef<JSVal> buttonItem = array->GetValueAt(i);
151         if (!buttonItem->IsObject()) {
152             break;
153         }
154         ParseButtonObj(args, properties, buttonItem, property + std::to_string(i));
155     }
156 }
157 
Show(const JSCallbackInfo & args)158 void JSAlertDialog::Show(const JSCallbackInfo& args)
159 {
160     auto scopedDelegate = EngineHelper::GetCurrentDelegateSafely();
161     if (!scopedDelegate) {
162         // this case usually means there is no foreground container, need to figure out the reason.
163         LOGE("scopedDelegate is null, please check");
164         return;
165     }
166 
167     DialogProperties properties { .type = DialogType::ALERT_DIALOG };
168     if (args[0]->IsObject()) {
169         auto obj = JSRef<JSObject>::Cast(args[0]);
170 
171         // Parse title.
172         auto titleValue = obj->GetProperty("title");
173         std::string title;
174         if (ParseJsString(titleValue, title)) {
175             properties.title = title;
176         }
177 
178         // Parse subtitle.
179         auto subtitleValue = obj->GetProperty("subtitle");
180         std::string subtitle;
181         if (ParseJsString(subtitleValue, subtitle)) {
182             properties.subtitle = subtitle;
183         }
184 
185         // Parses message.
186         auto messageValue = obj->GetProperty("message");
187         std::string message;
188         if (ParseJsString(messageValue, message)) {
189             properties.content = message;
190         }
191 
192         // Parses gridCount.
193         auto gridCountValue = obj->GetProperty("gridCount");
194         if (gridCountValue->IsNumber()) {
195             properties.gridCount = gridCountValue->ToNumber<int32_t>();
196         }
197 
198         // Parse auto autoCancel.
199         auto autoCancelValue = obj->GetProperty("autoCancel");
200         if (autoCancelValue->IsBoolean()) {
201             properties.autoCancel = autoCancelValue->ToBoolean();
202         }
203 
204         // Parse cancel.
205         auto cancelValue = obj->GetProperty("cancel");
206         if (cancelValue->IsFunction()) {
207             WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
208             auto cancelFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(cancelValue));
209             auto eventFunc = [execCtx = args.GetExecutionContext(), func = std::move(cancelFunc), node = frameNode]() {
210                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
211                 ACE_SCORING_EVENT("AlertDialog.property.cancel");
212                 auto pipelineContext = PipelineContext::GetCurrentContextSafely();
213                 CHECK_NULL_VOID(pipelineContext);
214                 pipelineContext->UpdateCurrentActiveNode(node);
215                 func->Execute();
216             };
217             AlertDialogModel::GetInstance()->SetOnCancel(eventFunc, properties);
218         }
219 
220         if (obj->GetProperty("confirm")->IsObject()) {
221             // Parse confirm.
222             auto objInner = obj->GetProperty("confirm");
223             ParseButtonObj(args, properties, objInner, "confirm");
224         } else if (obj->GetProperty("buttons")->IsArray()) {
225             // Parse buttons array.
226             ParseButtonArray(args, properties, obj, "buttons");
227         } else {
228             // Parse primaryButton and secondaryButton.
229             auto objInner = obj->GetProperty("primaryButton");
230             ParseButtonObj(args, properties, objInner, "primaryButton");
231             objInner = obj->GetProperty("secondaryButton");
232             ParseButtonObj(args, properties, objInner, "secondaryButton");
233         }
234 
235         // Parse buttons direction.
236         auto directionValue = obj->GetProperty("buttonDirection");
237         if (directionValue->IsNumber()) {
238             auto buttonDirection = directionValue->ToNumber<int32_t>();
239             if (buttonDirection >= 0 && buttonDirection <= static_cast<int32_t>(DIALOG_BUTTONS_DIRECTION.size())) {
240                 properties.buttonDirection = DIALOG_BUTTONS_DIRECTION[buttonDirection];
241             }
242         }
243 
244         // Parse alignment
245         auto alignmentValue = obj->GetProperty("alignment");
246         if (alignmentValue->IsNumber()) {
247             auto alignment = alignmentValue->ToNumber<int32_t>();
248             if (alignment >= 0 && alignment <= static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
249                 properties.alignment = DIALOG_ALIGNMENT[alignment];
250             }
251         }
252 
253         // Parse offset
254         auto offsetValue = obj->GetProperty("offset");
255         if (offsetValue->IsObject()) {
256             auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
257             CalcDimension dx;
258             auto dxValue = offsetObj->GetProperty("dx");
259             ParseJsDimensionVp(dxValue, dx);
260             CalcDimension dy;
261             auto dyValue = offsetObj->GetProperty("dy");
262             ParseJsDimensionVp(dyValue, dy);
263             properties.offset = DimensionOffset(dx, dy);
264         }
265 
266         // Parse maskRect.
267         auto maskRectValue = obj->GetProperty("maskRect");
268         DimensionRect maskRect;
269         if (JSViewAbstract::ParseJsDimensionRect(maskRectValue, maskRect)) {
270             properties.maskRect = maskRect;
271         }
272 
273         // Parse showInSubWindowValue.
274         auto showInSubWindowValue = obj->GetProperty("showInSubWindow");
275         if (showInSubWindowValue->IsBoolean()) {
276             LOGI("Parse showInSubWindowValue");
277             properties.isShowInSubWindow = showInSubWindowValue->ToBoolean();
278         }
279 
280         // Parse isModal.
281         auto isModalValue = obj->GetProperty("isModal");
282         if (isModalValue->IsBoolean()) {
283             LOGI("Parse isModalValue");
284             properties.isModal = isModalValue->ToBoolean();
285         }
286 
287         auto backgroundColorValue = obj->GetProperty("backgroundColor");
288         Color backgroundColor;
289         if (JSViewAbstract::ParseJsColor(backgroundColorValue, backgroundColor)) {
290             properties.backgroundColor = backgroundColor;
291         }
292 
293         auto backgroundBlurStyle = obj->GetProperty("backgroundBlurStyle");
294         BlurStyleOption styleOption;
295         if (backgroundBlurStyle->IsNumber()) {
296             auto blurStyle = backgroundBlurStyle->ToNumber<int32_t>();
297             if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
298                 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
299                 properties.backgroundBlurStyle = blurStyle;
300             }
301         }
302         AlertDialogModel::GetInstance()->SetShowDialog(properties);
303     }
304 }
305 
JSBind(BindingTarget globalObj)306 void JSAlertDialog::JSBind(BindingTarget globalObj)
307 {
308     JSClass<JSAlertDialog>::Declare("AlertDialog");
309     JSClass<JSAlertDialog>::StaticMethod("show", &JSAlertDialog::Show);
310 
311     JSClass<JSAlertDialog>::InheritAndBind<JSViewAbstract>(globalObj);
312 }
313 
314 } // namespace OHOS::Ace::Framework
315