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