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