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/common/dom/dom_popup.h"
17
18 #include <string>
19
20 #include "base/utils/linear_map.h"
21 #include "base/utils/utils.h"
22 #include "core/components/box/box_component.h"
23 #include "core/components/common/properties/color.h"
24 #include "core/components/focus_collaboration/focus_collaboration_component.h"
25 #include "core/components/popup/popup_theme.h"
26 #include "core/components/theme/theme_manager.h"
27 #include "frameworks/bridge/common/utils/utils.h"
28
29 namespace OHOS::Ace::Framework {
30 namespace {
31
32 constexpr uint32_t MASK_COLOR_ALPHA = 0x4c000000; // UX standand, 30% opacity
33
34 } // namespace
35
DOMPopup(NodeId nodeId,const std::string & nodeName)36 DOMPopup::DOMPopup(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
37 {
38 popupChild_ = AceType::MakeRefPtr<PopupComponent>(std::to_string(nodeId), nodeName);
39 }
40
~DOMPopup()41 DOMPopup::~DOMPopup()
42 {
43 RemoveMarker();
44 }
45
InitializeStyle()46 void DOMPopup::InitializeStyle()
47 {
48 RefPtr<PopupTheme> theme = GetTheme<PopupTheme>();
49 if (!theme) {
50 return;
51 }
52 maskColor_ = theme->GetMaskColor();
53 popupChild_->GetPopupParam()->SetMaskColor(maskColor_);
54 backgroundColor_ = theme->GetBackgroundColor();
55 popupChild_->GetPopupParam()->SetBackgroundColor(backgroundColor_);
56
57 if (!declaration_) {
58 return;
59 }
60 auto& borderStyle = declaration_->MaybeResetStyle<CommonBorderStyle>(StyleTag::COMMON_BORDER_STYLE);
61 if (borderStyle.IsValid()) {
62 borderStyle.border.SetBorderRadius(theme->GetRadius());
63 }
64
65 auto& paddingStyle = declaration_->MaybeResetStyle<CommonPaddingStyle>(StyleTag::COMMON_PADDING_STYLE);
66 if (paddingStyle.IsValid()) {
67 paddingStyle.padding = theme->GetPadding();
68 }
69 declaration_->SetHasBoxStyle(true);
70 declaration_->SetHasDecorationStyle(true);
71 }
72
RemoveMarker()73 void DOMPopup::RemoveMarker()
74 {
75 BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(clickMarker_);
76 }
77
ResetInitializedStyle()78 void DOMPopup::ResetInitializedStyle()
79 {
80 InitializeStyle();
81 }
82
OnChildNodeRemoved(const RefPtr<DOMNode> & child)83 void DOMPopup::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
84 {
85 popupChild_->SetChild(nullptr);
86 }
87
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)88 bool DOMPopup::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
89 {
90 // static linear map must be sorted by key.
91 static const LinearMapNode<Placement> placeMap[] = {
92 { "bottom", Placement::BOTTOM },
93 { "bottomLeft", Placement::BOTTOM_LEFT },
94 { "bottomRight", Placement::BOTTOM_RIGHT },
95 { "left", Placement::LEFT },
96 { "right", Placement::RIGHT },
97 { "top", Placement::TOP },
98 { "topLeft", Placement::TOP_LEFT },
99 { "topRight", Placement::TOP_RIGHT },
100 };
101 if (attr.first == DOM_PLACEMENT) {
102 auto valueIt = BinarySearchFindIndex(placeMap, ArraySize(placeMap), attr.second.c_str());
103 if (valueIt != -1) {
104 popupChild_->GetPopupParam()->SetPlacement(placeMap[valueIt].value);
105 }
106 return true;
107 } else if (attr.first == DOM_ARROW_OFFSET) {
108 popupChild_->GetPopupParam()->SetArrowOffset(ParseDimension(attr.second));
109 return true;
110 } else if (attr.first == DOM_CLICKABLE) {
111 clickable_ = StringToBool(attr.second);
112 return true;
113 } else if (attr.first == DOM_KEEP_ALIVE) {
114 popupChild_->GetPopupParam()->SetHasAction(StringToBool(attr.second));
115 return true;
116 }
117 return false;
118 }
119
SetSpecializedStyle(const std::pair<std::string,std::string> & style)120 bool DOMPopup::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
121 {
122 if (style.first == DOM_BACKGROUND_COLOR || style.first == DOM_BACKGROUND || style.first == DOM_BACKGROUND_IMAGE) {
123 hasBackground_ = true;
124 }
125
126 // popup don't support position
127 if (style.first == DOM_POSITION || style.first == DOM_POSITION_LEFT || style.first == DOM_POSITION_RIGHT ||
128 style.first == DOM_POSITION_TOP || style.first == DOM_POSITION_BOTTOM) {
129 return true;
130 }
131
132 if (style.first == DOM_MASK_COLOR) {
133 maskColor_ = ParseColor(style.second, MASK_COLOR_ALPHA);
134 popupChild_->GetPopupParam()->SetMaskColor(maskColor_);
135 return true;
136 } else if (style.first == DOM_BACKGROUND_COLOR) {
137 backgroundColor_ = ParseColor(style.second);
138 popupChild_->GetPopupParam()->SetBackgroundColor(backgroundColor_);
139 return false;
140 } else {
141 return false;
142 }
143 }
144
AddSpecializedEvent(int32_t pageId,const std::string & event)145 bool DOMPopup::AddSpecializedEvent(int32_t pageId, const std::string& event)
146 {
147 if (event == DOM_VISIBILITY_CHANGE) {
148 visibilityChangeEventId_ = EventMarker(GetNodeIdForEvent(), event, pageId);
149 popupChild_->GetPopupParam()->SetOnVisibilityChange(visibilityChangeEventId_);
150 return true;
151 } else {
152 return false;
153 }
154 }
155
CallSpecializedMethod(const std::string & method,const std::string & args)156 void DOMPopup::CallSpecializedMethod(const std::string& method, const std::string& args)
157 {
158 auto popup = AceType::DynamicCast<PopupComponent>(popupChild_);
159 if (!popup) {
160 return;
161 }
162 auto controller = popup->GetPopupController();
163 if (!controller) {
164 return;
165 }
166 if (method == DOM_SHOW) {
167 controller->ShowPopup();
168 } else if (method == DOM_HIDE) {
169 controller->CancelPopup();
170 }
171 }
172
BindIdNode(const RefPtr<DOMNode> & idNode)173 void DOMPopup::BindIdNode(const RefPtr<DOMNode>& idNode)
174 {
175 if (!idNode) {
176 return;
177 }
178 if (!clickMarker_.IsEmpty()) {
179 RemoveMarker();
180 }
181 clickMarker_ = BackEndEventManager<void(const ClickInfo&)>::GetInstance().GetAvailableMarker();
182 popupChild_->GetPopupParam()->SetTargetId(idNode->GetRootComponent()->GetId());
183 popupChild_->GetPopupParam()->SetTargetMargin(idNode->GetBoxComponent()->GetMargin());
184
185 if (clickable_) {
186 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
187 clickMarker_, [weakChild = WeakPtr<PopupComponent>(popupChild_), weakNode = WeakPtr<DOMNode>(idNode)](
188 const ClickInfo& clickInfo) {
189 auto popupChild = weakChild.Upgrade();
190 auto idNode = weakNode.Upgrade();
191 if (popupChild && idNode) {
192 auto controller = popupChild->GetPopupController();
193 controller->ShowPopup();
194 }
195 });
196 idNode->SetOnClick(clickMarker_);
197 idNode->MarkNeedUpdate();
198 }
199 }
200
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)201 void DOMPopup::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
202 {
203 if (!child) {
204 return;
205 }
206 if (lastComponent_) {
207 auto focusCollaboration = AceType::MakeRefPtr<FocusCollaborationComponent>();
208 focusCollaboration->InsertChild(0, child->GetRootComponent());
209 lastComponent_->SetChild(focusCollaboration);
210 }
211 }
212
PrepareSpecializedComponent()213 void DOMPopup::PrepareSpecializedComponent()
214 {
215 if (boxComponent_->GetBackDecoration()) {
216 auto boxBorder = boxComponent_->GetBackDecoration()->GetBorder();
217 popupChild_->GetPopupParam()->SetBorder(boxBorder);
218 Border border;
219 border.SetTopLeftRadius(boxBorder.TopLeftRadius());
220 border.SetTopRightRadius(boxBorder.TopRightRadius());
221 border.SetBottomLeftRadius(boxBorder.BottomLeftRadius());
222 border.SetBottomRightRadius(boxBorder.BottomRightRadius());
223 boxComponent_->GetBackDecoration()->SetBorder(border);
224 boxComponent_->GetBackDecoration()->SetBackgroundColor(Color::TRANSPARENT);
225 }
226 popupChild_->GetPopupParam()->SetIsShow(IsShow());
227 popupChild_->GetPopupParam()->SetPadding(boxComponent_->GetPadding());
228 popupChild_->GetPopupParam()->SetMargin(boxComponent_->GetMargin());
229 boxComponent_->SetMargin(Edge());
230 }
231
CompositeSpecializedComponent(const std::vector<RefPtr<SingleChild>> & components)232 RefPtr<Component> DOMPopup::CompositeSpecializedComponent(const std::vector<RefPtr<SingleChild>>& components)
233 {
234 lastComponent_ = components.back();
235 popupChild_->SetChild(AceType::DynamicCast<Component>(components.front()));
236 auto box = AceType::MakeRefPtr<BoxComponent>();
237 box->SetChild(popupChild_);
238 return box;
239 }
240
241 } // namespace OHOS::Ace::Framework
242