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