/* * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "bridge/declarative_frontend/jsview/js_search.h" #include #include #include "interfaces/inner_api/ui_session/ui_session_manager.h" #include "base/log/ace_scoring_log.h" #include "bridge/declarative_frontend/engine/functions/js_clipboard_function.h" #include "bridge/declarative_frontend/engine/functions/js_common_event_function.h" #include "bridge/declarative_frontend/engine/functions/js_cited_event_function.h" #include "bridge/declarative_frontend/engine/functions/js_event_function.h" #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h" #include "bridge/declarative_frontend/jsview/js_text_editable_controller.h" #include "bridge/declarative_frontend/jsview/js_textfield.h" #include "bridge/declarative_frontend/jsview/js_textinput.h" #include "bridge/declarative_frontend/jsview/js_view_abstract.h" #include "bridge/declarative_frontend/jsview/js_view_common_def.h" #include "bridge/declarative_frontend/jsview/models/search_model_impl.h" #include "core/components/common/layout/constants.h" #include "core/components/common/properties/text_style_parser.h" #include "core/components/search/search_theme.h" #include "core/components_ng/gestures/gesture_info.h" #include "core/components_ng/pattern/search/search_model_ng.h" #include "core/components_ng/pattern/text_field/text_field_model_ng.h" namespace OHOS::Ace { std::unique_ptr SearchModel::instance_ = nullptr; std::mutex SearchModel::mutex_; SearchModel* SearchModel::GetInstance() { #ifdef NG_BUILD static NG::SearchModelNG instance; return &instance; #else if (Container::IsCurrentUseNewPipeline()) { static NG::SearchModelNG instance; return &instance; } else { static Framework::SearchModelImpl instance; return &instance; } #endif } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { const std::vector TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END }; constexpr double DEFAULT_OPACITY = 0.2; const int32_t DEFAULT_ALPHA = 255; constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID; const char* TOP_START_PROPERTY = "topStart"; const char* TOP_END_PROPERTY = "topEnd"; const char* BOTTOM_START_PROPERTY = "bottomStart"; const char* BOTTOM_END_PROPERTY = "bottomEnd"; bool ParseJsLengthMetrics(const JSRef& obj, CalcDimension& result) { auto value = obj->GetProperty(static_cast(ArkUIIndex::VALUE)); if (!value->IsNumber()) { return false; } auto unit = DimensionUnit::VP; auto jsUnit = obj->GetProperty(static_cast(ArkUIIndex::UNIT)); if (jsUnit->IsNumber()) { unit = static_cast(jsUnit->ToNumber()); } CalcDimension dimension(value->ToNumber(), unit); result = dimension; return true; } } // namespace void JSSearch::JSBind(BindingTarget globalObj) { JSClass::Declare("Search"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSSearch::Create, opt); JSClass::StaticMethod("searchButton", &JSSearch::SetSearchButton, opt); JSClass::StaticMethod("searchIcon", &JSSearch::SetSearchIcon, opt); JSClass::StaticMethod("cancelButton", &JSSearch::SetCancelButton, opt); JSClass::StaticMethod("fontColor", &JSSearch::SetTextColor, opt); JSClass::StaticMethod("backgroundColor", &JSSearch::SetBackgroundColor, opt); JSClass::StaticMethod("caretStyle", &JSSearch::SetCaret, opt); JSClass::StaticMethod("placeholderColor", &JSSearch::SetPlaceholderColor, opt); JSClass::StaticMethod("placeholderFont", &JSSearch::SetPlaceholderFont, opt); JSClass::StaticMethod("textFont", &JSSearch::SetTextFont, opt); JSClass::StaticMethod("textAlign", &JSSearch::SetTextAlign, opt); JSClass::StaticMethod("onSubmit", &JSSearch::OnSubmit, opt); JSClass::StaticMethod("onChange", &JSSearch::OnChange, opt); JSClass::StaticMethod("onTextSelectionChange", &JSSearch::SetOnTextSelectionChange); JSClass::StaticMethod("onContentScroll", &JSSearch::SetOnScroll); JSClass::StaticMethod("border", &JSSearch::JsBorder); JSClass::StaticMethod("borderWidth", &JSSearch::JsBorderWidth); JSClass::StaticMethod("borderColor", &JSSearch::JsBorderColor); JSClass::StaticMethod("borderStyle", &JSSearch::JsBorderStyle); JSClass::StaticMethod("borderRadius", &JSSearch::JsBorderRadius); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("height", &JSSearch::SetHeight); JSClass::StaticMethod("width", &JSViewAbstract::JsWidth); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("requestKeyboardOnFocus", &JSSearch::SetEnableKeyboardOnFocus); JSClass::StaticMethod("enableKeyboardOnFocus", &JSSearch::SetEnableKeyboardOnFocus); JSClass::StaticMethod("onAttach", &JSInteractableView::JsOnAttach); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDetach", &JSInteractableView::JsOnDetach); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("onCopy", &JSSearch::SetOnCopy); JSClass::StaticMethod("onCut", &JSSearch::SetOnCut); JSClass::StaticMethod("onPaste", &JSSearch::SetOnPaste); JSClass::StaticMethod("copyOption", &JSSearch::SetCopyOption); JSClass::StaticMethod("selectionMenuHidden", &JSSearch::SetSelectionMenuHidden); JSClass::StaticMethod("customKeyboard", &JSSearch::SetCustomKeyboard); JSClass::StaticMethod("enterKeyType", &JSSearch::SetEnterKeyType); JSClass::StaticMethod("maxLength", &JSSearch::SetMaxLength); JSClass::StaticMethod("type", &JSSearch::SetType); JSClass::StaticMethod("dragPreviewOptions", &JSSearch::SetDragPreviewOptions); JSClass::StaticMethod("editMenuOptions", &JSSearch::EditMenuOptions); JSClass::StaticMethod("strokeWidth", &JSSearch::SetStrokeWidth); JSClass::StaticMethod("strokeColor", &JSSearch::SetStrokeColor); JSClass::StaticMethod("margin", &JSSearch::JsMargin); JSBindMore(); JSClass::InheritAndBind(globalObj); } void JSSearch::JSBindMore() { JSClass::StaticMethod("decoration", &JSSearch::SetDecoration); JSClass::StaticMethod("minFontSize", &JSSearch::SetMinFontSize); JSClass::StaticMethod("maxFontSize", &JSSearch::SetMaxFontSize); JSClass::StaticMethod("minFontScale", &JSSearch::SetMinFontScale); JSClass::StaticMethod("maxFontScale", &JSSearch::SetMaxFontScale); JSClass::StaticMethod("letterSpacing", &JSSearch::SetLetterSpacing); JSClass::StaticMethod("lineHeight", &JSSearch::SetLineHeight); JSClass::StaticMethod("halfLeading", &JSSearch::SetHalfLeading); JSClass::StaticMethod("fontFeature", &JSSearch::SetFontFeature); JSClass::StaticMethod("id", &JSSearch::SetId); JSClass::StaticMethod("key", &JSSearch::SetKey); JSClass::StaticMethod("selectedBackgroundColor", &JSSearch::SetSelectedBackgroundColor); JSClass::StaticMethod("inputFilter", &JSSearch::SetInputFilter); JSClass::StaticMethod("onEditChange", &JSSearch::SetOnEditChange); JSClass::StaticMethod("textIndent", &JSSearch::SetTextIndent); JSClass::StaticMethod("onWillInsert", &JSSearch::OnWillInsertValue); JSClass::StaticMethod("onDidInsert", &JSSearch::OnDidInsertValue); JSClass::StaticMethod("onWillDelete", &JSSearch::OnWillDelete); JSClass::StaticMethod("onDidDelete", &JSSearch::OnDidDelete); JSClass::StaticMethod("enablePreviewText", &JSSearch::SetEnablePreviewText); JSClass::StaticMethod("enableHapticFeedback", &JSSearch::SetEnableHapticFeedback); JSClass::StaticMethod("autoCapitalizationMode", &JSSearch::SetCapitalizationMode); JSClass::StaticMethod("stopBackPress", &JSSearch::SetStopBackPress); JSClass::StaticMethod("keyboardAppearance", &JSSearch::SetKeyboardAppearance); JSClass::StaticMethod("onWillChange", &JSSearch::SetOnWillChange); JSClass::StaticMethod("enableAutoSpacing", &JSSearch::SetEnableAutoSpacing); JSClass::StaticMethod("onWillAttachIME", &JSSearch::SetOnWillAttachIME); } void ParseSearchValueObject(const JSCallbackInfo& info, const JSRef& changeEventVal) { CHECK_NULL_VOID(changeEventVal->IsFunction()); JsEventCallback onChangeEvent( info.GetExecutionContext(), JSRef::Cast(changeEventVal)); SearchModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent)); } void JSSearch::SetDragPreviewOptions(const JSCallbackInfo& info) { NG::DragPreviewOption option = JSViewAbstract::ParseDragPreviewOptions(info); SearchModel::GetInstance()->SetDragPreviewOptions(option); } void JSSearch::SetFontFeature(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } if (!info[0]->IsString() && !info[0]->IsObject()) { return; } std::string fontFeatureSettings = info[0]->ToString(); SearchModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings)); } void JSSearch::Create(const JSCallbackInfo& info) { std::optional key; std::optional tip; std::optional src; JSTextEditableController* jsController = nullptr; JSRef changeEventVal; bool placeholderResult = false; bool textResult = false; std::u16string placeholder; std::u16string text; RefPtr placeholderObject; RefPtr textObject; if (info[0]->IsObject()) { auto param = JSRef::Cast(info[0]); if (param->GetProperty("placeholder")->IsUndefined()) { tip = u""; } placeholderResult = ParseJsString(param->GetProperty("placeholder"), placeholder, placeholderObject); if (placeholderResult) { tip = placeholder; } JSRef textValue = param->GetProperty("value"); if (textValue->IsObject()) { JSRef valueObj = JSRef::Cast(textValue); changeEventVal = valueObj->GetProperty("changeEvent"); if (changeEventVal->IsFunction()) { textValue = valueObj->GetProperty("value"); } textResult = ParseJsString(textValue, text, textObject); if (textResult) { key = text; } } else if (param->GetProperty("$value")->IsFunction()) { changeEventVal = param->GetProperty("$value"); textResult = ParseJsString(textValue, text, textObject); if (textResult) { key = text; } } else if (param->HasProperty("value") && textValue->IsUndefined()) { key = u""; } else { textResult = ParseJsString(textValue, text, textObject); if (textResult) { key = text; } } std::string icon; if (ParseJsString(param->GetProperty("icon"), icon)) { src = icon; } auto controllerObj = param->GetProperty("controller"); if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) { jsController = JSRef::Cast(controllerObj)->Unwrap(); } } auto controller = SearchModel::GetInstance()->Create(key, tip, src); if (jsController) { jsController->SetController(controller); } SearchModel::GetInstance()->SetFocusable(true); SearchModel::GetInstance()->SetFocusNode(true); if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) { ParseSearchValueObject(info, changeEventVal); } if (SystemProperties::ConfigChangePerform()) { if (placeholderResult && placeholderObject) { RegisterResource("placeholder", placeholderObject, placeholder); } else { UnregisterResource("placeholder"); } } if (SystemProperties::ConfigChangePerform()) { if (textResult && textObject) { RegisterResource("text", textObject, text); } else { UnregisterResource("text"); } } } void JSSearch::SetSelectedBackgroundColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color selectedColor; RefPtr resourceObject; UnregisterResource("selectedBackgroundColor"); if (!ParseJsColor(info[0], selectedColor, resourceObject)) { SearchModel::GetInstance()->ResetSelectedBackgroundColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("selectedBackgroundColor", resourceObject, selectedColor); } // Alpha = 255 means opaque if (selectedColor.GetAlpha() == DEFAULT_ALPHA) { // Default setting of 20% opacity selectedColor = selectedColor.ChangeOpacity(DEFAULT_OPACITY); } SearchModel::GetInstance()->SetSelectedBackgroundColor(selectedColor); } void JSSearch::SetEnableKeyboardOnFocus(const JSCallbackInfo& info) { if (info[0]->IsUndefined() || !info[0]->IsBoolean()) { SearchModel::GetInstance()->RequestKeyboardOnFocus(true); return; } SearchModel::GetInstance()->RequestKeyboardOnFocus(info[0]->ToBoolean()); } void JSSearch::SetId(const JSCallbackInfo& info) { JSViewAbstract::JsId(info); JSRef arg = info[0]; std::string id; if (arg->IsString()) { id = arg->ToString(); } SearchModel::GetInstance()->UpdateInspectorId(id); } void JSSearch::SetKey(const std::string& key) { JSViewAbstract::JsKey(key); SearchModel::GetInstance()->UpdateInspectorId(key); } void JSSearch::SetSearchButtonOptions(const JSCallbackInfo& info) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); Color fontColor = theme->GetSearchButtonTextColor(); if (info.Length() < 2 || !info[1]->IsObject()) { // 2 : args num SearchModel::GetInstance()->SetSearchButtonFontSize(theme->GetButtonFontSize()); SearchModel::GetInstance()->ResetSearchButtonFontColor(); return; } auto param = JSRef::Cast(info[1]); // set button font size, unit FP auto fontSize = param->GetProperty("fontSize"); RefPtr fontSizeObject; UnregisterResource("searchButtonFontSize"); CalcDimension size = theme->GetButtonFontSize(); if (ParseJsDimensionVpNG(fontSize, size, fontSizeObject) && size.Unit() != DimensionUnit::PERCENT && GreatOrEqual(size.Value(), 0.0)) { ParseJsDimensionFp(fontSize, size, fontSizeObject); } else { size = theme->GetButtonFontSize(); } if (SystemProperties::ConfigChangePerform() && fontSizeObject) { RegisterResource("searchButtonFontSize", fontSizeObject, size); } SearchModel::GetInstance()->SetSearchButtonFontSize(size); auto fontColorProp = param->GetProperty("fontColor"); RefPtr colorObject; UnregisterResource("searchButtonFontColor"); if (fontColorProp->IsUndefined() || fontColorProp->IsNull() || !ParseJsColor(fontColorProp, fontColor, colorObject)) { SearchModel::GetInstance()->ResetSearchButtonFontColor(); } else { SearchModel::GetInstance()->SetSearchButtonFontColor(fontColor); } if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("searchButtonFontColor", colorObject, fontColor); } auto autoDisable = param->GetProperty("autoDisable"); if (autoDisable->IsUndefined() || autoDisable->IsNull() || !autoDisable->IsBoolean()) { SearchModel::GetInstance()->SetSearchButtonAutoDisable(false); } else { SearchModel::GetInstance()->SetSearchButtonAutoDisable(autoDisable->ToBoolean()); } } void JSSearch::SetSearchButton(const JSCallbackInfo& info) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); std::string buttonValue = ""; UnregisterResource("searchButtonValue"); if (info[0]->IsString()) { buttonValue = info[0]->ToString(); } else { RefPtr resourceObject; ParseJsString(info[0], buttonValue, resourceObject); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("searchButtonValue", resourceObject, buttonValue); } } SearchModel::GetInstance()->SetSearchButton(buttonValue); SetSearchButtonOptions(info); } void JSSearch::SetSearchIcon(const JSCallbackInfo& info) { if (SystemProperties::ConfigChangePerform()) { UnregisterResource("searchIconSize"); UnregisterResource("searchButtonIconSrc"); UnregisterResource("searchIconColor"); } if (info[0]->IsUndefined() || info[0]->IsNull()) { SetSearchDefaultIcon(); return; } if (info[0]->IsObject()) { auto param = JSRef::Cast(info[0]); bool isSymbolIcon = param->HasProperty("fontColor"); // only SymbolGlyph has fontColor property if (isSymbolIcon) { SetSearchSymbolIcon(info); } else { SetSearchImageIcon(info); } } } void JSSearch::SetCancelDefaultIcon() { SearchModel::GetInstance()->SetCancelDefaultIcon(); } void JSSearch::SetCancelSymbolIcon(const JSCallbackInfo& info) { if (info[0]->IsObject()) { std::function)> iconSymbol = nullptr; auto param = JSRef::Cast(info[0]); auto iconProp = param->GetProperty("icon"); SetSymbolOptionApply(info, iconSymbol, iconProp); SearchModel::GetInstance()->SetCancelSymbolIcon(iconSymbol); } } void JSSearch::SetCancelImageIcon(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto theme = GetTheme(); CHECK_NULL_VOID(theme); auto iconJsVal = param->GetProperty("icon"); if (!iconJsVal->IsObject()) { return; } auto iconParam = JSRef::Cast(iconJsVal); // set icon size CalcDimension iconSize; auto iconSizeProp = iconParam->GetProperty("size"); RefPtr sizeObject; UnregisterResource("cancelButtonIconSize"); if (!iconSizeProp->IsUndefined() && !iconSizeProp->IsNull() && ParseJsDimensionVpNG(iconSizeProp, iconSize, sizeObject)) { if (LessNotEqual(iconSize.Value(), 0.0) || iconSize.Unit() == DimensionUnit::PERCENT) { iconSize = theme->GetIconHeight(); } } else { iconSize = theme->GetIconHeight(); } if (SystemProperties::ConfigChangePerform() && sizeObject) { RegisterResource("cancelButtonIconSize", sizeObject, iconSize); } // set icon src std::string iconSrc; RefPtr srcObject; UnregisterResource("cancelButtonIconSrc"); auto iconSrcProp = iconParam->GetProperty("src"); if (iconSrcProp->IsUndefined() || iconSrcProp->IsNull() || !ParseJsMedia(iconSrcProp, iconSrc, srcObject)) { iconSrc = ""; } if (SystemProperties::ConfigChangePerform() && srcObject) { RegisterResource("cancelButtonIconSrc", srcObject, iconSrc); } // set icon color Color iconColor; RefPtr colorObject; UnregisterResource("cancelButtonIconColor"); NG::IconOptions cancelIconOptions; auto iconColorProp = iconParam->GetProperty("color"); if (!iconColorProp->IsUndefined() && !iconColorProp->IsNull() && ParseJsColor(iconColorProp, iconColor, colorObject)) { SearchModel::GetInstance()->SetCancelIconColor(iconColor); cancelIconOptions = NG::IconOptions(iconColor, iconSize, iconSrc, "", ""); } else { SearchModel::GetInstance()->ResetCancelIconColor(); cancelIconOptions = NG::IconOptions(iconSize, iconSrc, "", ""); } if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("cancelButtonIconColor", colorObject, iconColor); } SearchModel::GetInstance()->SetCancelImageIcon(cancelIconOptions); } void JSSearch::SetSearchDefaultIcon() { SearchModel::GetInstance()->SetSearchDefaultIcon(); } void JSSearch::SetSearchSymbolIcon(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } std::function)> iconSymbol = nullptr; SetSymbolOptionApply(info, iconSymbol, info[0]); SearchModel::GetInstance()->SetSearchSymbolIcon(iconSymbol); } void JSSearch::SetSearchImageIcon(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto theme = GetTheme(); CHECK_NULL_VOID(theme); // set icon size CalcDimension size; auto sizeProp = param->GetProperty("size"); RefPtr sizeObject; if (!sizeProp->IsUndefined() && !sizeProp->IsNull() && ParseJsDimensionVpNG(sizeProp, size, sizeObject)) { if (LessNotEqual(size.Value(), 0.0) || size.Unit() == DimensionUnit::PERCENT) { size = theme->GetIconHeight(); } } else { size = theme->GetIconHeight(); } if (SystemProperties::ConfigChangePerform() && sizeObject) { RegisterResource("searchIconSize", sizeObject, size); } // set icon src std::string src; RefPtr mediaObject; auto srcPathProp = param->GetProperty("src"); if (srcPathProp->IsUndefined() || srcPathProp->IsNull() || !ParseJsMedia(srcPathProp, src, mediaObject)) { src = ""; } if (SystemProperties::ConfigChangePerform() && mediaObject) { RegisterResource("searchButtonIconSrc", mediaObject, src); } std::string bundleName; std::string moduleName; GetJsMediaBundleInfo(srcPathProp, bundleName, moduleName); // set icon color Color colorVal; RefPtr colorObject; NG::IconOptions searchIconOptions; auto colorProp = param->GetProperty("color"); if (!colorProp->IsUndefined() && !colorProp->IsNull() && ParseJsColor(colorProp, colorVal, colorObject)) { SearchModel::GetInstance()->SetSearchIconColor(colorVal); searchIconOptions = NG::IconOptions(colorVal, size, src, bundleName, moduleName); } else { SearchModel::GetInstance()->ResetSearchIconColor(); searchIconOptions = NG::IconOptions(size, src, bundleName, moduleName); } if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("searchIconColor", colorObject, colorVal); } SearchModel::GetInstance()->SetSearchImageIcon(searchIconOptions); } static CancelButtonStyle ConvertStrToCancelButtonStyle(const std::string& value) { if (value == "CONSTANT") { return CancelButtonStyle::CONSTANT; } else if (value == "INVISIBLE") { return CancelButtonStyle::INVISIBLE; } else { return CancelButtonStyle::INPUT; } } void JSSearch::SetCancelButton(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto theme = GetTheme(); CHECK_NULL_VOID(theme); // set style std::string styleStr; CancelButtonStyle cancelButtonStyle; auto styleProp = param->GetProperty("style"); if (!styleProp->IsUndefined() && !styleProp->IsNull() && ParseJsString(styleProp, styleStr)) { cancelButtonStyle = ConvertStrToCancelButtonStyle(styleStr); } else { cancelButtonStyle = theme->GetCancelButtonStyle(); } SearchModel::GetInstance()->SetCancelButtonStyle(cancelButtonStyle); auto iconProp = param->GetProperty("icon"); if (iconProp->IsUndefined() || iconProp->IsNull()) { SetCancelDefaultIcon(); } else { SetIconStyle(info); } } void JSSearch::SetIconStyle(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto iconJsVal = param->GetProperty("icon"); if (!iconJsVal->IsObject()) { return; } auto iconParam = JSRef::Cast(iconJsVal); bool isSymbolIcon = iconParam->HasProperty("fontColor"); // only SymbolGlyph has fontColor property if (isSymbolIcon) { SetCancelSymbolIcon(info); } else { SetCancelImageIcon(info); } } void JSSearch::SetTextColor(const JSCallbackInfo& info) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); auto value = JSRef::Cast(info[0]); Color colorVal; RefPtr resourceObject; UnregisterResource("fontColor"); if (!ParseJsColor(value, colorVal, resourceObject)) { SearchModel::GetInstance()->ResetTextColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("fontColor", resourceObject, colorVal); } SearchModel::GetInstance()->SetTextColor(colorVal); } void JSSearch::SetBackgroundColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color colorVal; if (!ParseJsColor(info[0], colorVal)) { SearchModel::GetInstance()->ResetBackgroundColor(); return; } SearchModel::GetInstance()->SetBackgroundColor(colorVal); } void JSSearch::SetCaret(const JSCallbackInfo& info) { if (info[0]->IsObject()) { auto param = JSRef::Cast(info[0]); auto textFieldTheme = GetTheme(); CHECK_NULL_VOID(textFieldTheme); // set caret width CalcDimension caretWidth = textFieldTheme->GetCursorWidth(); auto caretWidthProp = param->GetProperty("width"); RefPtr widthObject; UnregisterResource("caretWidth"); if (!ParseJsDimensionVpNG(caretWidthProp, caretWidth, widthObject, false) || LessNotEqual(caretWidth.Value(), 0.0)) { caretWidth = textFieldTheme->GetCursorWidth(); } if (SystemProperties::ConfigChangePerform() && widthObject) { RegisterResource("caretWidth", widthObject, caretWidth); } SearchModel::GetInstance()->SetCaretWidth(caretWidth); // set caret color Color caretColor; RefPtr colorObject; UnregisterResource("caretColor"); auto caretColorProp = param->GetProperty("color"); if (caretColorProp->IsUndefined() || caretColorProp->IsNull() || !ParseJsColor(caretColorProp, caretColor, colorObject)) { SearchModel::GetInstance()->ResetCaretColor(); return; } if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("caretColor", colorObject, caretColor); } SearchModel::GetInstance()->SetCaretColor(caretColor); } } void JSSearch::SetInputFilter(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto tmpInfo = info[0]; auto errInfo = info[1]; std::string inputFilter; if (tmpInfo->IsUndefined()) { UnregisterResource("inputFilter"); SearchModel::GetInstance()->SetInputFilter(inputFilter, nullptr); return; } RefPtr resourceObject; if (!ParseJsString(tmpInfo, inputFilter, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("inputFilter", resourceObject, inputFilter); } else { UnregisterResource("inputFilter"); } if (!CheckRegexValid(inputFilter)) { inputFilter = ""; } if (info.Length() > 1 && errInfo->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef::Cast(errInfo)); auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto resultId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]( const std::u16string& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); PipelineContext::SetCallBackNode(node); func->Execute(info); }; SearchModel::GetInstance()->SetInputFilter(inputFilter, resultId); return; } SearchModel::GetInstance()->SetInputFilter(inputFilter, nullptr); } void JSSearch::SetOnEditChange(const JSCallbackInfo& info) { auto tmpInfo = info[0]; CHECK_NULL_VOID(tmpInfo->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(tmpInfo)); SearchModel::GetInstance()->SetOnEditChanged(std::move(callback)); } void JSSearch::SetTextIndent(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; UnregisterResource("textIndent"); if (!ParseJsDimensionVpNG(info[0], value, resourceObject, true)) { value.Reset(); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("textIndent", resourceObject, value); } SearchModel::GetInstance()->SetTextIndent(value); } void JSSearch::SetPlaceholderColor(const JSCallbackInfo& info) { auto value = JSRef::Cast(info[0]); Color colorVal; RefPtr resourceObject; UnregisterResource("placeholderColor"); if (!ParseJsColor(value, colorVal, resourceObject)) { SearchModel::GetInstance()->ResetPlaceholderColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("placeholderColor", resourceObject, colorVal); } SearchModel::GetInstance()->SetPlaceholderColor(colorVal); } void JSSearch::SetPlaceholderFont(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto theme = GetTheme(); CHECK_NULL_VOID(theme); auto themeFontSize = theme->GetFontSize(); Font font; auto fontSize = param->GetProperty("size"); RefPtr resourceObject; UnregisterResource("placeholderFontSize"); if (fontSize->IsNull() || fontSize->IsUndefined()) { font.fontSize = themeFontSize; } else { auto versionTenOrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN); CalcDimension size; if ((versionTenOrLarger ? ParseJsDimensionVpNG(fontSize, size, resourceObject) : ParseJsDimensionVp(fontSize, size, resourceObject)) && size.Unit() != DimensionUnit::PERCENT) { ParseJsDimensionFp(fontSize, size, resourceObject); font.fontSize = size; } else { font.fontSize = themeFontSize; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("placeholderFontSize", resourceObject, size); } } auto weight = param->GetProperty("weight"); if (!weight->IsNull()) { std::string weightVal; if (weight->IsNumber()) { weightVal = std::to_string(weight->ToNumber()); } else { ParseJsString(weight, weightVal); } font.fontWeight = ConvertStrToFontWeight(weightVal); } auto family = param->GetProperty("family"); if (!family->IsNull() && family->IsString()) { auto familyVal = family->ToString(); font.fontFamilies = ConvertStrToFontFamilies(familyVal); } auto style = param->GetProperty("style"); if (!style->IsNull() && style->IsNumber()) { FontStyle styleVal = static_cast(style->ToNumber()); font.fontStyle = styleVal; } SearchModel::GetInstance()->SetPlaceholderFont(font); } void JSSearch::SetTextFont(const JSCallbackInfo& info) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); auto themeFontSize = theme->GetFontSize(); auto themeFontWeight = theme->GetFontWeight(); Font font { .fontWeight = themeFontWeight, .fontSize = themeFontSize, .fontStyle = Ace::FontStyle::NORMAL }; if (info.Length() < 1 || !info[0]->IsObject()) { if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) { SearchModel::GetInstance()->SetTextFont(font); } return; } auto param = JSRef::Cast(info[0]); auto fontSize = param->GetProperty("size"); CalcDimension size = themeFontSize; RefPtr resourceObject; UnregisterResource("fontSize"); if (ParseJsDimensionVpNG(fontSize, size, resourceObject) && size.Unit() != DimensionUnit::PERCENT && GreatOrEqual(size.Value(), 0.0)) { ParseJsDimensionFp(fontSize, size, resourceObject); } else { size = themeFontSize; } font.fontSize = size; if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("fontSize", resourceObject, size); } auto weight = param->GetProperty("weight"); if (!weight->IsNull()) { std::string weightVal; if (weight->IsNumber()) { weightVal = std::to_string(weight->ToNumber()); } else { ParseJsString(weight, weightVal); } font.fontWeight = ConvertStrToFontWeight(weightVal); } auto family = param->GetProperty("family"); if (!family->IsNull() && family->IsString()) { auto familyVal = family->ToString(); font.fontFamilies = ConvertStrToFontFamilies(familyVal); } auto style = param->GetProperty("style"); if (!style->IsNull() && style->IsNumber()) { FontStyle styleVal = static_cast(style->ToNumber()); font.fontStyle = styleVal; } SearchModel::GetInstance()->SetTextFont(font); } void JSSearch::SetTextAlign(int32_t value) { if (value >= 0 && value < static_cast(TEXT_ALIGNS.size())) { SearchModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]); } } void JSSearch::JsBorder(const JSCallbackInfo& info) { if (!info[0]->IsObject()) { CalcDimension borderWidth; ViewAbstractModel::GetInstance()->SetBorderWidth(borderWidth); ViewAbstractModel::GetInstance()->SetBorderColor(Color::BLACK); ViewAbstractModel::GetInstance()->SetBorderRadius(borderWidth); ViewAbstractModel::GetInstance()->SetBorderStyle(BorderStyle::SOLID); ViewAbstractModel::GetInstance()->SetDashGap(Dimension(-1)); ViewAbstractModel::GetInstance()->SetDashWidth(Dimension(-1)); return; } JSRef object = JSRef::Cast(info[0]); auto valueWidth = object->GetProperty(static_cast(ArkUIIndex::WIDTH)); if (!valueWidth->IsUndefined()) { JSViewAbstract::ParseBorderWidth(valueWidth); } // use default value when undefined. JSViewAbstract::ParseBorderColor(object->GetProperty(static_cast(ArkUIIndex::COLOR))); auto valueRadius = object->GetProperty(static_cast(ArkUIIndex::RADIUS)); if (!valueRadius->IsUndefined()) { JSViewAbstract::ParseBorderRadius(valueRadius); SearchModel::GetInstance()->SetBackBorderRadius(); } // use default value when undefined. JSViewAbstract::ParseBorderStyle(object->GetProperty(static_cast(ArkUIIndex::STYLE))); auto dashGap = object->GetProperty("dashGap"); if (!dashGap->IsUndefined()) { JSViewAbstract::ParseDashGap(dashGap); } auto dashWidth = object->GetProperty("dashWidth"); if (!dashWidth->IsUndefined()) { JSViewAbstract::ParseDashWidth(dashWidth); } SearchModel::GetInstance()->SetBackBorder(); info.ReturnSelf(); } void JSSearch::JsBorderWidth(const JSCallbackInfo& info) { JSViewAbstract::JsBorderWidth(info); if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) { return; } SearchModel::GetInstance()->SetBackBorder(); } void JSSearch::JsBorderColor(const JSCallbackInfo& info) { JSViewAbstract::JsBorderColor(info); if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) { return; } SearchModel::GetInstance()->SetBackBorder(); } void JSSearch::JsBorderStyle(const JSCallbackInfo& info) { JSViewAbstract::JsBorderStyle(info); if (!info[0]->IsObject() && !info[0]->IsNumber()) { return; } SearchModel::GetInstance()->SetBackBorder(); } void JSSearch::GetBorderRadiusByLengthMetrics(const char* key, JSRef& object, std::optional& radius) { if (object->HasProperty(key) && object->GetProperty(key)->IsObject()) { JSRef startObj = JSRef::Cast(object->GetProperty(key)); CalcDimension value; ParseJsLengthMetrics(startObj, value); radius = value; } } bool JSSearch::ParseAllBorderRadiuses(JSRef& object, CalcDimension& topLeft, CalcDimension& topRight, CalcDimension& bottomLeft, CalcDimension& bottomRight) { if (object->HasProperty(TOP_START_PROPERTY) || object->HasProperty(TOP_END_PROPERTY) || object->HasProperty(BOTTOM_START_PROPERTY) || object->HasProperty(BOTTOM_END_PROPERTY)) { std::optional topStart; std::optional topEnd; std::optional bottomStart; std::optional bottomEnd; GetBorderRadiusByLengthMetrics(TOP_START_PROPERTY, object, topStart); GetBorderRadiusByLengthMetrics(TOP_END_PROPERTY, object, topEnd); GetBorderRadiusByLengthMetrics(BOTTOM_START_PROPERTY, object, bottomStart); GetBorderRadiusByLengthMetrics(BOTTOM_END_PROPERTY, object, bottomEnd); topLeft = topStart.has_value() ? topStart.value() : topLeft; topRight = topEnd.has_value() ? topEnd.value() : topRight; bottomLeft = bottomStart.has_value() ? bottomStart.value() : bottomLeft; bottomRight = bottomEnd.has_value() ? bottomEnd.value() : bottomRight; return true; } JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topLeft"), topLeft); JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topRight"), topRight); JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomLeft"), bottomLeft); JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomRight"), bottomRight); return false; } void JSSearch::ParseBorderRadius(const JSRef& args) { CalcDimension borderRadius; if (ParseJsDimensionVp(args, borderRadius)) { ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius); } else if (args->IsObject()) { auto textFieldTheme = GetTheme(); CHECK_NULL_VOID(textFieldTheme); auto borderRadiusTheme = textFieldTheme->GetBorderRadius(); NG::BorderRadiusProperty defaultBorderRadius { borderRadiusTheme.GetX(), borderRadiusTheme.GetY(), borderRadiusTheme.GetY(), borderRadiusTheme.GetX(), }; JSRef object = JSRef::Cast(args); CalcDimension topLeft = defaultBorderRadius.radiusTopLeft.value(); CalcDimension topRight = defaultBorderRadius.radiusTopRight.value(); CalcDimension bottomLeft = defaultBorderRadius.radiusBottomLeft.value(); CalcDimension bottomRight = defaultBorderRadius.radiusBottomRight.value(); if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) { ViewAbstractModel::GetInstance()->SetBorderRadius( JSViewAbstract::GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight)); return; } ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight); } } void JSSearch::JsBorderRadius(const JSCallbackInfo& info) { auto jsValue = info[0]; static std::vector checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER, JSCallbackInfoType::OBJECT }; if (!CheckJSCallbackInfo("JsBorderRadius", jsValue, checkList)) { auto textFieldTheme = GetTheme(); CHECK_NULL_VOID(textFieldTheme); auto borderRadiusTheme = textFieldTheme->GetBorderRadius(); NG::BorderRadiusProperty defaultBorderRadius { borderRadiusTheme.GetX(), borderRadiusTheme.GetY(), borderRadiusTheme.GetY(), borderRadiusTheme.GetX(), }; ViewAbstractModel::GetInstance()->SetBorderRadius(defaultBorderRadius); return; } ParseBorderRadius(jsValue); SearchModel::GetInstance()->SetBackBorderRadius(); } void JSSearch::CreateJsSearchCommonEvent(const JSCallbackInfo &info) { if (info.Length() < 1 || !info[0]->IsFunction()) { return; } auto jsTextFunc = AceType::MakeRefPtr>( JSRef::Cast(info[0])); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode]( const std::u16string& value, NG::TextFieldCommonEvent& event) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("onSubmit"); PipelineContext::SetCallBackNode(node); JSRef objectTemplate = JSRef::New(); objectTemplate->SetInternalFieldCount(2); JSRef object = objectTemplate->NewInstance(); object->SetProperty("text", event.GetText()); object->SetPropertyObject( "keepEditableState", JSRef::New(JSTextField::JsKeepEditableState)); object->Wrap(&event); JSRef stringValue = JSRef::Make(ToJSValue(value)); JSRef dataObject = JSRef::Cast(object); JSRef param[2] = {stringValue, dataObject}; func->Execute(param); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onSubmit"); }; SearchModel::GetInstance()->SetOnSubmit(std::move(callback)); } void JSSearch::OnSubmit(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); #ifdef NG_BUILD CreateJsSearchCommonEvent(info); #else if (Container::IsCurrentUseNewPipeline()) { CreateJsSearchCommonEvent(info); } else { JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); SearchModel::GetInstance()->SetOnSubmit(std::move(callback)); } #endif } JSRef JSSearch::CreateJsOnChangeObj(const PreviewText& previewText) { JSRef previewTextObj = JSRef::New(); previewTextObj->SetProperty("offset", previewText.offset); previewTextObj->SetProperty("value", previewText.value); return JSRef::Cast(previewTextObj); } void JSSearch::OnChange(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsChangeFunc = AceType::MakeRefPtr(JSRef::Cast(jsValue)); auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsChangeFunc)]( const ChangeValueInfo& changeValueInfo) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("onChange"); JSRef valueObj = JSRef::Make(ToJSValue(changeValueInfo.value)); auto previewTextObj = CreateJsOnChangeObj(changeValueInfo.previewText); auto optionsObj = JSRef::New(); auto rangeBeforeObj = JSRef::New(); rangeBeforeObj->SetProperty("start", changeValueInfo.rangeBefore.start); rangeBeforeObj->SetProperty("end", changeValueInfo.rangeBefore.end); optionsObj->SetPropertyObject("rangeBefore", rangeBeforeObj); auto rangeAfterObj = JSRef::New(); rangeAfterObj->SetProperty("start", changeValueInfo.rangeAfter.start); rangeAfterObj->SetProperty("end", changeValueInfo.rangeAfter.end); optionsObj->SetPropertyObject("rangeAfter", rangeAfterObj); optionsObj->SetProperty("oldContent", changeValueInfo.oldContent); auto oldPreviewTextObj = CreateJsOnChangeObj(changeValueInfo.oldPreviewText); optionsObj->SetPropertyObject("oldPreviewText", oldPreviewTextObj); JSRef argv[] = { valueObj, previewTextObj, optionsObj }; func->ExecuteJS(3, argv); }; SearchModel::GetInstance()->SetOnChange(std::move(onChange)); } void JSSearch::SetOnTextSelectionChange(const JSCallbackInfo& info) { CHECK_NULL_VOID(info[0]->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(info[0])); SearchModel::GetInstance()->SetOnTextSelectionChange(std::move(callback)); } void JSSearch::SetOnScroll(const JSCallbackInfo& info) { CHECK_NULL_VOID(info[0]->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(info[0])); SearchModel::GetInstance()->SetOnScroll(std::move(callback)); } void JSSearch::SetHeight(const JSCallbackInfo& info) { JSViewAbstract::JsHeight(info); CalcDimension value; auto versionTenOrLarger = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN); if (versionTenOrLarger ? !ParseJsDimensionVpNG(info[0], value) : !ParseJsDimensionVp(info[0], value)) { return; } if (LessNotEqual(value.Value(), 0.0)) { value.SetValue(0.0); } SearchModel::GetInstance()->SetHeight(value); } void JSSearch::SetOnCopy(const JSCallbackInfo& info) { CHECK_NULL_VOID(info[0]->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(info[0])); SearchModel::GetInstance()->SetOnCopy(std::move(callback)); } void JSSearch::SetOnCut(const JSCallbackInfo& info) { CHECK_NULL_VOID(info[0]->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(info[0])); SearchModel::GetInstance()->SetOnCut(std::move(callback)); } JSRef JSSearch::CreateJSTextCommonEvent(NG::TextCommonEvent& event) { JSRef objectTemplate = JSRef::New(); objectTemplate->SetInternalFieldCount(1); JSRef object = objectTemplate->NewInstance(); object->SetPropertyObject("preventDefault", JSRef::New(JsPreventDefault)); object->Wrap(&event); return JSRef::Cast(object); } void JSSearch::SetOnPaste(const JSCallbackInfo& info) { CHECK_NULL_VOID(info[0]->IsFunction()); auto jsTextFunc = AceType::MakeRefPtr>( JSRef::Cast(info[0]), CreateJSTextCommonEvent); auto onPaste = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc)]( const std::u16string& val, NG::TextCommonEvent& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("onPaste"); func->Execute(val, info); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onPaste"); }; SearchModel::GetInstance()->SetOnPasteWithEvent(std::move(onPaste)); } void JSSearch::SetCopyOption(const JSCallbackInfo& info) { if (info.Length() == 0) { return; } if (info[0]->IsUndefined()) { SearchModel::GetInstance()->SetCopyOption(CopyOptions::Local); return; } auto copyOptions = CopyOptions::Local; if (info[0]->IsNumber()) { auto emunNumber = info[0]->ToNumber(); copyOptions = static_cast(emunNumber); } SearchModel::GetInstance()->SetCopyOption(copyOptions); } JSRef JSSearch::CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue) { JSRef aboutToIMEInputObj = JSRef::New(); aboutToIMEInputObj->SetProperty("insertOffset", insertValue.insertOffset); aboutToIMEInputObj->SetProperty("insertValue", insertValue.insertValue); return JSRef::Cast(aboutToIMEInputObj); } void JSSearch::OnWillInsertValue(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsAboutToIMEInputFunc = AceType::MakeRefPtr>( JSRef::Cast(jsValue), CreateJsAboutToIMEInputObj); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)]( const InsertValueInfo& insertValue) -> bool { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true); auto ret = func->ExecuteWithValue(insertValue); if (ret->IsBoolean()) { return ret->ToBoolean(); } return true; }; SearchModel::GetInstance()->SetOnWillInsertValueEvent(std::move(callback)); } JSRef JSSearch::CreateJsDeleteToIMEObj(const DeleteValueInfo& deleteValueInfo) { JSRef aboutToIMEInputObj = JSRef::New(); aboutToIMEInputObj->SetProperty("deleteOffset", deleteValueInfo.deleteOffset); aboutToIMEInputObj->SetProperty("direction", static_cast(deleteValueInfo.direction)); aboutToIMEInputObj->SetProperty("deleteValue", deleteValueInfo.deleteValue); return JSRef::Cast(aboutToIMEInputObj); } void JSSearch::OnDidInsertValue(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsAboutToIMEInputFunc = AceType::MakeRefPtr>( JSRef::Cast(jsValue), CreateJsAboutToIMEInputObj); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)]( const InsertValueInfo& insertValue) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->ExecuteWithValue(insertValue); }; SearchModel::GetInstance()->SetOnDidInsertValueEvent(std::move(callback)); } void JSSearch::OnWillDelete(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsAboutToIMEInputFunc = AceType::MakeRefPtr>(JSRef::Cast(jsValue), CreateJsDeleteToIMEObj); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)]( const DeleteValueInfo& deleteValue) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true); auto ret = func->ExecuteWithValue(deleteValue); if (ret->IsBoolean()) { return ret->ToBoolean(); } return true; }; SearchModel::GetInstance()->SetOnWillDeleteEvent(std::move(callback)); } void JSSearch::OnDidDelete(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsAboutToIMEInputFunc = AceType::MakeRefPtr>(JSRef::Cast(jsValue), CreateJsDeleteToIMEObj); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)]( const DeleteValueInfo& deleteValue) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); func->ExecuteWithValue(deleteValue); }; SearchModel::GetInstance()->SetOnDidDeleteEvent(std::move(callback)); } void JSSearch::SetSelectionMenuHidden(const JSCallbackInfo& info) { if (info[0]->IsUndefined() || !info[0]->IsBoolean()) { SearchModel::GetInstance()->SetSelectionMenuHidden(false); return; } SearchModel::GetInstance()->SetSelectionMenuHidden(info[0]->ToBoolean()); } void JSSearch::SetCustomKeyboard(const JSCallbackInfo& info) { if (info.Length() > 0 && (info[0]->IsUndefined() || info[0]->IsNull())) { SearchModel::GetInstance()->SetCustomKeyboard(nullptr); return; } if (info.Length() < 1 || !info[0]->IsObject()) { return; } bool supportAvoidance = false; if (info.Length() == 2 && info[1]->IsObject()) { // 2 here refers to the number of parameters auto paramObject = JSRef::Cast(info[1]); auto isSupportAvoidance = paramObject->GetProperty("supportAvoidance"); if (!isSupportAvoidance->IsNull() && isSupportAvoidance->IsBoolean()) { supportAvoidance = isSupportAvoidance->ToBoolean(); } } std::function buildFunc; if (JSTextField::ParseJsCustomKeyboardBuilder(info, 0, buildFunc)) { SearchModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance); } } void JSSearch::SetType(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } if (info[0]->IsUndefined()) { SearchModel::GetInstance()->SetType(TextInputType::UNSPECIFIED); return; } if (!info[0]->IsNumber()) { return; } TextInputType textInputType = CastToTextInputType(info[0]->ToNumber()); SearchModel::GetInstance()->SetType(textInputType); } void JSSearchController::JSBind(BindingTarget globalObj) { JSClass::Declare("SearchController"); JSTextEditableController::JSBind(globalObj); } void JSSearch::SetEnterKeyType(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } if (info[0]->IsUndefined()) { SearchModel::GetInstance()->SetSearchEnterKeyType(TextInputAction::SEARCH); return; } if (!info[0]->IsNumber()) { return; } TextInputAction textInputAction = CastToTextInputAction(info[0]->ToNumber()); SearchModel::GetInstance()->SetSearchEnterKeyType(textInputAction); } void JSSearch::SetCapitalizationMode(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; auto autoCapitalizationMode = AutoCapitalizationMode::NONE; if (jsValue->IsUndefined() || !jsValue->IsNumber() || jsValue->IsNull()) { SearchModel::GetInstance()->SetSearchCapitalizationMode(autoCapitalizationMode); return; } if (jsValue->IsNumber()) { auto emunNumber = jsValue->ToNumber(); autoCapitalizationMode = CastToAutoCapitalizationMode(emunNumber); } SearchModel::GetInstance()->SetSearchCapitalizationMode(autoCapitalizationMode); } void JSSearch::SetMaxLength(const JSCallbackInfo& info) { int32_t maxLength = 0; if (info[0]->IsUndefined()) { SearchModel::GetInstance()->ResetMaxLength(); return; } else if (!info[0]->IsNumber()) { SearchModel::GetInstance()->ResetMaxLength(); return; } maxLength = info[0]->ToNumber(); if (std::isinf(info[0]->ToNumber())) { maxLength = INT32_MAX; // Infinity } if (GreatOrEqual(maxLength, 0)) { SearchModel::GetInstance()->SetMaxLength(maxLength); } else { SearchModel::GetInstance()->ResetMaxLength(); } } void JSSearch::SetDecoration(const JSCallbackInfo& info) { auto tmpInfo = info[0]; UnregisterResource("decorationColor"); if (!tmpInfo->IsObject()) { SearchModel::GetInstance()->SetTextDecoration(TextDecoration::NONE); SearchModel::GetInstance()->SetTextDecorationColor(Color::BLACK); SearchModel::GetInstance()->SetTextDecorationStyle(TextDecorationStyle::SOLID); return; } JSRef obj = JSRef::Cast(tmpInfo); JSRef typeValue = obj->GetProperty("type"); JSRef colorValue = obj->GetProperty("color"); JSRef styleValue = obj->GetProperty("style"); auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); TextDecoration textDecoration = theme->GetTextDecoration(); if (typeValue->IsNumber()) { textDecoration = static_cast(typeValue->ToNumber()); } Color result = theme->GetTextStyle().GetTextDecorationColor(); RefPtr resourceObject; ParseJsColor(colorValue, result, Color::BLACK, resourceObject); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("decorationColor", resourceObject, result); } std::optional textDecorationStyle; if (styleValue->IsNumber()) { textDecorationStyle = static_cast(styleValue->ToNumber()); } else { textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE; } SearchModel::GetInstance()->SetTextDecoration(textDecoration); SearchModel::GetInstance()->SetTextDecorationColor(result); if (textDecorationStyle) { SearchModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value()); } } void JSSearch::SetMinFontSize(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension minFontSize; RefPtr resourceObject; UnregisterResource("minFontSize"); if (!ParseJsDimensionFpNG(info[0], minFontSize, resourceObject, false)) { SearchModel::GetInstance()->SetAdaptMinFontSize(CalcDimension()); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("minFontSize", resourceObject, minFontSize); } if (minFontSize.IsNegative()) { minFontSize = CalcDimension(); } SearchModel::GetInstance()->SetAdaptMinFontSize(minFontSize); } void JSSearch::SetMaxFontSize(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize(); RefPtr resourceObject; UnregisterResource("maxFontSize"); if (!ParseJsDimensionFpNG(info[0], maxFontSize, resourceObject, false)) { maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize(); SearchModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("maxFontSize", resourceObject, maxFontSize); } if (maxFontSize.IsNegative()) { maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize(); } SearchModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize); } void JSSearch::SetMinFontScale(const JSCallbackInfo& info) { double minFontScale = 0.0; RefPtr resourceObject; if (info.Length() < 1 || !ParseJsDouble(info[0], minFontScale, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("minFontScale", resourceObject, minFontScale); } else { UnregisterResource("minFontScale"); } if (LessOrEqual(minFontScale, 0.0f)) { SearchModel::GetInstance()->SetMinFontScale(0.0f); return; } if (GreatOrEqual(minFontScale, 1.0f)) { SearchModel::GetInstance()->SetMinFontScale(1.0f); return; } SearchModel::GetInstance()->SetMinFontScale(static_cast(minFontScale)); } void JSSearch::SetMaxFontScale(const JSCallbackInfo& info) { double maxFontScale = 0.0; RefPtr resourceObject; if (info.Length() < 1 || !ParseJsDouble(info[0], maxFontScale, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("maxFontScale", resourceObject, maxFontScale); } else { UnregisterResource("maxFontScale"); } if (LessOrEqual(maxFontScale, 1.0f)) { SearchModel::GetInstance()->SetMaxFontScale(1.0f); return; } SearchModel::GetInstance()->SetMaxFontScale(static_cast(maxFontScale)); } void JSSearch::SetLetterSpacing(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; if (!ParseJsDimensionFpNG(info[0], value, resourceObject, false)) { value.Reset(); SearchModel::GetInstance()->SetLetterSpacing(value); UnregisterResource("letterSpacing"); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("letterSpacing", resourceObject, value); } SearchModel::GetInstance()->SetLetterSpacing(value); } void JSSearch::SetLineHeight(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; if (!ParseJsDimensionFpNG(info[0], value, resourceObject)) { value.Reset(); SearchModel::GetInstance()->SetLineHeight(value); UnregisterResource("lineHeight"); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("lineHeight", resourceObject, value); } if (value.IsNegative()) { value.Reset(); } SearchModel::GetInstance()->SetLineHeight(value); } void JSSearch::SetHalfLeading(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; bool halfLeading = jsValue->IsBoolean() ? jsValue->ToBoolean() : false; SearchModel::GetInstance()->SetHalfLeading(halfLeading); } void JSSearch::EditMenuOptions(const JSCallbackInfo& info) { NG::OnCreateMenuCallback onCreateMenuCallback; NG::OnMenuItemClickCallback onMenuItemClick; NG::OnPrepareMenuCallback onPrepareMenuCallback; JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick, onPrepareMenuCallback); SearchModel::GetInstance()->SetSelectionMenuOptions( std::move(onCreateMenuCallback), std::move(onMenuItemClick), std::move(onPrepareMenuCallback)); } void JSSearch::SetEnablePreviewText(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { SearchModel::GetInstance()->SetEnablePreviewText(true); return; } SearchModel::GetInstance()->SetEnablePreviewText(jsValue->ToBoolean()); } void JSSearch::SetEnableHapticFeedback(const JSCallbackInfo& info) { bool state = true; if (info.Length() > 0 && info[0]->IsBoolean()) { state = info[0]->ToBoolean(); } SearchModel::GetInstance()->SetEnableHapticFeedback(state); } void JSSearch::SetStopBackPress(const JSCallbackInfo& info) { bool isStopBackPress = true; if (info.Length() > 0 && info[0]->IsBoolean()) { isStopBackPress = info[0]->ToBoolean(); } SearchModel::GetInstance()->SetStopBackPress(isStopBackPress); } void JSSearch::SetKeyboardAppearance(const JSCallbackInfo& info) { if (info.Length() != 1 || !info[0]->IsNumber()) { SearchModel::GetInstance()->SetKeyboardAppearance( static_cast(KeyboardAppearance::NONE_IMMERSIVE)); return; } auto keyboardAppearance = info[0]->ToNumber(); if (keyboardAppearance < static_cast(KeyboardAppearance::NONE_IMMERSIVE) || keyboardAppearance > static_cast(KeyboardAppearance::DARK_IMMERSIVE)) { SearchModel::GetInstance()->SetKeyboardAppearance( static_cast(KeyboardAppearance::NONE_IMMERSIVE)); return; } SearchModel::GetInstance()->SetKeyboardAppearance( static_cast(keyboardAppearance)); } JSRef JSSearch::CreateJsOnWillChangeObj(const ChangeValueInfo& changeValueInfo) { JSRef ChangeValueInfo = JSRef::New(); ChangeValueInfo->SetProperty("content", changeValueInfo.value); auto previewTextObj = CreateJsOnChangeObj(changeValueInfo.previewText); ChangeValueInfo->SetPropertyObject("previewText", previewTextObj); auto optionsObj = JSRef::New(); auto rangeBeforeObj = JSRef::New(); rangeBeforeObj->SetProperty("start", changeValueInfo.rangeBefore.start); rangeBeforeObj->SetProperty("end", changeValueInfo.rangeBefore.end); optionsObj->SetPropertyObject("rangeBefore", rangeBeforeObj); auto rangeAfterObj = JSRef::New(); rangeAfterObj->SetProperty("start", changeValueInfo.rangeAfter.start); rangeAfterObj->SetProperty("end", changeValueInfo.rangeAfter.end); optionsObj->SetPropertyObject("rangeAfter", rangeAfterObj); optionsObj->SetProperty("oldContent", changeValueInfo.oldContent); auto oldPreviewTextObj = CreateJsOnChangeObj(changeValueInfo.oldPreviewText); optionsObj->SetPropertyObject("oldPreviewText", oldPreviewTextObj); ChangeValueInfo->SetPropertyObject("options", optionsObj); return JSRef::Cast(ChangeValueInfo); } void JSSearch::SetOnWillChange(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsChangeFunc = AceType::MakeRefPtr>( JSRef::Cast(jsValue), CreateJsOnWillChangeObj); auto onWillChange = [execCtx = info.GetExecutionContext(), func = std::move(jsChangeFunc)]( const ChangeValueInfo& changeValue) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true); ACE_SCORING_EVENT("onWillChange"); auto ret = func->ExecuteWithValue(changeValue); if (ret->IsBoolean()) { return ret->ToBoolean(); } return true; }; SearchModel::GetInstance()->SetOnWillChangeEvent(std::move(onWillChange)); } void JSSearch::SetStrokeWidth(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension value; if (!ParseLengthMetricsToDimension(info[0], value)) { value.Reset(); } SearchModel::GetInstance()->SetStrokeWidth(value); } void JSSearch::SetStrokeColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color strokeColor; if (!ParseJsColor(info[0], strokeColor)) { SearchModel::GetInstance()->ResetStrokeColor(); return; } SearchModel::GetInstance()->SetStrokeColor(strokeColor); } void JSSearch::SetEnableAutoSpacing(const JSCallbackInfo& info) { bool enabled = false; if (info.Length() > 0 && info[0]->IsBoolean()) { enabled = info[0]->ToBoolean(); } SearchModel::GetInstance()->SetEnableAutoSpacing(enabled); } void JSSearch::SetOnWillAttachIME(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsOnWillAttachIMEFunc = AceType::MakeRefPtr(JSRef::Cast(jsValue)); auto onWillAttachIME = [execCtx = info.GetExecutionContext(), func = std::move(jsOnWillAttachIMEFunc)]( const IMEClient& imeClientInfo) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("onWillAttachIME"); JSRef imeClientObj = JSRef::New(); imeClientObj->SetProperty("nodeId", imeClientInfo.nodeId); JSRef argv[] = { imeClientObj }; func->ExecuteJS(1, argv); }; SearchModel::GetInstance()->SetOnWillAttachIME(std::move(onWillAttachIME)); } void JSSearch::SetKeyboardAppearanceConfig(const JSCallbackInfo& info) { EcmaVM* vm = info.GetVm(); CHECK_NULL_VOID(vm); auto jsTargetNode = info[0]; auto* targetNodePtr = jsTargetNode->GetLocalHandle()->ToNativePointer(vm)->Value(); auto* frameNode = reinterpret_cast(targetNodePtr); CHECK_NULL_VOID(frameNode); if (!info[1]->IsObject()) { return; } NG::KeyboardAppearanceConfig config = JSTextField::ParseKeyboardAppearanceConfig(JSRef::Cast(info[1])); NG::SearchModelNG::SetKeyboardAppearanceConfig(frameNode, config); } void JSSearch::UnregisterResource(const std::string& key) { auto frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode(); CHECK_NULL_VOID(frameNode); auto pattern = frameNode->GetPattern(); CHECK_NULL_VOID(pattern); pattern->RemoveResObj(key); } void JSSearch::JsMargin(const JSCallbackInfo& info) { JSViewAbstract::JsMargin(info); SearchModel::GetInstance()->SetUserMargin(); } } // namespace OHOS::Ace::Framework