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/common/dom/dom_select.h"
17 
18 #include "frameworks/bridge/common/dom/dom_option.h"
19 #include "frameworks/bridge/common/utils/utils.h"
20 
21 namespace OHOS::Ace::Framework {
22 
IsParentNavigation() const23 bool DOMSelect::IsParentNavigation() const
24 {
25     auto parent = GetParentNode();
26     if (!parent) {
27         return false;
28     }
29     return parent->GetTag() == DOM_NODE_TAG_NAVIGATION_BAR;
30 }
31 
DOMSelect(NodeId nodeId,const std::string & nodeName)32 DOMSelect::DOMSelect(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
33 {
34     selectComponent_ = AceType::MakeRefPtr<SelectComponent>();
35     tipText_ = AceType::MakeRefPtr<TextComponent>("");
36     selectComponent_->SetTipText(tipText_);
37 #if defined(PREVIEW)
38     selectComponent_->SetNodeId(nodeId);
39 #endif
40 }
41 
ResetInitializedStyle()42 void DOMSelect::ResetInitializedStyle()
43 {
44     InitializeStyle();
45 }
46 
InitializeStyle()47 void DOMSelect::InitializeStyle()
48 {
49     if (!selectComponent_) {
50         return;
51     }
52     selectComponent_->InitTheme(GetThemeManager());
53     theme_ = GetTheme<SelectTheme>();
54     if (theme_ && selectComponent_) {
55         selectComponent_->SetClickedColor(theme_->GetClickedColor());
56         selectComponent_->SetDisabledColor(theme_->GetDisabledColor());
57         selectComponent_->SetSelectedColor(theme_->GetSelectedColor());
58         selectComponent_->SetOptionSize(theme_->GetOptionSize());
59         selectComponent_->SetRRectSize(theme_->GetRRectSize());
60         selectComponent_->SetPopupBorderWidth(theme_->GetPopupBorderWidth());
61         selectComponent_->SetPopupShadowWidth(theme_->GetPopupShadowWidth());
62         selectComponent_->SetFontFamily(theme_->GetFontFamily());
63         selectComponent_->SetFontSize(theme_->GetFontSize());
64         selectComponent_->SetAllowScale(theme_->IsAllowScale());
65         selectComponent_->SetTextColor(theme_->GetFontColor());
66         selectComponent_->SetFontWeight(FontWeight::W500);
67         selectComponent_->SetTextDecoration(theme_->GetTextDecoration());
68         selectComponent_->SetBackgroundColor(Color::TRANSPARENT);
69     }
70 }
71 
UpdateBoxSize(const CalcDimension & width,const CalcDimension & height)72 void DOMSelect::UpdateBoxSize(const CalcDimension& width, const CalcDimension& height)
73 {
74     if (!selectComponent_) {
75         return;
76     }
77 
78     if (width.Unit() != DimensionUnit::PERCENT && height.Unit() != DimensionUnit::PERCENT) {
79         selectComponent_->SetInnerSize(width, height);
80         return;
81     }
82 
83     if (width.Unit() == DimensionUnit::PERCENT && height.Unit() == DimensionUnit::PERCENT) {
84         DOMNode::UpdateBoxSize(width, height);
85         selectComponent_->SetInnerSize(100.0_pct, 100.0_pct);
86         return;
87     }
88 
89     if (width.Unit() == DimensionUnit::PERCENT) {
90         DOMNode::UpdateBoxSize(width, height);
91         selectComponent_->SetInnerSize(100.0_pct, height);
92         return;
93     }
94 
95     DOMNode::UpdateBoxSize(width, height);
96     selectComponent_->SetInnerSize(100.0_pct, 100.0_pct);
97 }
98 
UpdateBoxPadding(const Edge & padding)99 void DOMSelect::UpdateBoxPadding(const Edge& padding)
100 {
101     if (!selectComponent_) {
102         return;
103     }
104 
105     selectComponent_->SetInnerPadding(padding);
106 }
107 
UpdateBoxBorder(const Border & border)108 void DOMSelect::UpdateBoxBorder(const Border& border)
109 {
110     if (!selectComponent_) {
111         return;
112     }
113 
114     selectComponent_->SetInnerBorder(border);
115 }
116 
AddSpecializedEvent(int32_t pageId,const std::string & event)117 bool DOMSelect::AddSpecializedEvent(int32_t pageId, const std::string& event)
118 {
119     if (event == DOM_CHANGE) {
120         onChanged_ = EventMarker(GetNodeIdForEvent(), event, pageId);
121         selectComponent_->SetOnChanged(onChanged_);
122         return true;
123     }
124     return false;
125 }
126 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)127 bool DOMSelect::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
128 {
129     if (IsParentNavigation()) {
130         // not support style setting for navigation.
131         return true;
132     }
133 
134     static const LinearMapNode<void (*)(const std::string&, const DOMSelect&, SelectComponent&)>
135         selectStyleOperators[] = {
136             { DOM_TEXT_ALLOW_SCALE, [](const std::string& val, const DOMSelect& node,
137                                     SelectComponent& select) { select.SetAllowScale(StringToBool(val)); } },
138             { DOM_BACKGROUND_COLOR, [](const std::string& val, const DOMSelect& node,
139                                     SelectComponent& select) { select.SetBackgroundColor(node.ParseColor(val)); } },
140             { DOM_TEXT_COLOR, [](const std::string& val, const DOMSelect& node,
141                               SelectComponent& select) { select.SetTextColor(node.ParseColor(val)); } },
142             { DOM_TEXT_FONT_FAMILY, [](const std::string& val, const DOMSelect& node,
143                                     SelectComponent& select) { select.SetFontFamily(val); } },
144             { DOM_TEXT_FONT_SIZE,
145                 [](const std::string& val, const DOMSelect& node, SelectComponent& select) {
146                     select.SetFontSize(node.ParseDimension(val));
147                     select.SetIsFontSetFlag(true);
148                 } },
149             { DOM_TEXT_FONT_WEIGHT, [](const std::string& val, const DOMSelect& node,
150                                     SelectComponent& select) { select.SetFontWeight(ConvertStrToFontWeight(val)); } },
151             { DOM_TEXT_DECORATION,
152                 [](const std::string& val, const DOMSelect& node, SelectComponent& select) {
153                     select.SetTextDecoration(ConvertStrToTextDecoration(val));
154                 } },
155         };
156     auto operatorIter =
157         BinarySearchFindIndex(selectStyleOperators, ArraySize(selectStyleOperators), style.first.c_str());
158     if (operatorIter != -1) {
159         selectStyleOperators[operatorIter].value(style.second, *this, *selectComponent_);
160         return true;
161     }
162     return false;
163 }
164 
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)165 void DOMSelect::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
166 {
167     if (!child || child->GetTag() != DOM_NODE_TAG_OPTION) {
168         LOGW("DOMSelect child is not tag node");
169         return;
170     }
171 
172     auto option = AceType::DynamicCast<DOMOption>(child);
173     if (option) {
174         auto optionComponent = AceType::DynamicCast<OptionComponent>(option->GetSpecializedComponent());
175         if (!optionComponent) {
176             return;
177         }
178         if (!selectComponent_->GetSelectOptionCount() || optionComponent->GetSelected()) {
179             auto text = optionComponent->GetText();
180             if (text) {
181                 tipText_->SetData(text->GetData());
182             } else {
183                 tipText_->SetData("");
184             }
185         }
186         if (slot < 0) {
187             selectComponent_->AppendSelectOption(optionComponent);
188         } else {
189             selectComponent_->InsertSelectOption(optionComponent, static_cast<uint32_t>(slot));
190         }
191     }
192 }
193 
OnChildNodeRemoved(const RefPtr<DOMNode> & child)194 void DOMSelect::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
195 {
196     if (!child || !selectComponent_) {
197         return;
198     }
199 
200     auto option = AceType::DynamicCast<OptionComponent>(child->GetSpecializedComponent());
201     if (!option) {
202         return;
203     }
204 
205     selectComponent_->RemoveSelectOption(option);
206 }
207 
PrepareSpecializedComponent()208 void DOMSelect::PrepareSpecializedComponent()
209 {
210     if (selectComponent_) {
211         selectComponent_->SetTextDirection((IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR));
212     }
213 }
214 
215 } // namespace OHOS::Ace::Framework
216