1 /*
2  * Copyright (c) 2021-2023 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 "bridge/declarative_frontend/jsview/js_search.h"
17 
18 #include <optional>
19 #include <string>
20 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
21 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
22 #endif
23 
24 #include "base/log/ace_scoring_log.h"
25 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_search_theme.h"
26 #include "bridge/declarative_frontend/engine/functions/js_clipboard_function.h"
27 #include "bridge/declarative_frontend/engine/functions/js_function.h"
28 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
29 #include "bridge/declarative_frontend/jsview/js_text_editable_controller.h"
30 #include "bridge/declarative_frontend/jsview/js_textfield.h"
31 #include "bridge/declarative_frontend/jsview/js_textinput.h"
32 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
33 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
34 #include "bridge/declarative_frontend/jsview/models/search_model_impl.h"
35 #include "core/components/common/layout/constants.h"
36 #include "core/components/common/properties/text_style_parser.h"
37 #include "core/components/search/search_theme.h"
38 #include "core/components_ng/gestures/gesture_info.h"
39 #include "core/components_ng/pattern/search/search_model_ng.h"
40 #include "core/components_ng/pattern/text_field/text_field_model_ng.h"
41 
42 namespace OHOS::Ace {
43 
44 std::unique_ptr<SearchModel> SearchModel::instance_ = nullptr;
45 std::mutex SearchModel::mutex_;
46 
GetInstance()47 SearchModel* SearchModel::GetInstance()
48 {
49 #ifdef NG_BUILD
50     static NG::SearchModelNG instance;
51     return &instance;
52 #else
53     if (Container::IsCurrentUseNewPipeline()) {
54         static NG::SearchModelNG instance;
55         return &instance;
56     } else {
57         static Framework::SearchModelImpl instance;
58         return &instance;
59     }
60 #endif
61 }
62 
63 } // namespace OHOS::Ace
64 
65 namespace OHOS::Ace::Framework {
66 namespace {
67 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END };
68 constexpr double DEFAULT_OPACITY = 0.2;
69 const int32_t DEFAULT_ALPHA = 255;
70 constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID;
71 const char* TOP_START_PROPERTY = "topStart";
72 const char* TOP_END_PROPERTY = "topEnd";
73 const char* BOTTOM_START_PROPERTY = "bottomStart";
74 const char* BOTTOM_END_PROPERTY = "bottomEnd";
75 
ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)76 bool ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)
77 {
78     auto value = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::VALUE));
79     if (!value->IsNumber()) {
80         return false;
81     }
82     auto unit = DimensionUnit::VP;
83     auto jsUnit = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::UNIT));
84     if (jsUnit->IsNumber()) {
85         unit = static_cast<DimensionUnit>(jsUnit->ToNumber<int32_t>());
86     }
87     CalcDimension dimension(value->ToNumber<double>(), unit);
88     result = dimension;
89     return true;
90 }
91 } // namespace
92 
JSBind(BindingTarget globalObj)93 void JSSearch::JSBind(BindingTarget globalObj)
94 {
95     JSClass<JSSearch>::Declare("Search");
96     MethodOptions opt = MethodOptions::NONE;
97 
98     JSClass<JSSearch>::StaticMethod("create", &JSSearch::Create, opt);
99     JSClass<JSSearch>::StaticMethod("searchButton", &JSSearch::SetSearchButton, opt);
100     JSClass<JSSearch>::StaticMethod("searchIcon", &JSSearch::SetSearchIcon, opt);
101     JSClass<JSSearch>::StaticMethod("cancelButton", &JSSearch::SetCancelButton, opt);
102     JSClass<JSSearch>::StaticMethod("fontColor", &JSSearch::SetTextColor, opt);
103     JSClass<JSSearch>::StaticMethod("caretStyle", &JSSearch::SetCaret, opt);
104     JSClass<JSSearch>::StaticMethod("placeholderColor", &JSSearch::SetPlaceholderColor, opt);
105     JSClass<JSSearch>::StaticMethod("placeholderFont", &JSSearch::SetPlaceholderFont, opt);
106     JSClass<JSSearch>::StaticMethod("textFont", &JSSearch::SetTextFont, opt);
107     JSClass<JSSearch>::StaticMethod("textAlign", &JSSearch::SetTextAlign, opt);
108     JSClass<JSSearch>::StaticMethod("onSubmit", &JSSearch::OnSubmit, opt);
109     JSClass<JSSearch>::StaticMethod("onChange", &JSSearch::OnChange, opt);
110     JSClass<JSSearch>::StaticMethod("onTextSelectionChange", &JSSearch::SetOnTextSelectionChange);
111     JSClass<JSSearch>::StaticMethod("onContentScroll", &JSSearch::SetOnScroll);
112     JSClass<JSSearch>::StaticMethod("border", &JSSearch::JsBorder);
113     JSClass<JSSearch>::StaticMethod("borderWidth", &JSSearch::JsBorderWidth);
114     JSClass<JSSearch>::StaticMethod("borderColor", &JSSearch::JsBorderColor);
115     JSClass<JSSearch>::StaticMethod("borderStyle", &JSSearch::JsBorderStyle);
116     JSClass<JSSearch>::StaticMethod("borderRadius", &JSSearch::JsBorderRadius);
117     JSClass<JSSearch>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
118     JSClass<JSSearch>::StaticMethod("height", &JSSearch::SetHeight);
119     JSClass<JSSearch>::StaticMethod("width", &JSViewAbstract::JsWidth);
120     JSClass<JSSearch>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
121     JSClass<JSSearch>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
122     JSClass<JSSearch>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
123     JSClass<JSSearch>::StaticMethod("requestKeyboardOnFocus", &JSSearch::SetEnableKeyboardOnFocus);
124     JSClass<JSSearch>::StaticMethod("enableKeyboardOnFocus", &JSSearch::SetEnableKeyboardOnFocus);
125     JSClass<JSSearch>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
126     JSClass<JSSearch>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
127     JSClass<JSSearch>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
128     JSClass<JSSearch>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
129     JSClass<JSSearch>::StaticMethod("onCopy", &JSSearch::SetOnCopy);
130     JSClass<JSSearch>::StaticMethod("onCut", &JSSearch::SetOnCut);
131     JSClass<JSSearch>::StaticMethod("onPaste", &JSSearch::SetOnPaste);
132     JSClass<JSSearch>::StaticMethod("copyOption", &JSSearch::SetCopyOption);
133     JSClass<JSSearch>::StaticMethod("selectionMenuHidden", &JSSearch::SetSelectionMenuHidden);
134     JSClass<JSSearch>::StaticMethod("customKeyboard", &JSSearch::SetCustomKeyboard);
135     JSClass<JSSearch>::StaticMethod("enterKeyType", &JSSearch::SetEnterKeyType);
136     JSClass<JSSearch>::StaticMethod("maxLength", &JSSearch::SetMaxLength);
137     JSClass<JSSearch>::StaticMethod("type", &JSSearch::SetType);
138     JSClass<JSSearch>::StaticMethod("dragPreviewOptions", &JSSearch::SetDragPreviewOptions);
139     JSClass<JSSearch>::StaticMethod("editMenuOptions", &JSSearch::EditMenuOptions);
140     JSBindMore();
141     JSClass<JSSearch>::InheritAndBind<JSViewAbstract>(globalObj);
142 }
143 
JSBindMore()144 void JSSearch::JSBindMore()
145 {
146     JSClass<JSSearch>::StaticMethod("decoration", &JSSearch::SetDecoration);
147     JSClass<JSSearch>::StaticMethod("minFontSize", &JSSearch::SetMinFontSize);
148     JSClass<JSSearch>::StaticMethod("maxFontSize", &JSSearch::SetMaxFontSize);
149     JSClass<JSSearch>::StaticMethod("letterSpacing", &JSSearch::SetLetterSpacing);
150     JSClass<JSSearch>::StaticMethod("lineHeight", &JSSearch::SetLineHeight);
151     JSClass<JSSearch>::StaticMethod("fontFeature", &JSSearch::SetFontFeature);
152     JSClass<JSSearch>::StaticMethod("id", &JSSearch::SetId);
153     JSClass<JSSearch>::StaticMethod("key", &JSSearch::SetKey);
154     JSClass<JSSearch>::StaticMethod("selectedBackgroundColor", &JSSearch::SetSelectedBackgroundColor);
155     JSClass<JSSearch>::StaticMethod("inputFilter", &JSSearch::SetInputFilter);
156     JSClass<JSSearch>::StaticMethod("onEditChange", &JSSearch::SetOnEditChange);
157     JSClass<JSSearch>::StaticMethod("textIndent", &JSSearch::SetTextIndent);
158     JSClass<JSSearch>::StaticMethod("onWillInsert", &JSSearch::OnWillInsertValue);
159     JSClass<JSSearch>::StaticMethod("onDidInsert", &JSSearch::OnDidInsertValue);
160     JSClass<JSSearch>::StaticMethod("onWillDelete", &JSSearch::OnWillDelete);
161     JSClass<JSSearch>::StaticMethod("onDidDelete", &JSSearch::OnDidDelete);
162     JSClass<JSSearch>::StaticMethod("enablePreviewText", &JSSearch::SetEnablePreviewText);
163     JSClass<JSSearch>::StaticMethod("enableHapticFeedback", &JSSearch::SetEnableHapticFeedback);
164 }
165 
ParseSearchValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)166 void ParseSearchValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
167 {
168     CHECK_NULL_VOID(changeEventVal->IsFunction());
169 
170     JsEventCallback<void(const std::string&)> onChangeEvent(
171         info.GetExecutionContext(), JSRef<JSFunc>::Cast(changeEventVal));
172     SearchModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
173 }
174 
SetDragPreviewOptions(const JSCallbackInfo& info)175 void JSSearch::SetDragPreviewOptions(const JSCallbackInfo& info)
176 {
177     NG::DragPreviewOption option = JSViewAbstract::ParseDragPreviewOptions(info);
178     SearchModel::GetInstance()->SetDragPreviewOptions(option);
179 }
180 
SetFontFeature(const JSCallbackInfo& info)181 void JSSearch::SetFontFeature(const JSCallbackInfo& info)
182 {
183     if (info.Length() < 1) {
184         return;
185     }
186 
187     if (!info[0]->IsString() && !info[0]->IsObject()) {
188         return;
189     }
190     std::string fontFeatureSettings = info[0]->ToString();
191     SearchModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings));
192 }
193 
Create(const JSCallbackInfo& info)194 void JSSearch::Create(const JSCallbackInfo& info)
195 {
196     std::optional<std::string> key;
197     std::optional<std::string> tip;
198     std::optional<std::string> src;
199     JSTextEditableController* jsController = nullptr;
200     JSRef<JSVal> changeEventVal;
201     if (info[0]->IsObject()) {
202         auto param = JSRef<JSObject>::Cast(info[0]);
203         std::string placeholder;
204         if (param->GetProperty("placeholder")->IsUndefined()) {
205             tip = "";
206         }
207         if (ParseJsString(param->GetProperty("placeholder"), placeholder)) {
208             tip = placeholder;
209         }
210         std::string text;
211         JSRef<JSVal> textValue = param->GetProperty("value");
212         if (textValue->IsObject()) {
213             JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(textValue);
214             changeEventVal = valueObj->GetProperty("changeEvent");
215             if (changeEventVal->IsFunction()) {
216                 textValue = valueObj->GetProperty("value");
217             }
218             if (ParseJsString(textValue, text)) {
219                 key = text;
220             }
221         } else if (param->HasProperty("value") && textValue->IsUndefined()) {
222             key = "";
223         } else {
224             if (ParseJsString(textValue, text)) {
225                 key = text;
226             }
227         }
228         std::string icon;
229         if (ParseJsString(param->GetProperty("icon"), icon)) {
230             src = icon;
231         }
232         auto controllerObj = param->GetProperty("controller");
233         if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
234             jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextEditableController>();
235         }
236     }
237     auto controller = SearchModel::GetInstance()->Create(key, tip, src);
238     if (jsController) {
239         jsController->SetController(controller);
240     }
241     SearchModel::GetInstance()->SetFocusable(true);
242     SearchModel::GetInstance()->SetFocusNode(true);
243     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
244         ParseSearchValueObject(info, changeEventVal);
245     }
246     JSSeacrhTheme::ApplyTheme();
247 }
248 
SetSelectedBackgroundColor(const JSCallbackInfo& info)249 void JSSearch::SetSelectedBackgroundColor(const JSCallbackInfo& info)
250 {
251     if (info.Length() < 1) {
252         return;
253     }
254     Color selectedColor;
255     if (!ParseJsColor(info[0], selectedColor)) {
256         auto pipeline = PipelineBase::GetCurrentContext();
257         CHECK_NULL_VOID(pipeline);
258         auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
259         CHECK_NULL_VOID(theme);
260         selectedColor = theme->GetSelectedColor();
261     }
262     // Alpha = 255 means opaque
263     if (selectedColor.GetAlpha() == DEFAULT_ALPHA) {
264         // Default setting of 20% opacity
265         selectedColor = selectedColor.ChangeOpacity(DEFAULT_OPACITY);
266     }
267     SearchModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
268 }
269 
SetEnableKeyboardOnFocus(const JSCallbackInfo& info)270 void JSSearch::SetEnableKeyboardOnFocus(const JSCallbackInfo& info)
271 {
272     if (info[0]->IsUndefined() || !info[0]->IsBoolean()) {
273         SearchModel::GetInstance()->RequestKeyboardOnFocus(true);
274         return;
275     }
276     SearchModel::GetInstance()->RequestKeyboardOnFocus(info[0]->ToBoolean());
277 }
278 
SetId(const JSCallbackInfo& info)279 void JSSearch::SetId(const JSCallbackInfo& info)
280 {
281     JSViewAbstract::JsId(info);
282     JSRef<JSVal> arg = info[0];
283     std::string id;
284     if (arg->IsString()) {
285         id = arg->ToString();
286     }
287     SearchModel::GetInstance()->UpdateInspectorId(id);
288 }
289 
SetKey(const std::string& key)290 void JSSearch::SetKey(const std::string& key)
291 {
292     JSViewAbstract::JsKey(key);
293     SearchModel::GetInstance()->UpdateInspectorId(key);
294 }
295 
SetSearchButton(const JSCallbackInfo& info)296 void JSSearch::SetSearchButton(const JSCallbackInfo& info)
297 {
298     auto theme = GetTheme<SearchTheme>();
299     CHECK_NULL_VOID(theme);
300     std::string buttonValue = "";
301     if (info[0]->IsString()) {
302         buttonValue = info[0]->ToString();
303     }
304     SearchModel::GetInstance()->SetSearchButton(buttonValue);
305     // set font color
306     Color fontColor = theme->GetSearchButtonTextColor();
307     if (info[1]->IsObject()) {
308         auto param = JSRef<JSObject>::Cast(info[1]);
309 
310         // set button font size, unit FP
311         auto fontSize = param->GetProperty("fontSize");
312         CalcDimension size = theme->GetFontSize();
313         if (ParseJsDimensionVpNG(fontSize, size) && size.Unit() != DimensionUnit::PERCENT &&
314             GreatOrEqual(size.Value(), 0.0)) {
315             ParseJsDimensionFp(fontSize, size);
316         } else {
317             size = theme->GetFontSize();
318         }
319         SearchModel::GetInstance()->SetSearchButtonFontSize(size);
320 
321         auto fontColorProp = param->GetProperty("fontColor");
322         if (fontColorProp->IsUndefined() || fontColorProp->IsNull() || !ParseJsColor(fontColorProp, fontColor)) {
323             if (!JSSeacrhTheme::ObtainSearchButtonFontColor(fontColor)) {
324                 SearchModel::GetInstance()->SetSearchButtonFontColor(fontColor);
325             }
326         } else {
327             SearchModel::GetInstance()->SetSearchButtonFontColor(fontColor);
328         }
329     } else {
330         SearchModel::GetInstance()->SetSearchButtonFontSize(theme->GetFontSize());
331         if (!JSSeacrhTheme::ObtainSearchButtonFontColor(fontColor)) {
332             SearchModel::GetInstance()->SetSearchButtonFontColor(fontColor);
333         }
334     }
335 }
336 
SetSearchIcon(const JSCallbackInfo& info)337 void JSSearch::SetSearchIcon(const JSCallbackInfo& info)
338 {
339     if (info[0]->IsUndefined() || info[0]->IsNull()) {
340         SetSearchDefaultIcon();
341         return;
342     }
343     if (info[0]->IsObject()) {
344         auto param = JSRef<JSObject>::Cast(info[0]);
345         bool isSymbolIcon = param->HasProperty("fontColor"); // only SymbolGlyph has fontColor property
346         if (isSymbolIcon) {
347             SetSearchSymbolIcon(info);
348         } else {
349             SetSearchImageIcon(info);
350         }
351     }
352 }
353 
SetCancelDefaultIcon()354 void JSSearch::SetCancelDefaultIcon()
355 {
356     SearchModel::GetInstance()->SetCancelDefaultIcon();
357 }
358 
SetCancelSymbolIcon(const JSCallbackInfo& info)359 void JSSearch::SetCancelSymbolIcon(const JSCallbackInfo& info)
360 {
361     if (info[0]->IsObject()) {
362         std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
363         auto param = JSRef<JSObject>::Cast(info[0]);
364         auto iconProp = param->GetProperty("icon");
365         SetSymbolOptionApply(info, iconSymbol, iconProp);
366         SearchModel::GetInstance()->SetCancelSymbolIcon(iconSymbol);
367     }
368 }
369 
SetCancelImageIcon(const JSCallbackInfo& info)370 void JSSearch::SetCancelImageIcon(const JSCallbackInfo& info)
371 {
372     if (!info[0]->IsObject()) {
373         return;
374     }
375     auto param = JSRef<JSObject>::Cast(info[0]);
376     auto theme = GetTheme<SearchTheme>();
377     CHECK_NULL_VOID(theme);
378     auto iconJsVal = param->GetProperty("icon");
379     if (!iconJsVal->IsObject()) {
380         return;
381     }
382     auto iconParam = JSRef<JSObject>::Cast(iconJsVal);
383 
384     // set icon size
385     CalcDimension iconSize;
386     auto iconSizeProp = iconParam->GetProperty("size");
387     if (!iconSizeProp->IsUndefined() && !iconSizeProp->IsNull() && ParseJsDimensionVpNG(iconSizeProp, iconSize)) {
388         if (LessNotEqual(iconSize.Value(), 0.0) || iconSize.Unit() == DimensionUnit::PERCENT) {
389             iconSize = theme->GetIconHeight();
390         }
391     } else {
392         iconSize = theme->GetIconHeight();
393     }
394 
395     // set icon src
396     std::string iconSrc;
397     auto iconSrcProp = iconParam->GetProperty("src");
398     if (iconSrcProp->IsUndefined() || iconSrcProp->IsNull() || !ParseJsMedia(iconSrcProp, iconSrc)) {
399         iconSrc = "";
400     }
401 
402     // set icon color
403     Color iconColor = theme->GetSearchIconColor();
404     auto iconColorProp = iconParam->GetProperty("color");
405     if (!iconColorProp->IsUndefined() && !iconColorProp->IsNull() && ParseJsColor(iconColorProp, iconColor)) {
406         NG::IconOptions cancelIconOptions = NG::IconOptions(iconColor, iconSize, iconSrc, "", "");
407         SearchModel::GetInstance()->SetCancelImageIcon(cancelIconOptions);
408     } else {
409         NG::IconOptions cancelIconOptions = NG::IconOptions(iconSize, iconSrc, "", "");
410         SearchModel::GetInstance()->SetCancelImageIcon(cancelIconOptions);
411     }
412 }
413 
SetSearchDefaultIcon()414 void JSSearch::SetSearchDefaultIcon()
415 {
416     SearchModel::GetInstance()->SetSearchDefaultIcon();
417 }
418 
SetSearchSymbolIcon(const JSCallbackInfo& info)419 void JSSearch::SetSearchSymbolIcon(const JSCallbackInfo& info)
420 {
421     if (!info[0]->IsObject()) {
422         return;
423     }
424 
425     std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
426     SetSymbolOptionApply(info, iconSymbol, info[0]);
427     SearchModel::GetInstance()->SetSearchSymbolIcon(iconSymbol);
428 }
429 
SetSearchImageIcon(const JSCallbackInfo& info)430 void JSSearch::SetSearchImageIcon(const JSCallbackInfo& info)
431 {
432     if (!info[0]->IsObject()) {
433         return;
434     }
435     auto param = JSRef<JSObject>::Cast(info[0]);
436     auto theme = GetTheme<SearchTheme>();
437     CHECK_NULL_VOID(theme);
438 
439     // set icon size
440     CalcDimension size;
441     auto sizeProp = param->GetProperty("size");
442     if (!sizeProp->IsUndefined() && !sizeProp->IsNull() && ParseJsDimensionVpNG(sizeProp, size)) {
443         if (LessNotEqual(size.Value(), 0.0) || size.Unit() == DimensionUnit::PERCENT) {
444             size = theme->GetIconHeight();
445         }
446     } else {
447         size = theme->GetIconHeight();
448     }
449 
450     // set icon src
451     std::string src;
452     auto srcPathProp = param->GetProperty("src");
453     if (srcPathProp->IsUndefined() || srcPathProp->IsNull() || !ParseJsMedia(srcPathProp, src)) {
454         src = "";
455     }
456     // set icon color
457     Color colorVal = theme->GetSearchIconColor();
458     auto colorProp = param->GetProperty("color");
459     if (!colorProp->IsUndefined() && !colorProp->IsNull()) {
460         ParseJsColor(colorProp, colorVal);
461     }
462 
463     std::string bundleName;
464     std::string moduleName;
465     GetJsMediaBundleInfo(srcPathProp, bundleName, moduleName);
466     NG::IconOptions searchIconOptions = NG::IconOptions(colorVal, size, src, bundleName, moduleName);
467     SearchModel::GetInstance()->SetSearchImageIcon(searchIconOptions);
468 }
469 
ConvertStrToCancelButtonStyle(const std::string& value)470 static CancelButtonStyle ConvertStrToCancelButtonStyle(const std::string& value)
471 {
472     if (value == "CONSTANT") {
473         return CancelButtonStyle::CONSTANT;
474     } else if (value == "INVISIBLE") {
475         return CancelButtonStyle::INVISIBLE;
476     } else {
477         return CancelButtonStyle::INPUT;
478     }
479 }
480 
SetCancelButton(const JSCallbackInfo& info)481 void JSSearch::SetCancelButton(const JSCallbackInfo& info)
482 {
483     if (!info[0]->IsObject()) {
484         return;
485     }
486     auto param = JSRef<JSObject>::Cast(info[0]);
487     auto theme = GetTheme<SearchTheme>();
488     CHECK_NULL_VOID(theme);
489 
490     // set style
491     std::string styleStr;
492     CancelButtonStyle cancelButtonStyle;
493     auto styleProp = param->GetProperty("style");
494     if (!styleProp->IsUndefined() && !styleProp->IsNull() && ParseJsString(styleProp, styleStr)) {
495         cancelButtonStyle = ConvertStrToCancelButtonStyle(styleStr);
496     } else {
497         cancelButtonStyle = theme->GetCancelButtonStyle();
498     }
499     SearchModel::GetInstance()->SetCancelButtonStyle(cancelButtonStyle);
500 
501     auto iconProp = param->GetProperty("icon");
502     if (iconProp->IsUndefined() || iconProp->IsNull()) {
503         SetCancelDefaultIcon();
504     } else {
505         SetIconStyle(info);
506     }
507 }
508 
SetIconStyle(const JSCallbackInfo& info)509 void JSSearch::SetIconStyle(const JSCallbackInfo& info)
510 {
511     if (!info[0]->IsObject()) {
512         return;
513     }
514 
515     auto param = JSRef<JSObject>::Cast(info[0]);
516     auto iconJsVal = param->GetProperty("icon");
517     if (!iconJsVal->IsObject()) {
518         return;
519     }
520 
521     auto iconParam = JSRef<JSObject>::Cast(iconJsVal);
522     bool isSymbolIcon = iconParam->HasProperty("fontColor"); // only SymbolGlyph has fontColor property
523     if (isSymbolIcon) {
524         SetCancelSymbolIcon(info);
525     } else {
526         SetCancelImageIcon(info);
527     }
528 }
529 
SetTextColor(const JSCallbackInfo& info)530 void JSSearch::SetTextColor(const JSCallbackInfo& info)
531 {
532     auto theme = GetTheme<SearchTheme>();
533     CHECK_NULL_VOID(theme);
534 
535     auto value = JSRef<JSVal>::Cast(info[0]);
536     Color colorVal;
537     if (!ParseJsColor(value, colorVal)) {
538         colorVal = theme->GetTextColor();
539     }
540     SearchModel::GetInstance()->SetTextColor(colorVal);
541 }
542 
SetCaret(const JSCallbackInfo& info)543 void JSSearch::SetCaret(const JSCallbackInfo& info)
544 {
545     if (info[0]->IsObject()) {
546         auto param = JSRef<JSObject>::Cast(info[0]);
547         auto textFieldTheme = GetTheme<TextFieldTheme>();
548         CHECK_NULL_VOID(textFieldTheme);
549 
550         // set caret width
551         CalcDimension caretWidth = textFieldTheme->GetCursorWidth();
552         auto caretWidthProp = param->GetProperty("width");
553         if (!ParseJsDimensionVpNG(caretWidthProp, caretWidth, false) || LessNotEqual(caretWidth.Value(), 0.0)) {
554             caretWidth = textFieldTheme->GetCursorWidth();
555         }
556         SearchModel::GetInstance()->SetCaretWidth(caretWidth);
557 
558         // set caret color
559         Color caretColor;
560         auto caretColorProp = param->GetProperty("color");
561         if (caretColorProp->IsUndefined() || caretColorProp->IsNull() || !ParseJsColor(caretColorProp, caretColor)) {
562             caretColor = textFieldTheme->GetCursorColor();
563         }
564         SearchModel::GetInstance()->SetCaretColor(caretColor);
565     }
566 }
567 
SetInputFilter(const JSCallbackInfo& info)568 void JSSearch::SetInputFilter(const JSCallbackInfo& info)
569 {
570     if (info.Length() < 1) {
571         return;
572     }
573     auto tmpInfo = info[0];
574     auto errInfo = info[1];
575     std::string inputFilter;
576     if (tmpInfo->IsUndefined()) {
577         SearchModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
578         return;
579     }
580     if (!ParseJsString(tmpInfo, inputFilter)) {
581         return;
582     }
583     if (!CheckRegexValid(inputFilter)) {
584         inputFilter = "";
585     }
586     if (info.Length() > 1 && errInfo->IsFunction()) {
587         auto jsFunc = AceType::MakeRefPtr<JsClipboardFunction>(JSRef<JSFunc>::Cast(errInfo));
588         auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
589         auto resultId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
590                             const std::string& info) {
591             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
592             PipelineContext::SetCallBackNode(node);
593             func->Execute(info);
594         };
595         SearchModel::GetInstance()->SetInputFilter(inputFilter, resultId);
596         return;
597     }
598     SearchModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
599 }
600 
SetOnEditChange(const JSCallbackInfo& info)601 void JSSearch::SetOnEditChange(const JSCallbackInfo& info)
602 {
603     auto tmpInfo = info[0];
604     CHECK_NULL_VOID(tmpInfo->IsFunction());
605     JsEventCallback<void(bool)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(tmpInfo));
606     SearchModel::GetInstance()->SetOnEditChanged(std::move(callback));
607 }
608 
SetTextIndent(const JSCallbackInfo& info)609 void JSSearch::SetTextIndent(const JSCallbackInfo& info)
610 {
611     CalcDimension value;
612     if (!ParseJsDimensionVpNG(info[0], value, true)) {
613         value.Reset();
614     }
615     SearchModel::GetInstance()->SetTextIndent(value);
616 }
617 
SetPlaceholderColor(const JSCallbackInfo& info)618 void JSSearch::SetPlaceholderColor(const JSCallbackInfo& info)
619 {
620     auto value = JSRef<JSVal>::Cast(info[0]);
621     Color colorVal;
622     if (!ParseJsColor(value, colorVal)) {
623         auto theme = GetTheme<SearchTheme>();
624         CHECK_NULL_VOID(theme);
625         colorVal = theme->GetPlaceholderColor();
626     }
627     SearchModel::GetInstance()->SetPlaceholderColor(colorVal);
628 }
629 
SetPlaceholderFont(const JSCallbackInfo& info)630 void JSSearch::SetPlaceholderFont(const JSCallbackInfo& info)
631 {
632     if (!info[0]->IsObject()) {
633         return;
634     }
635     auto param = JSRef<JSObject>::Cast(info[0]);
636     auto theme = GetTheme<SearchTheme>();
637     CHECK_NULL_VOID(theme);
638     auto themeFontSize = theme->GetFontSize();
639     Font font;
640     auto fontSize = param->GetProperty("size");
641     if (fontSize->IsNull() || fontSize->IsUndefined()) {
642         font.fontSize = themeFontSize;
643     } else {
644         auto versionTenOrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
645         CalcDimension size;
646         if ((versionTenOrLarger ? ParseJsDimensionVpNG(fontSize, size) : ParseJsDimensionVp(fontSize, size)) &&
647             size.Unit() != DimensionUnit::PERCENT) {
648             ParseJsDimensionFp(fontSize, size);
649             font.fontSize = size;
650         } else {
651             font.fontSize = themeFontSize;
652         }
653     }
654 
655     auto weight = param->GetProperty("weight");
656     if (!weight->IsNull()) {
657         std::string weightVal;
658         if (weight->IsNumber()) {
659             weightVal = std::to_string(weight->ToNumber<int32_t>());
660         } else {
661             ParseJsString(weight, weightVal);
662         }
663         font.fontWeight = ConvertStrToFontWeight(weightVal);
664     }
665 
666     auto family = param->GetProperty("family");
667     if (!family->IsNull() && family->IsString()) {
668         auto familyVal = family->ToString();
669         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
670     }
671 
672     auto style = param->GetProperty("style");
673     if (!style->IsNull() && style->IsNumber()) {
674         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
675         font.fontStyle = styleVal;
676     }
677     SearchModel::GetInstance()->SetPlaceholderFont(font);
678 }
679 
SetTextFont(const JSCallbackInfo& info)680 void JSSearch::SetTextFont(const JSCallbackInfo& info)
681 {
682     auto theme = GetTheme<SearchTheme>();
683     CHECK_NULL_VOID(theme);
684     auto themeFontSize = theme->GetFontSize();
685     auto themeFontWeight = theme->GetFontWeight();
686     Font font { .fontWeight = themeFontWeight, .fontSize = themeFontSize, .fontStyle = Ace::FontStyle::NORMAL };
687     if (info.Length() < 1 || !info[0]->IsObject()) {
688         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
689             SearchModel::GetInstance()->SetTextFont(font);
690         }
691         return;
692     }
693     auto param = JSRef<JSObject>::Cast(info[0]);
694     auto fontSize = param->GetProperty("size");
695     CalcDimension size = themeFontSize;
696     if (ParseJsDimensionVpNG(fontSize, size) && size.Unit() != DimensionUnit::PERCENT &&
697         GreatOrEqual(size.Value(), 0.0)) {
698         ParseJsDimensionFp(fontSize, size);
699     } else {
700         size = themeFontSize;
701     }
702     font.fontSize = size;
703 
704     auto weight = param->GetProperty("weight");
705     if (!weight->IsNull()) {
706         std::string weightVal;
707         if (weight->IsNumber()) {
708             weightVal = std::to_string(weight->ToNumber<int32_t>());
709         } else {
710             ParseJsString(weight, weightVal);
711         }
712         font.fontWeight = ConvertStrToFontWeight(weightVal);
713     }
714 
715     auto family = param->GetProperty("family");
716     if (!family->IsNull() && family->IsString()) {
717         auto familyVal = family->ToString();
718         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
719     }
720 
721     auto style = param->GetProperty("style");
722     if (!style->IsNull() && style->IsNumber()) {
723         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
724         font.fontStyle = styleVal;
725     }
726     SearchModel::GetInstance()->SetTextFont(font);
727 }
728 
SetTextAlign(int32_t value)729 void JSSearch::SetTextAlign(int32_t value)
730 {
731     if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
732         SearchModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
733     }
734 }
735 
JsBorder(const JSCallbackInfo& info)736 void JSSearch::JsBorder(const JSCallbackInfo& info)
737 {
738     if (!info[0]->IsObject()) {
739         CalcDimension borderWidth;
740         ViewAbstractModel::GetInstance()->SetBorderWidth(borderWidth);
741         ViewAbstractModel::GetInstance()->SetBorderColor(Color::BLACK);
742         ViewAbstractModel::GetInstance()->SetBorderRadius(borderWidth);
743         ViewAbstractModel::GetInstance()->SetBorderStyle(BorderStyle::SOLID);
744         ViewAbstractModel::GetInstance()->SetDashGap(Dimension(-1));
745         ViewAbstractModel::GetInstance()->SetDashWidth(Dimension(-1));
746         return;
747     }
748     JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
749 
750     auto valueWidth = object->GetProperty(static_cast<int32_t>(ArkUIIndex::WIDTH));
751     if (!valueWidth->IsUndefined()) {
752         JSViewAbstract::ParseBorderWidth(valueWidth);
753     }
754 
755     // use default value when undefined.
756     JSViewAbstract::ParseBorderColor(object->GetProperty(static_cast<int32_t>(ArkUIIndex::COLOR)));
757 
758     auto valueRadius = object->GetProperty(static_cast<int32_t>(ArkUIIndex::RADIUS));
759     if (!valueRadius->IsUndefined()) {
760         ParseBorderRadius(valueRadius);
761         SearchModel::GetInstance()->SetBackBorderRadius();
762     }
763     // use default value when undefined.
764     JSViewAbstract::ParseBorderStyle(object->GetProperty(static_cast<int32_t>(ArkUIIndex::STYLE)));
765 
766     auto dashGap = object->GetProperty("dashGap");
767     if (!dashGap->IsUndefined()) {
768         JSViewAbstract::ParseDashGap(dashGap);
769     }
770     auto dashWidth = object->GetProperty("dashWidth");
771     if (!dashWidth->IsUndefined()) {
772         JSViewAbstract::ParseDashWidth(dashWidth);
773     }
774 
775     SearchModel::GetInstance()->SetBackBorder();
776     info.ReturnSelf();
777 }
778 
JsBorderWidth(const JSCallbackInfo& info)779 void JSSearch::JsBorderWidth(const JSCallbackInfo& info)
780 {
781     JSViewAbstract::JsBorderWidth(info);
782     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
783         return;
784     }
785     SearchModel::GetInstance()->SetBackBorder();
786 }
787 
JsBorderColor(const JSCallbackInfo& info)788 void JSSearch::JsBorderColor(const JSCallbackInfo& info)
789 {
790     JSViewAbstract::JsBorderColor(info);
791     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
792         return;
793     }
794     SearchModel::GetInstance()->SetBackBorder();
795 }
796 
JsBorderStyle(const JSCallbackInfo& info)797 void JSSearch::JsBorderStyle(const JSCallbackInfo& info)
798 {
799     JSViewAbstract::JsBorderStyle(info);
800     if (!info[0]->IsObject() && !info[0]->IsNumber()) {
801         return;
802     }
803     SearchModel::GetInstance()->SetBackBorder();
804 }
805 
GetBorderRadiusByLengthMetrics(const char* key, JSRef<JSObject>& object, std::optional<CalcDimension>& radius)806 void JSSearch::GetBorderRadiusByLengthMetrics(const char* key, JSRef<JSObject>& object,
807     std::optional<CalcDimension>& radius)
808 {
809     if (object->HasProperty(key) && object->GetProperty(key)->IsObject()) {
810         JSRef<JSObject> startObj = JSRef<JSObject>::Cast(object->GetProperty(key));
811         CalcDimension value;
812         ParseJsLengthMetrics(startObj, value);
813         radius = value;
814     }
815 }
816 
ParseAllBorderRadiuses(JSRef<JSObject>& object, CalcDimension& topLeft, CalcDimension& topRight, CalcDimension& bottomLeft, CalcDimension& bottomRight)817 bool JSSearch::ParseAllBorderRadiuses(JSRef<JSObject>& object, CalcDimension& topLeft,
818     CalcDimension& topRight, CalcDimension& bottomLeft, CalcDimension& bottomRight)
819 {
820     if (object->HasProperty(TOP_START_PROPERTY) || object->HasProperty(TOP_END_PROPERTY) ||
821         object->HasProperty(BOTTOM_START_PROPERTY) || object->HasProperty(BOTTOM_END_PROPERTY)) {
822         std::optional<CalcDimension> topStart;
823         std::optional<CalcDimension> topEnd;
824         std::optional<CalcDimension> bottomStart;
825         std::optional<CalcDimension> bottomEnd;
826         GetBorderRadiusByLengthMetrics(TOP_START_PROPERTY, object, topStart);
827         GetBorderRadiusByLengthMetrics(TOP_END_PROPERTY, object, topEnd);
828         GetBorderRadiusByLengthMetrics(BOTTOM_START_PROPERTY, object, bottomStart);
829         GetBorderRadiusByLengthMetrics(BOTTOM_END_PROPERTY, object, bottomEnd);
830         topLeft = topStart.has_value() ? topStart.value() : topLeft;
831         topRight = topEnd.has_value() ? topEnd.value() : topRight;
832         bottomLeft = bottomStart.has_value() ? bottomStart.value() : bottomLeft;
833         bottomRight = bottomEnd.has_value() ? bottomEnd.value() : bottomRight;
834         return true;
835     }
836     JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topLeft"), topLeft);
837     JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topRight"), topRight);
838     JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomLeft"), bottomLeft);
839     JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomRight"), bottomRight);
840     return false;
841 }
842 
ParseBorderRadius(const JSRef<JSVal>& args)843 void JSSearch::ParseBorderRadius(const JSRef<JSVal>& args)
844 {
845     CalcDimension borderRadius;
846     if (ParseJsDimensionVp(args, borderRadius)) {
847         ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius);
848     } else if (args->IsObject()) {
849         auto textFieldTheme = GetTheme<TextFieldTheme>();
850         CHECK_NULL_VOID(textFieldTheme);
851         auto borderRadiusTheme = textFieldTheme->GetBorderRadius();
852         NG::BorderRadiusProperty defaultBorderRadius {
853             borderRadiusTheme.GetX(), borderRadiusTheme.GetY(),
854             borderRadiusTheme.GetY(), borderRadiusTheme.GetX(),
855         };
856 
857         JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
858         CalcDimension topLeft = defaultBorderRadius.radiusTopLeft.value();
859         CalcDimension topRight = defaultBorderRadius.radiusTopRight.value();
860         CalcDimension bottomLeft = defaultBorderRadius.radiusBottomLeft.value();
861         CalcDimension bottomRight = defaultBorderRadius.radiusBottomRight.value();
862         if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) {
863             ViewAbstractModel::GetInstance()->SetBorderRadius(
864                 JSViewAbstract::GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
865                 return;
866         }
867         ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
868     }
869 }
870 
JsBorderRadius(const JSCallbackInfo& info)871 void JSSearch::JsBorderRadius(const JSCallbackInfo& info)
872 {
873     auto jsValue = info[0];
874     static std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING,
875         JSCallbackInfoType::NUMBER, JSCallbackInfoType::OBJECT };
876     if (!CheckJSCallbackInfo("JsBorderRadius", jsValue, checkList)) {
877         auto textFieldTheme = GetTheme<TextFieldTheme>();
878         CHECK_NULL_VOID(textFieldTheme);
879         auto borderRadiusTheme = textFieldTheme->GetBorderRadius();
880         NG::BorderRadiusProperty defaultBorderRadius {
881             borderRadiusTheme.GetX(), borderRadiusTheme.GetY(),
882             borderRadiusTheme.GetY(), borderRadiusTheme.GetX(),
883         };
884         ViewAbstractModel::GetInstance()->SetBorderRadius(defaultBorderRadius);
885         return;
886     }
887     ParseBorderRadius(jsValue);
888     SearchModel::GetInstance()->SetBackBorderRadius();
889 }
890 
OnSubmit(const JSCallbackInfo& info)891 void JSSearch::OnSubmit(const JSCallbackInfo& info)
892 {
893     CHECK_NULL_VOID(info[0]->IsFunction());
894     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
895     SearchModel::GetInstance()->SetOnSubmit(std::move(callback));
896 }
897 
CreateJsOnChangeObj(const PreviewText& previewText)898 JSRef<JSVal> JSSearch::CreateJsOnChangeObj(const PreviewText& previewText)
899 {
900     JSRef<JSObject> previewTextObj = JSRef<JSObject>::New();
901     previewTextObj->SetProperty<int32_t>("offset", previewText.offset);
902     previewTextObj->SetProperty<std::string>("value", previewText.value);
903     return JSRef<JSVal>::Cast(previewTextObj);
904 }
905 
OnChange(const JSCallbackInfo& info)906 void JSSearch::OnChange(const JSCallbackInfo& info)
907 {
908     auto jsValue = info[0];
909     CHECK_NULL_VOID(jsValue->IsFunction());
910     auto jsChangeFunc =
911         AceType::MakeRefPtr<JsCitedEventFunction<PreviewText, 2>>(JSRef<JSFunc>::Cast(jsValue), CreateJsOnChangeObj);
912     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsChangeFunc)](
913                         const std::string& val, PreviewText& previewText) {
914         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
915         ACE_SCORING_EVENT("onChange");
916         func->Execute(val, previewText);
917     };
918     SearchModel::GetInstance()->SetOnChange(std::move(onChange));
919 }
920 
SetOnTextSelectionChange(const JSCallbackInfo& info)921 void JSSearch::SetOnTextSelectionChange(const JSCallbackInfo& info)
922 {
923     CHECK_NULL_VOID(info[0]->IsFunction());
924     JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
925     SearchModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
926 }
927 
SetOnScroll(const JSCallbackInfo& info)928 void JSSearch::SetOnScroll(const JSCallbackInfo& info)
929 {
930     CHECK_NULL_VOID(info[0]->IsFunction());
931     JsEventCallback<void(float, float)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
932     SearchModel::GetInstance()->SetOnScroll(std::move(callback));
933 }
934 
SetHeight(const JSCallbackInfo& info)935 void JSSearch::SetHeight(const JSCallbackInfo& info)
936 {
937     JSViewAbstract::JsHeight(info);
938     CalcDimension value;
939     auto versionTenOrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN);
940     if (versionTenOrLarger ? !ParseJsDimensionVpNG(info[0], value) : !ParseJsDimensionVp(info[0], value)) {
941         return;
942     }
943     if (LessNotEqual(value.Value(), 0.0)) {
944         value.SetValue(0.0);
945     }
946     SearchModel::GetInstance()->SetHeight(value);
947 }
948 
SetOnCopy(const JSCallbackInfo& info)949 void JSSearch::SetOnCopy(const JSCallbackInfo& info)
950 {
951     CHECK_NULL_VOID(info[0]->IsFunction());
952     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
953     SearchModel::GetInstance()->SetOnCopy(std::move(callback));
954 }
955 
SetOnCut(const JSCallbackInfo& info)956 void JSSearch::SetOnCut(const JSCallbackInfo& info)
957 {
958     CHECK_NULL_VOID(info[0]->IsFunction());
959     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
960     SearchModel::GetInstance()->SetOnCut(std::move(callback));
961 }
962 
CreateJSTextCommonEvent(NG::TextCommonEvent& event)963 JSRef<JSVal> JSSearch::CreateJSTextCommonEvent(NG::TextCommonEvent& event)
964 {
965     JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
966     objectTemplate->SetInternalFieldCount(1);
967     JSRef<JSObject> object = objectTemplate->NewInstance();
968     object->SetPropertyObject("preventDefault", JSRef<JSFunc>::New<FunctionCallback>(JsPreventDefault));
969     object->Wrap<NG::TextCommonEvent>(&event);
970     return JSRef<JSVal>::Cast(object);
971 }
972 
SetOnPaste(const JSCallbackInfo& info)973 void JSSearch::SetOnPaste(const JSCallbackInfo& info)
974 {
975     CHECK_NULL_VOID(info[0]->IsFunction());
976     auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 2>>(
977         JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
978 
979     auto onPaste = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc)](
980                        const std::string& val, NG::TextCommonEvent& info) {
981         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
982         ACE_SCORING_EVENT("onPaste");
983         func->Execute(val, info);
984 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
985         UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onPaste");
986 #endif
987     };
988     SearchModel::GetInstance()->SetOnPasteWithEvent(std::move(onPaste));
989 }
990 
SetCopyOption(const JSCallbackInfo& info)991 void JSSearch::SetCopyOption(const JSCallbackInfo& info)
992 {
993     if (info.Length() == 0) {
994         return;
995     }
996     if (info[0]->IsUndefined()) {
997         SearchModel::GetInstance()->SetCopyOption(CopyOptions::Local);
998         return;
999     }
1000     auto copyOptions = CopyOptions::Local;
1001     if (info[0]->IsNumber()) {
1002         auto emunNumber = info[0]->ToNumber<int>();
1003         copyOptions = static_cast<CopyOptions>(emunNumber);
1004     }
1005     SearchModel::GetInstance()->SetCopyOption(copyOptions);
1006 }
1007 
CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue)1008 JSRef<JSVal> JSSearch::CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue)
1009 {
1010     JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
1011     aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.insertOffset);
1012     aboutToIMEInputObj->SetProperty<std::string>("insertValue", insertValue.insertValue);
1013     return JSRef<JSVal>::Cast(aboutToIMEInputObj);
1014 }
1015 
OnWillInsertValue(const JSCallbackInfo& info)1016 void JSSearch::OnWillInsertValue(const JSCallbackInfo& info)
1017 {
1018     auto jsValue = info[0];
1019     CHECK_NULL_VOID(jsValue->IsFunction());
1020     auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<InsertValueInfo, 1>>(
1021         JSRef<JSFunc>::Cast(jsValue), CreateJsAboutToIMEInputObj);
1022     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1023                         const InsertValueInfo& insertValue) -> bool {
1024         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
1025         auto ret = func->ExecuteWithValue(insertValue);
1026         if (ret->IsBoolean()) {
1027             return ret->ToBoolean();
1028         }
1029         return true;
1030     };
1031     SearchModel::GetInstance()->SetOnWillInsertValueEvent(std::move(callback));
1032 }
1033 
CreateJsDeleteToIMEObj(const DeleteValueInfo& deleteValueInfo)1034 JSRef<JSVal> JSSearch::CreateJsDeleteToIMEObj(const DeleteValueInfo& deleteValueInfo)
1035 {
1036     JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
1037     aboutToIMEInputObj->SetProperty<int32_t>("deleteOffset", deleteValueInfo.deleteOffset);
1038     aboutToIMEInputObj->SetProperty<int32_t>("direction", static_cast<int32_t>(deleteValueInfo.direction));
1039     aboutToIMEInputObj->SetProperty<std::string>("deleteValue", deleteValueInfo.deleteValue);
1040     return JSRef<JSVal>::Cast(aboutToIMEInputObj);
1041 }
1042 
OnDidInsertValue(const JSCallbackInfo& info)1043 void JSSearch::OnDidInsertValue(const JSCallbackInfo& info)
1044 {
1045     auto jsValue = info[0];
1046     CHECK_NULL_VOID(jsValue->IsFunction());
1047     auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<InsertValueInfo, 1>>(
1048         JSRef<JSFunc>::Cast(jsValue), CreateJsAboutToIMEInputObj);
1049     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1050                         const InsertValueInfo& insertValue) {
1051         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1052         func->ExecuteWithValue(insertValue);
1053     };
1054     SearchModel::GetInstance()->SetOnDidInsertValueEvent(std::move(callback));
1055 }
1056 
OnWillDelete(const JSCallbackInfo& info)1057 void JSSearch::OnWillDelete(const JSCallbackInfo& info)
1058 {
1059     auto jsValue = info[0];
1060     CHECK_NULL_VOID(jsValue->IsFunction());
1061     auto jsAboutToIMEInputFunc =
1062         AceType::MakeRefPtr<JsEventFunction<DeleteValueInfo, 1>>(JSRef<JSFunc>::Cast(jsValue), CreateJsDeleteToIMEObj);
1063     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1064                         const DeleteValueInfo& deleteValue) {
1065         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
1066         auto ret = func->ExecuteWithValue(deleteValue);
1067         if (ret->IsBoolean()) {
1068             return ret->ToBoolean();
1069         }
1070         return true;
1071     };
1072     SearchModel::GetInstance()->SetOnWillDeleteEvent(std::move(callback));
1073 }
1074 
OnDidDelete(const JSCallbackInfo& info)1075 void JSSearch::OnDidDelete(const JSCallbackInfo& info)
1076 {
1077     auto jsValue = info[0];
1078     CHECK_NULL_VOID(jsValue->IsFunction());
1079     auto jsAboutToIMEInputFunc =
1080         AceType::MakeRefPtr<JsEventFunction<DeleteValueInfo, 1>>(JSRef<JSFunc>::Cast(jsValue), CreateJsDeleteToIMEObj);
1081     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1082                         const DeleteValueInfo& deleteValue) {
1083         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1084         func->ExecuteWithValue(deleteValue);
1085     };
1086     SearchModel::GetInstance()->SetOnDidDeleteEvent(std::move(callback));
1087 }
1088 
SetSelectionMenuHidden(const JSCallbackInfo& info)1089 void JSSearch::SetSelectionMenuHidden(const JSCallbackInfo& info)
1090 {
1091     if (info[0]->IsUndefined() || !info[0]->IsBoolean()) {
1092         SearchModel::GetInstance()->SetSelectionMenuHidden(false);
1093         return;
1094     }
1095     SearchModel::GetInstance()->SetSelectionMenuHidden(info[0]->ToBoolean());
1096 }
1097 
SetCustomKeyboard(const JSCallbackInfo& info)1098 void JSSearch::SetCustomKeyboard(const JSCallbackInfo& info)
1099 {
1100     if (info.Length() > 0 && (info[0]->IsUndefined() || info[0]->IsNull())) {
1101         SearchModel::GetInstance()->SetCustomKeyboard(nullptr);
1102         return;
1103     }
1104     if (info.Length() < 1 || !info[0]->IsObject()) {
1105         return;
1106     }
1107     bool supportAvoidance = false;
1108     if (info.Length() == 2 && info[1]->IsObject()) { //  2 here refers to the number of parameters
1109         auto paramObject = JSRef<JSObject>::Cast(info[1]);
1110         auto isSupportAvoidance = paramObject->GetProperty("supportAvoidance");
1111         if (!isSupportAvoidance->IsNull() && isSupportAvoidance->IsBoolean()) {
1112             supportAvoidance = isSupportAvoidance->ToBoolean();
1113         }
1114     }
1115     std::function<void()> buildFunc;
1116     if (JSTextField::ParseJsCustomKeyboardBuilder(info, 0, buildFunc)) {
1117         SearchModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance);
1118     }
1119 }
1120 
SetType(const JSCallbackInfo& info)1121 void JSSearch::SetType(const JSCallbackInfo& info)
1122 {
1123     if (info.Length() < 1) {
1124         return;
1125     }
1126     if (info[0]->IsUndefined()) {
1127         SearchModel::GetInstance()->SetType(TextInputType::UNSPECIFIED);
1128         return;
1129     }
1130     if (!info[0]->IsNumber()) {
1131         return;
1132     }
1133     TextInputType textInputType = CastToTextInputType(info[0]->ToNumber<int32_t>());
1134     SearchModel::GetInstance()->SetType(textInputType);
1135 }
1136 
JSBind(BindingTarget globalObj)1137 void JSSearchController::JSBind(BindingTarget globalObj)
1138 {
1139     JSClass<JSTextEditableController>::Declare("SearchController");
1140     JSTextEditableController::JSBind(globalObj);
1141 }
1142 
SetEnterKeyType(const JSCallbackInfo& info)1143 void JSSearch::SetEnterKeyType(const JSCallbackInfo& info)
1144 {
1145     if (info.Length() < 1) {
1146         return;
1147     }
1148     if (info[0]->IsUndefined()) {
1149         SearchModel::GetInstance()->SetSearchEnterKeyType(TextInputAction::SEARCH);
1150         return;
1151     }
1152     if (!info[0]->IsNumber()) {
1153         return;
1154     }
1155     TextInputAction textInputAction = CastToTextInputAction(info[0]->ToNumber<int32_t>());
1156     SearchModel::GetInstance()->SetSearchEnterKeyType(textInputAction);
1157 }
1158 
SetMaxLength(const JSCallbackInfo& info)1159 void JSSearch::SetMaxLength(const JSCallbackInfo& info)
1160 {
1161     int32_t maxLength = 0;
1162     if (info[0]->IsUndefined()) {
1163         SearchModel::GetInstance()->ResetMaxLength();
1164         return;
1165     } else if (!info[0]->IsNumber()) {
1166         SearchModel::GetInstance()->ResetMaxLength();
1167         return;
1168     }
1169     maxLength = info[0]->ToNumber<int32_t>();
1170     if (std::isinf(info[0]->ToNumber<float>())) {
1171         maxLength = INT32_MAX; // Infinity
1172     }
1173     if (GreatOrEqual(maxLength, 0)) {
1174         SearchModel::GetInstance()->SetMaxLength(maxLength);
1175     } else {
1176         SearchModel::GetInstance()->ResetMaxLength();
1177     }
1178 }
1179 
SetDecoration(const JSCallbackInfo& info)1180 void JSSearch::SetDecoration(const JSCallbackInfo& info)
1181 {
1182     do {
1183         auto tmpInfo = info[0];
1184         if (!tmpInfo->IsObject()) {
1185             SearchModel::GetInstance()->SetTextDecoration(TextDecoration::NONE);
1186             SearchModel::GetInstance()->SetTextDecorationColor(Color::BLACK);
1187             SearchModel::GetInstance()->SetTextDecorationStyle(TextDecorationStyle::SOLID);
1188             break;
1189         }
1190         JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
1191         JSRef<JSVal> typeValue = obj->GetProperty("type");
1192         JSRef<JSVal> colorValue = obj->GetProperty("color");
1193         JSRef<JSVal> styleValue = obj->GetProperty("style");
1194 
1195         auto pipelineContext = PipelineBase::GetCurrentContext();
1196         CHECK_NULL_VOID(pipelineContext);
1197         auto theme = pipelineContext->GetTheme<SearchTheme>();
1198         CHECK_NULL_VOID(theme);
1199         TextDecoration textDecoration = theme->GetTextStyle().GetTextDecoration();
1200         if (typeValue->IsNumber()) {
1201             textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
1202         }
1203         Color result = theme->GetTextStyle().GetTextDecorationColor();
1204         ParseJsColor(colorValue, result, Color::BLACK);
1205         std::optional<TextDecorationStyle> textDecorationStyle;
1206         if (styleValue->IsNumber()) {
1207             textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
1208         } else {
1209             textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE;
1210         }
1211         SearchModel::GetInstance()->SetTextDecoration(textDecoration);
1212         SearchModel::GetInstance()->SetTextDecorationColor(result);
1213         if (textDecorationStyle) {
1214             SearchModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
1215         }
1216     } while (false);
1217 }
1218 
SetMinFontSize(const JSCallbackInfo& info)1219 void JSSearch::SetMinFontSize(const JSCallbackInfo& info)
1220 {
1221     if (info.Length() < 1) {
1222         return;
1223     }
1224     CalcDimension minFontSize;
1225     if (!ParseJsDimensionFpNG(info[0], minFontSize, false)) {
1226         SearchModel::GetInstance()->SetAdaptMinFontSize(CalcDimension());
1227         return;
1228     }
1229     if (minFontSize.IsNegative()) {
1230         minFontSize = CalcDimension();
1231     }
1232     SearchModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
1233 }
1234 
SetMaxFontSize(const JSCallbackInfo& info)1235 void JSSearch::SetMaxFontSize(const JSCallbackInfo& info)
1236 {
1237     if (info.Length() < 1) {
1238         return;
1239     }
1240     auto pipelineContext = PipelineBase::GetCurrentContext();
1241     CHECK_NULL_VOID(pipelineContext);
1242     auto theme = pipelineContext->GetTheme<SearchTheme>();
1243     CHECK_NULL_VOID(theme);
1244     CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1245     if (!ParseJsDimensionFpNG(info[0], maxFontSize, false)) {
1246         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1247         SearchModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
1248         return;
1249     }
1250     if (maxFontSize.IsNegative()) {
1251         maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1252     }
1253     SearchModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
1254 }
1255 
SetLetterSpacing(const JSCallbackInfo& info)1256 void JSSearch::SetLetterSpacing(const JSCallbackInfo& info)
1257 {
1258     CalcDimension value;
1259     if (!ParseJsDimensionFpNG(info[0], value, false)) {
1260         value.Reset();
1261         SearchModel::GetInstance()->SetLetterSpacing(value);
1262         return;
1263     }
1264     SearchModel::GetInstance()->SetLetterSpacing(value);
1265 }
1266 
SetLineHeight(const JSCallbackInfo& info)1267 void JSSearch::SetLineHeight(const JSCallbackInfo& info)
1268 {
1269     CalcDimension value;
1270     if (!ParseJsDimensionFpNG(info[0], value)) {
1271         value.Reset();
1272         SearchModel::GetInstance()->SetLineHeight(value);
1273         return;
1274     }
1275     if (value.IsNegative()) {
1276         value.Reset();
1277     }
1278     SearchModel::GetInstance()->SetLineHeight(value);
1279 }
1280 
EditMenuOptions(const JSCallbackInfo& info)1281 void JSSearch::EditMenuOptions(const JSCallbackInfo& info)
1282 {
1283     NG::OnCreateMenuCallback onCreateMenuCallback;
1284     NG::OnMenuItemClickCallback onMenuItemClick;
1285     JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
1286     SearchModel::GetInstance()->SetSelectionMenuOptions(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
1287 }
1288 
SetEnablePreviewText(const JSCallbackInfo& info)1289 void JSSearch::SetEnablePreviewText(const JSCallbackInfo& info)
1290 {
1291     auto jsValue = info[0];
1292     if (!jsValue->IsBoolean()) {
1293         SearchModel::GetInstance()->SetEnablePreviewText(true);
1294         return;
1295     }
1296     SearchModel::GetInstance()->SetEnablePreviewText(jsValue->ToBoolean());
1297 }
1298 
SetEnableHapticFeedback(const JSCallbackInfo& info)1299 void JSSearch::SetEnableHapticFeedback(const JSCallbackInfo& info)
1300 {
1301     bool state = true;
1302     if (info.Length() > 0 && info[0]->IsBoolean()) {
1303         state = info[0]->ToBoolean();
1304     }
1305     SearchModel::GetInstance()->SetEnableHapticFeedback(state);
1306 }
1307 } // namespace OHOS::Ace::Framework
1308