• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_search.h"
17 
18 #include "base/utils/linear_map.h"
19 #include "base/utils/utils.h"
20 #include "core/common/ime/text_selection.h"
21 #include "core/components/common/properties/radius.h"
22 #include "core/components/search/search_theme.h"
23 #include "core/components/text_field/textfield_theme.h"
24 #include "frameworks/bridge/common/dom/input/dom_textfield_util.h"
25 #include "frameworks/bridge/common/utils/utils.h"
26 
27 namespace OHOS::Ace::Framework {
28 namespace {
29 
30 struct StyleParseHolder {
31     const DOMSearch& node;
32     RefPtr<SearchComponent>& search;
33     RefPtr<TextFieldComponent>& textField;
34     TextStyle& textStyle;
35     bool& isPaddingChanged;
36 };
37 
38 } // namespace
39 
DOMSearch(NodeId nodeId,const std::string & nodeName)40 DOMSearch::DOMSearch(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName)
41 {
42     searchChild_ = AceType::MakeRefPtr<SearchComponent>();
43     textFieldComponent_ = AceType::MakeRefPtr<TextFieldComponent>();
44     DOMTextFieldUtil::InitController(textFieldComponent_);
45 }
46 
ResetInitializedStyle()47 void DOMSearch::ResetInitializedStyle()
48 {
49     InitializeStyle();
50 }
51 
InitializeStyle()52 void DOMSearch::InitializeStyle()
53 {
54     auto textFieldTheme = GetTheme<TextFieldTheme>();
55     auto searchTheme = GetTheme<SearchTheme>();
56     if (!textFieldTheme || !searchTheme) {
57         // theme is null, set default decoration to text field component
58         RefPtr<Decoration> decoration = AceType::MakeRefPtr<Decoration>();
59         textFieldComponent_->SetDecoration(decoration);
60         LOGE("textFieldTheme or searchTheme is null");
61         return;
62     }
63 
64     DOMTextFieldUtil::InitDefaultValue(boxComponent_, textFieldComponent_, textFieldTheme);
65     boxComponent_->SetBackDecoration(nullptr);
66     boxComponent_->SetPadding(Edge());
67     textFieldComponent_->SetIconSize(searchTheme->GetIconSize());
68     textFieldComponent_->SetIconHotZoneSize(searchTheme->GetCloseIconHotZoneSize());
69     Edge decorationPadding;
70     Dimension leftPadding = searchTheme->GetLeftPadding();
71     Dimension rightPadding = searchTheme->GetRightPadding();
72     if (IsRightToLeft()) {
73         decorationPadding = Edge(rightPadding.Value(), 0.0, leftPadding.Value(), 0.0, leftPadding.Unit());
74     } else {
75         decorationPadding = Edge(leftPadding.Value(), 0.0, rightPadding.Value(), 0.0, leftPadding.Unit());
76     }
77     auto textFieldDecoration = textFieldComponent_->GetDecoration();
78     if (textFieldDecoration) {
79         textFieldDecoration->SetPadding(decorationPadding);
80         textFieldDecoration->SetBorderRadius(searchTheme->GetBorderRadius());
81         textFieldComponent_->SetOriginBorder(textFieldDecoration->GetBorder());
82     }
83     textFieldComponent_->SetAction(TextInputAction::SEARCH);
84     textFieldComponent_->SetWidthReserved(searchTheme->GetTextFieldWidthReserved());
85     textFieldComponent_->SetTextColor(searchTheme->GetTextColor());
86     textFieldComponent_->SetFocusTextColor(searchTheme->GetFocusTextColor());
87     textFieldComponent_->SetPlaceholderColor(searchTheme->GetPlaceholderColor());
88     textFieldComponent_->SetFocusPlaceholderColor(searchTheme->GetFocusPlaceholderColor());
89     textFieldComponent_->SetBlockRightShade(searchTheme->GetBlockRightShade());
90     textStyle_ = textFieldComponent_->GetTextStyle();
91 
92     std::function<void(const std::string&)> submitEvent;
93     searchChild_->SetSubmitEvent(submitEvent);
94     searchChild_->SetChild(textFieldComponent_);
95     searchChild_->SetTextEditController(textFieldComponent_->GetTextEditController());
96     searchChild_->SetCloseIconSize(searchTheme->GetCloseIconSize());
97     searchChild_->SetCloseIconHotZoneHorizontal(searchTheme->GetCloseIconHotZoneSize());
98     searchChild_->SetHoverColor(textFieldTheme->GetHoverColor());
99     searchChild_->SetPressColor(textFieldTheme->GetPressColor());
100     SetHeight(searchTheme->GetHeight());
101     isPaddingChanged_ = true;
102 }
103 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)104 bool DOMSearch::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
105 {
106     static const LinearMapNode<void (*)(const std::string&, SearchComponent&, TextFieldComponent&, TextStyle&)>
107         searchAttrOperators[] = {
108             { DOM_AUTO_FOCUS,
109                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
110                     TextStyle& textStyle) { textFieldComponent.SetAutoFocus(StringToBool(val)); } },
111             { DOM_SEARCH_HINT,
112                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
113                     TextStyle& textStyle) { textFieldComponent.SetPlaceholder(val); } },
114             { DOM_SEARCH_ICON,
115                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
116                     TextStyle& textStyle) {
117                     if (SystemProperties::GetDeviceType() == DeviceType::TV) {
118                         return;
119                     }
120                     textFieldComponent.SetIconImage(val);
121                 } },
122             { DOM_SEARCH_BUTTON,
123                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
124                     TextStyle& textStyle) { searchComponent.SetSearchText(val); } },
125             { DOM_INPUT_SELECTED_END,
126                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
127                     TextStyle& textStyle) { textFieldComponent.SetSelectedEnd(StringToInt(val)); } },
128             { DOM_INPUT_SELECTED_START,
129                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
130                     TextStyle& textStyle) { textFieldComponent.SetSelectedStart(StringToInt(val)); } },
131             { DOM_INPUT_SOFT_KEYBOARD_ENABLED,
132                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
133                     TextStyle& textStyle) { textFieldComponent.SetSoftKeyboardEnabled(StringToBool(val)); } },
134             { DOM_SEARCH_VALUE,
135                 [](const std::string& val, SearchComponent& searchComponent, TextFieldComponent& textFieldComponent,
136                     TextStyle& textStyle) {
137                     textFieldComponent.SetValue(val);
138                     textFieldComponent.SetResetToStart(false);
139                 } },
140         };
141     auto operatorIter = BinarySearchFindIndex(searchAttrOperators, ArraySize(searchAttrOperators), attr.first.c_str());
142     if (operatorIter != -1) {
143         searchAttrOperators[operatorIter].value(attr.second, *searchChild_, *textFieldComponent_, textStyle_);
144         return true;
145     }
146     return false;
147 }
148 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)149 bool DOMSearch::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
150 {
151     // static linear map must be sorted by key.
152     static const LinearMapNode<void (*)(const std::string&, StyleParseHolder&)> searchStyleSize[] = {
153         { DOM_TEXT_ALLOW_SCALE, [](const std::string& val,
154                                     StyleParseHolder& holder) { holder.textStyle.SetAllowScale(StringToBool(val)); } },
155         { DOM_BACKGROUND_COLOR,
156             [](const std::string& val, StyleParseHolder& holder) {
157                 holder.textField->SetBgColor(holder.node.ParseColor(val));
158                 holder.textField->SetFocusBgColor(holder.node.ParseColor(val));
159             } },
160         { DOM_CARET_COLOR,
161             [](const std::string& val, StyleParseHolder& holder) {
162                 holder.textField->SetCursorColor(holder.node.ParseColor(val));
163             } },
164         { DOM_COLOR,
165             [](const std::string& val, StyleParseHolder& holder) {
166                 auto color = holder.node.ParseColor(val);
167                 holder.textStyle.SetTextColor(color);
168                 holder.textField->SetTextColor(color);
169                 holder.textField->SetFocusTextColor(color);
170             } },
171         { DOM_TEXT_FONT_FAMILY,
172             [](const std::string& val, StyleParseHolder& holder) {
173                 holder.textStyle.SetFontFamilies(holder.node.ParseFontFamilies(val));
174             } },
175         { DOM_TEXT_FONT_SIZE,
176             [](const std::string& val, StyleParseHolder& holder) {
177                 holder.textStyle.SetFontSize(holder.node.ParseDimension(val));
178             } },
179         { DOM_TEXT_FONT_WEIGHT,
180             [](const std::string& val, StyleParseHolder& holder) {
181                 holder.textStyle.SetFontWeight(ConvertStrToFontWeight(val));
182             } },
183         { DOM_PADDING,
184             [](const std::string& val, StyleParseHolder& holder) {
185                 Edge padding;
186                 if (Edge::FromString(val, padding)) {
187                     holder.textField->GetDecoration()->SetPadding(padding);
188                     holder.isPaddingChanged = true;
189                 }
190             } },
191         { DOM_PADDING_BOTTOM,
192             [](const std::string& val, StyleParseHolder& holder) {
193                 auto padding = holder.textField->GetDecoration()->GetPadding();
194                 padding.SetBottom(holder.node.ParseDimension(val));
195                 holder.textField->GetDecoration()->SetPadding(padding);
196                 holder.isPaddingChanged = true;
197             } },
198         { DOM_PADDING_END,
199             [](const std::string& val, StyleParseHolder& holder) {
200                 auto padding = holder.textField->GetDecoration()->GetPadding();
201                 (holder.search->GetTextDirection() == TextDirection::RTL)
202                     ? padding.SetLeft(holder.node.ParseDimension(val))
203                     : padding.SetRight(holder.node.ParseDimension(val));
204                 holder.textField->GetDecoration()->SetPadding(padding);
205                 holder.isPaddingChanged = true;
206             } },
207         { DOM_PADDING_LEFT,
208             [](const std::string& val, StyleParseHolder& holder) {
209                 auto padding = holder.textField->GetDecoration()->GetPadding();
210                 padding.SetLeft(holder.node.ParseDimension(val));
211                 holder.textField->GetDecoration()->SetPadding(padding);
212                 holder.isPaddingChanged = true;
213             } },
214         { DOM_PADDING_RIGHT,
215             [](const std::string& val, StyleParseHolder& holder) {
216                 auto padding = holder.textField->GetDecoration()->GetPadding();
217                 padding.SetRight(holder.node.ParseDimension(val));
218                 holder.textField->GetDecoration()->SetPadding(padding);
219                 holder.isPaddingChanged = true;
220             } },
221         { DOM_PADDING_START,
222             [](const std::string& val, StyleParseHolder& holder) {
223                 auto padding = holder.textField->GetDecoration()->GetPadding();
224                 (holder.search->GetTextDirection() == TextDirection::RTL)
225                     ? padding.SetRight(holder.node.ParseDimension(val))
226                     : padding.SetLeft(holder.node.ParseDimension(val));
227                 holder.textField->GetDecoration()->SetPadding(padding);
228                 holder.isPaddingChanged = true;
229             } },
230         { DOM_PADDING_TOP,
231             [](const std::string& val, StyleParseHolder& holder) {
232                 auto padding = holder.textField->GetDecoration()->GetPadding();
233                 padding.SetTop(holder.node.ParseDimension(val));
234                 holder.textField->GetDecoration()->SetPadding(padding);
235                 holder.isPaddingChanged = true;
236             } },
237         { DOM_INPUT_PLACEHOLDER_COLOR,
238             [](const std::string& val, StyleParseHolder& holder) {
239                 auto color = holder.node.ParseColor(val);
240                 holder.textField->SetPlaceholderColor(color);
241                 holder.textField->SetFocusPlaceholderColor(color);
242             } },
243     };
244     auto operatorIter = BinarySearchFindIndex(searchStyleSize, ArraySize(searchStyleSize), style.first.c_str());
245     if (operatorIter != -1) {
246         StyleParseHolder holder = { .node = *this,
247             .search = searchChild_,
248             .textField = textFieldComponent_,
249             .textStyle = textStyle_,
250             .isPaddingChanged = isPaddingChanged_ };
251         searchStyleSize[operatorIter].value(style.second, holder);
252         return true;
253     }
254     if (DOMTextFieldUtil::IsRadiusStyle(style.first)) {
255         hasBoxRadius_ = true;
256     }
257     return false;
258 }
259 
AddSpecializedEvent(int32_t pageId,const std::string & event)260 bool DOMSearch::AddSpecializedEvent(int32_t pageId, const std::string& event)
261 {
262     static const LinearMapNode<void (*)(
263         const RefPtr<SearchComponent>&, const RefPtr<TextFieldComponent>&, const EventMarker&)>
264         eventOperators[] = {
265             { DOM_CATCH_BUBBLE_CLICK,
266                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
267                     const EventMarker& event) {
268                     EventMarker eventMarker(event);
269                     eventMarker.SetCatchMode(true);
270                     textField->SetOnTap(eventMarker);
271                 } },
272             { DOM_CHANGE, [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
273                               const EventMarker& event) { search->SetChangeEventId(event); } },
274             { DOM_CLICK,
275                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
276                     const EventMarker& event) {
277                     EventMarker eventMarker(event);
278                     eventMarker.SetCatchMode(false);
279                     textField->SetOnTap(eventMarker);
280                 } },
281             { DOM_LONG_PRESS, [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
282                                   const EventMarker& event) { textField->SetOnLongPress(event); } },
283             { DOM_INPUT_EVENT_OPTION_SELECT,
284                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
285                     const EventMarker& event) { textField->SetOnOptionsClick(event); } },
286             { DOM_INPUT_EVENT_SEARCH,
287                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
288                     const EventMarker& event) { textField->SetOnSearch(event); } },
289             { DOM_INPUT_EVENT_SELECT_CHANGE,
290                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
291                     const EventMarker& event) { textField->SetOnSelectChange(event); } },
292             { DOM_INPUT_EVENT_SHARE,
293                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
294                     const EventMarker& event) { textField->SetOnShare(event); } },
295             { DOM_SUBMIT, [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
296                               const EventMarker& event) { search->SetSubmitEventId(event); } },
297             { DOM_INPUT_EVENT_TRANSLATE,
298                 [](const RefPtr<SearchComponent>& search, const RefPtr<TextFieldComponent>& textField,
299                     const EventMarker& event) { textField->SetOnTranslate(event); } },
300         };
301     auto operatorIter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
302     if (operatorIter != -1) {
303         eventOperators[operatorIter].value(
304             searchChild_, textFieldComponent_, EventMarker(GetNodeIdForEvent(), event, pageId));
305         return true;
306     }
307     return false;
308 }
309 
CallSpecializedMethod(const std::string & method,const std::string & args)310 void DOMSearch::CallSpecializedMethod(const std::string& method, const std::string& args)
311 {
312     auto textField = AceType::DynamicCast<TextFieldComponent>(textFieldComponent_);
313     if (!textField) {
314         return;
315     }
316     auto controller = textField->GetTextFieldController();
317     if (!controller) {
318         return;
319     }
320     if (method == DOM_INPUT_METHOD_DELETE) {
321         controller->Delete();
322     }
323 }
324 
PrepareSpecializedComponent()325 void DOMSearch::PrepareSpecializedComponent()
326 {
327     Border boxBorder;
328     // [boxComponent_] is created when [DomNode] is constructed so it won't be null
329     boxComponent_->SetMouseAnimationType(HoverAnimationType::OPACITY);
330     if (boxComponent_->GetBackDecoration()) {
331         boxBorder = boxComponent_->GetBackDecoration()->GetBorder();
332     }
333     searchChild_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
334     textFieldComponent_->SetTextDirection(IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR);
335     // [textFieldComponent_] is created when [DomSearch] is constructed so it won't be null
336     textFieldComponent_->SetTextStyle(textStyle_);
337     textFieldComponent_->SetInputOptions(inputOptions_);
338     textFieldComponent_->SetImageFill(GetImageFill());
339     DOMTextFieldUtil::UpdateDecorationStyle(boxComponent_, textFieldComponent_, boxBorder, hasBoxRadius_);
340     if (GreatOrEqual(boxComponent_->GetHeightDimension().Value(), 0.0)) {
341         textFieldComponent_->SetHeight(boxComponent_->GetHeightDimension());
342     }
343     if (isPaddingChanged_) {
344         auto padding = textFieldComponent_->GetDecoration()->GetPadding();
345         if (searchChild_->GetTextDirection() == TextDirection::RTL) {
346             padding.SetLeft(padding.Left() + searchChild_->GetCloseIconHotZoneHorizontal());
347         } else {
348             padding.SetRight(padding.Right() + searchChild_->GetCloseIconHotZoneHorizontal());
349         }
350         textFieldComponent_->GetDecoration()->SetPadding(padding);
351         searchChild_->SetDecoration(textFieldComponent_->GetDecoration());
352         isPaddingChanged_ = false;
353     }
354 }
355 
OnRequestFocus(bool shouldFocus)356 void DOMSearch::OnRequestFocus(bool shouldFocus)
357 {
358     if (IsNodeDisabled() || !textFieldComponent_) {
359         return;
360     }
361     auto textFieldController = textFieldComponent_->GetTextFieldController();
362     if (!textFieldController) {
363         return;
364     }
365     textFieldController->Focus(shouldFocus);
366 }
367 
368 } // namespace OHOS::Ace::Framework
369