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
16 #include "frameworks/bridge/declarative_frontend/jsview/dialog/js_alert_dialog.h"
17
18 #include <sstream>
19 #include <string>
20 #include <vector>
21
22 #include "base/log/ace_scoring_log.h"
23 #include "core/common/container.h"
24 #include "core/components/dialog/dialog_component.h"
25 #include "core/components_ng/event/click_event.h"
26 #include "core/components_ng/pattern/dialog/dialog_event_hub.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 #include "frameworks/bridge/common/utils/engine_helper.h"
29 #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h"
30 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
31
32 namespace OHOS::Ace::Framework {
33 namespace {
34 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
35 DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
36 DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
37 DialogAlignment::BOTTOM_END };
38 } // namespace
39
ParseButtonObj(const JSCallbackInfo & args,DialogProperties & properties,JSRef<JSObject> obj,const std::string & property)40 void ParseButtonObj(
41 const JSCallbackInfo& args, DialogProperties& properties, JSRef<JSObject> obj, const std::string& property)
42 {
43 auto jsVal = obj->GetProperty(property.c_str());
44 if (!jsVal->IsObject()) {
45 return;
46 }
47 auto objInner = JSRef<JSObject>::Cast(jsVal);
48 auto value = objInner->GetProperty("value");
49 std::string buttonValue;
50 ButtonInfo buttonInfo;
51 if (JSAlertDialog::ParseJsString(value, buttonValue)) {
52 buttonInfo.text = buttonValue;
53 }
54
55 auto fontColorValue = objInner->GetProperty("fontColor");
56 Color textColor;
57 if (JSAlertDialog::ParseJsColor(fontColorValue, textColor)) {
58 buttonInfo.textColor = textColor.ColorToString();
59 }
60
61 auto backgroundColorValue = objInner->GetProperty("backgroundColor");
62 Color backgroundColor;
63 if (JSAlertDialog::ParseJsColor(backgroundColorValue, backgroundColor)) {
64 buttonInfo.isBgColorSetted = true;
65 buttonInfo.bgColor = backgroundColor;
66 }
67
68 auto actionValue = objInner->GetProperty("action");
69 if (actionValue->IsFunction()) {
70 auto actionFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(actionValue));
71 // NG
72 if (Container::IsCurrentUseNewPipeline()) {
73 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(actionFunc), property](
74 GestureEvent& /*info*/) {
75 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
76 ACE_SCORING_EVENT("AlertDialog.[" + property + "].onAction");
77 func->ExecuteJS();
78 };
79 buttonInfo.action = AceType::MakeRefPtr<NG::ClickEvent>(std::move(callback));
80 } else {
81 EventMarker actionId([execCtx = args.GetExecutionContext(), func = std::move(actionFunc), property]() {
82 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
83 ACE_SCORING_EVENT("AlertDialog.[" + property + "].onAction");
84 func->Execute();
85 });
86
87 if (property == "confirm" || property == "primaryButton") {
88 properties.primaryId = actionId;
89 } else if (property == "secondaryButton") {
90 properties.secondaryId = actionId;
91 }
92 }
93 }
94
95 if (buttonInfo.IsValid()) {
96 properties.buttons.emplace_back(buttonInfo);
97 }
98 }
99
Show(const JSCallbackInfo & args)100 void JSAlertDialog::Show(const JSCallbackInfo& args)
101 {
102 auto scopedDelegate = EngineHelper::GetCurrentDelegate();
103 if (!scopedDelegate) {
104 // this case usually means there is no foreground container, need to figure out the reason.
105 LOGE("scopedDelegate is null, please check");
106 return;
107 }
108
109 DialogProperties properties { .type = DialogType::ALERT_DIALOG };
110 if (args[0]->IsObject()) {
111 auto obj = JSRef<JSObject>::Cast(args[0]);
112
113 // Parse title.
114 auto titleValue = obj->GetProperty("title");
115 std::string title;
116 if (ParseJsString(titleValue, title)) {
117 properties.title = title;
118 }
119
120 // Parses message.
121 auto messageValue = obj->GetProperty("message");
122 std::string message;
123 if (ParseJsString(messageValue, message)) {
124 properties.content = message;
125 }
126
127 // Parses gridCount.
128 auto gridCountValue = obj->GetProperty("gridCount");
129 if (gridCountValue->IsNumber()) {
130 properties.gridCount = gridCountValue->ToNumber<int32_t>();
131 }
132
133 // Parse auto autoCancel.
134 auto autoCancelValue = obj->GetProperty("autoCancel");
135 if (autoCancelValue->IsBoolean()) {
136 properties.autoCancel = autoCancelValue->ToBoolean();
137 }
138
139 // Parse cancel.
140 auto cancelValue = obj->GetProperty("cancel");
141 if (cancelValue->IsFunction()) {
142 auto cancelFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(cancelValue));
143 // NG set onCancel
144 if (Container::IsCurrentUseNewPipeline()) {
145 properties.onCancel = [execCtx = args.GetExecutionContext(), func = std::move(cancelFunc)] {
146 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
147 ACE_SCORING_EVENT("AlertDialog.property.cancel");
148 LOGD("dialog onCancel triggered");
149 func->ExecuteJS();
150 };
151 } else {
152 EventMarker cancelId([execCtx = args.GetExecutionContext(), func = std::move(cancelFunc)]() {
153 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
154 ACE_SCORING_EVENT("AlertDialog.property.cancel");
155 func->Execute();
156 });
157 properties.callbacks.try_emplace("cancel", cancelId);
158 }
159 }
160
161 if (obj->GetProperty("confirm")->IsObject()) {
162 // Parse confirm.
163 ParseButtonObj(args, properties, obj, "confirm");
164 } else {
165 // Parse primaryButton and secondaryButton.
166 ParseButtonObj(args, properties, obj, "primaryButton");
167 ParseButtonObj(args, properties, obj, "secondaryButton");
168 }
169
170 // Parse alignment
171 auto alignmentValue = obj->GetProperty("alignment");
172 if (alignmentValue->IsNumber()) {
173 auto alignment = alignmentValue->ToNumber<int32_t>();
174 if (alignment >= 0 && alignment <= static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
175 properties.alignment = DIALOG_ALIGNMENT[alignment];
176 }
177 }
178
179 // Parse offset
180 auto offsetValue = obj->GetProperty("offset");
181 if (offsetValue->IsObject()) {
182 auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
183 Dimension dx;
184 auto dxValue = offsetObj->GetProperty("dx");
185 ParseJsDimensionVp(dxValue, dx);
186 Dimension dy;
187 auto dyValue = offsetObj->GetProperty("dy");
188 ParseJsDimensionVp(dyValue, dy);
189 properties.offset = DimensionOffset(dx, dy);
190 }
191
192 if (Container::IsCurrentUseNewPipeline()) {
193 auto container = Container::Current();
194 CHECK_NULL_VOID(container);
195 auto pipelineContext = container->GetPipelineContext();
196 CHECK_NULL_VOID(pipelineContext);
197 auto context = AceType::DynamicCast<NG::PipelineContext>(pipelineContext);
198 CHECK_NULL_VOID(context);
199 auto overlayManager = context->GetOverlayManager();
200 CHECK_NULL_VOID(overlayManager);
201
202 auto dialog = overlayManager->ShowDialog(properties, nullptr, false);
203 CHECK_NULL_VOID(dialog);
204 auto hub = dialog->GetEventHub<NG::DialogEventHub>();
205 hub->SetOnCancel(std::move(properties.onCancel));
206 return;
207 }
208
209 // Show dialog.
210 auto container = Container::Current();
211 if (container) {
212 auto context = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
213 auto executor = container->GetTaskExecutor();
214 if (executor) {
215 executor->PostTask(
216 [context, properties]() {
217 if (context) {
218 context->ShowDialog(properties, false, "AlertDialog");
219 }
220 },
221 TaskExecutor::TaskType::UI);
222 }
223 }
224 args.SetReturnValue(args.This());
225 }
226 }
227
JSBind(BindingTarget globalObj)228 void JSAlertDialog::JSBind(BindingTarget globalObj)
229 {
230 JSClass<JSAlertDialog>::Declare("AlertDialog");
231 JSClass<JSAlertDialog>::StaticMethod("show", &JSAlertDialog::Show);
232
233 JSClass<JSAlertDialog>::Inherit<JSViewAbstract>();
234 JSClass<JSAlertDialog>::Bind<>(globalObj);
235 }
236
237 } // namespace OHOS::Ace::Framework
238