/* * Copyright (c) 2022-2024 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 "frameworks/bridge/declarative_frontend/jsview/js_textfield.h" #include #include #include #include #include "base/utils/utf_helper.h" #include "bridge/cj_frontend/interfaces/cj_ffi/utils.h" #include "interfaces/inner_api/ui_session/ui_session_manager.h" #include "base/geometry/dimension.h" #include "base/log/ace_scoring_log.h" #include "base/utils/utils.h" #include "bridge/common/utils/utils.h" #include "bridge/declarative_frontend/engine/functions/js_click_function.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_container_base.h" #include "bridge/declarative_frontend/jsview/js_interactable_view.h" #include "bridge/declarative_frontend/jsview/js_text_editable_controller.h" #include "bridge/declarative_frontend/jsview/js_textarea.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/text_field_model_impl.h" #include "core/common/container.h" #include "core/common/ime/text_input_action.h" #include "core/common/ime/text_input_type.h" #include "core/components/common/layout/constants.h" #include "core/components/common/properties/text_style_parser.h" #include "core/components/text_field/textfield_theme.h" #include "core/components_ng/base/view_abstract.h" #include "core/components_ng/pattern/text_field/text_content_type.h" #include "core/components_ng/pattern/text_field/text_field_model_ng.h" #include "core/image/image_source_info.h" #include "core/text/text_emoji_processor.h" namespace OHOS::Ace { std::unique_ptr TextFieldModel::instance_ = nullptr; std::mutex TextFieldModel::mutex_; TextFieldModel* TextFieldModel::GetInstance() { #ifdef NG_BUILD static NG::TextFieldModelNG instance; return &instance; #else if (Container::IsCurrentUseNewPipeline()) { static NG::TextFieldModelNG instance; return &instance; } else { static Framework::TextFieldModelImpl instance; return &instance; } #endif } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { const std::vector TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END, TextAlign::JUSTIFY }; const std::vector LINE_BREAK_STRATEGY_TYPES = { LineBreakStrategy::GREEDY, LineBreakStrategy::HIGH_QUALITY, LineBreakStrategy::BALANCED }; const std::vector FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC }; const std::vector INPUT_FONT_FAMILY_VALUE = { "sans-serif" }; const std::vector WORD_BREAK_TYPES = { WordBreak::NORMAL, WordBreak::BREAK_ALL, WordBreak::BREAK_WORD, WordBreak::HYPHENATION }; const std::vector TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS, TextOverflow::MARQUEE, TextOverflow::DEFAULT }; const std::vector ELLIPSIS_MODALS = { EllipsisMode::HEAD, EllipsisMode::MIDDLE, EllipsisMode::TAIL }; constexpr uint32_t MAX_LINES = 3; constexpr uint32_t MINI_VAILD_VALUE = 1; constexpr uint32_t MAX_VAILD_VALUE = 100; constexpr uint32_t ILLEGAL_VALUE = 0; constexpr uint32_t DEFAULT_MODE = -1; constexpr uint32_t DEFAULT_OVERFLOW = 4; constexpr double DEFAULT_OPACITY = 0.2; const int32_t DEFAULT_ALPHA = 255; const char* TOP_START_PROPERTY = "topStart"; const char* TOP_END_PROPERTY = "topEnd"; const char* BOTTOM_START_PROPERTY = "bottomStart"; const char* BOTTOM_END_PROPERTY = "bottomEnd"; const std::vector HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST, TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST }; constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID; 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 ParseTextFieldTextObject(const JSCallbackInfo& info, const JSRef& changeEventVal) { CHECK_NULL_VOID(changeEventVal->IsFunction()); JsEventCallback onChangeEvent( info.GetExecutionContext(), JSRef::Cast(changeEventVal)); TextFieldModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent)); } void ParseTextProperty(const JSRef& textValue, std::optional& value, std::u16string& text) { if (JSViewAbstract::ParseJsString(textValue, text)) { value = text; } if (textValue->IsUndefined()) { value = u""; } } bool JSTextField::ParseText(const JSRef& paramObject, std::optional& value, JSRef& changeEventVal, std::u16string& text, RefPtr& textObject) { bool textResult = false; JSRef textValue = paramObject->GetProperty("text"); if (textValue->IsObject()) { JSRef valueObj = JSRef::Cast(textValue); changeEventVal = valueObj->GetProperty("changeEvent"); if (changeEventVal->IsFunction()) { textValue = valueObj->GetProperty("value"); } value = u""; textResult = ParseJsString(textValue, text, textObject); if (textResult) { value = text; } } else if (paramObject->GetProperty("$text")->IsFunction()) { changeEventVal = paramObject->GetProperty("$text"); value = u""; textResult = ParseJsString(textValue, text, textObject); if (textResult) { value = text; } } else if (paramObject->HasProperty("text")) { textResult = ParseJsString(textValue, text, textObject); if (textResult) { value = text; } if (textValue->IsUndefined()) { value = u""; } } return textResult; } void JSTextField::CreateTextInput(const JSCallbackInfo& info) { std::optional placeholderSrc; std::optional value; bool placeholderResult = false; bool textResult = false; std::u16string placeholder; std::u16string text; RefPtr placeholderObject; RefPtr textObject; JSTextEditableController* jsController = nullptr; JSRef changeEventVal = JSRef::Make(); auto jsValue = info[0]; if (jsValue->IsObject()) { auto paramObject = JSRef::Cast(jsValue); placeholderResult = ParseJsString(paramObject->GetProperty("placeholder"), placeholder, placeholderObject); if (placeholderResult) { placeholderSrc = placeholder; } JSRef textValue = paramObject->GetProperty("text"); textResult = ParseText(paramObject, value, changeEventVal, text, textObject); auto controllerObj = paramObject->GetProperty("controller"); if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) { jsController = JSRef::Cast(controllerObj)->Unwrap(); } } auto controller = TextFieldModel::GetInstance()->CreateTextInput(placeholderSrc, value); if (jsController) { jsController->SetController(controller); } if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) { ParseTextFieldTextObject(info, changeEventVal); } TextFieldModel::GetInstance()->SetFocusableAndFocusNode(); if (SystemProperties::ConfigChangePerform()) { UnregisterResource("placeholder"); if (placeholderResult && placeholderObject) { RegisterResource("placeholder", placeholderObject, placeholder); } } if (SystemProperties::ConfigChangePerform()) { UnregisterResource("text"); if (textResult && textObject) { RegisterResource("text", textObject, text); } } } void JSTextField::CreateTextArea(const JSCallbackInfo& info) { std::optional placeholderSrc; std::optional value; bool placeholderResult = false; bool textResult = false; std::u16string placeholder; std::u16string text; RefPtr placeholderObject; RefPtr textObject; JSTextEditableController* jsController = nullptr; JSRef changeEventVal = JSRef::Make(); auto jsValue = info[0]; if (jsValue->IsObject()) { auto paramObject = JSRef::Cast(jsValue); placeholderResult = ParseJsString(paramObject->GetProperty("placeholder"), placeholder, placeholderObject); if (placeholderResult) { placeholderSrc = placeholder; } JSRef textValue = paramObject->GetProperty("text"); textResult = ParseText(paramObject, value, changeEventVal, text, textObject); auto controllerObj = paramObject->GetProperty("controller"); if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) { jsController = JSRef::Cast(controllerObj)->Unwrap(); } } auto controller = TextFieldModel::GetInstance()->CreateTextArea(placeholderSrc, value); if (jsController) { jsController->SetController(controller); } if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) { ParseTextFieldTextObject(info, changeEventVal); } TextFieldModel::GetInstance()->SetFocusableAndFocusNode(); if (SystemProperties::ConfigChangePerform()) { UnregisterResource("placeholder"); if (placeholderResult && placeholderObject) { RegisterResource("placeholder", placeholderObject, placeholder); } } if (SystemProperties::ConfigChangePerform()) { UnregisterResource("text"); if (textResult && textObject) { RegisterResource("text", textObject, text); } } } void JSTextField::SetType(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined()) { TextFieldModel::GetInstance()->SetType(TextInputType::UNSPECIFIED); return; } if (!jsValue->IsNumber()) { return; } TextInputType textInputType = CastToTextInputType(jsValue->ToNumber()); TextFieldModel::GetInstance()->SetType(textInputType); } void JSTextField::SetContentType(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined()) { TextFieldModel::GetInstance()->SetContentType(NG::TextContentType::UNSPECIFIED); return; } if (!jsValue->IsNumber()) { return; } NG::TextContentType textContentType = static_cast(jsValue->ToNumber()); TextFieldModel::GetInstance()->SetContentType(textContentType); } void JSTextField::SetPlaceholderColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto theme = GetTheme(); CHECK_NULL_VOID(theme); Color color = theme->GetPlaceholderColor(); RefPtr resourceObject; UnregisterResource("placeholderColor"); if (!CheckColor(info[0], color, V2::TEXTINPUT_ETS_TAG, "PlaceholderColor", resourceObject)) { TextFieldModel::GetInstance()->ResetPlaceholderColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("placeholderColor", resourceObject, color); } TextFieldModel::GetInstance()->SetPlaceholderColor(color); } void JSTextField::SetPlaceholderFont(const JSCallbackInfo& info) { if (info.Length() < 1 || !info[0]->IsObject()) { return; } auto theme = GetTheme(); CHECK_NULL_VOID(theme); Font font; auto paramObject = JSRef::Cast(info[0]); auto fontSize = paramObject->GetProperty("size"); RefPtr resourceObject; UnregisterResource("placeholderFontSize"); if (fontSize->IsNull() || fontSize->IsUndefined()) { font.fontSize = Dimension(-1); } else { CalcDimension size; if (fontSize->IsString()) { auto result = StringUtils::StringToDimensionWithThemeValue( fontSize->ToString(), true, Dimension(theme->GetFontSize())); if (result.Unit() == DimensionUnit::PERCENT) { result = theme->GetFontSize(); } font.fontSize = result; } else if (ParseJsDimensionFp(fontSize, size, resourceObject) && size.Unit() != DimensionUnit::PERCENT) { font.fontSize = size; } else { font.fontSize = Dimension(theme->GetFontSize()); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("placeholderFontSize", resourceObject, size); } } std::string weight; auto fontWeight = paramObject->GetProperty("weight"); if (!fontWeight->IsNull()) { if (fontWeight->IsNumber()) { weight = std::to_string(fontWeight->ToNumber()); } else { ParseJsString(fontWeight, weight); } font.fontWeight = ConvertStrToFontWeight(weight); } auto fontFamily = paramObject->GetProperty("family"); UnregisterResource("placeholderFontFamily"); if (!fontFamily->IsNull()) { std::vector fontFamilies; RefPtr resourceObject; if (ParseJsFontFamilies(fontFamily, fontFamilies, resourceObject)) { font.fontFamilies = fontFamilies; if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource>("placeholderFontFamily", resourceObject, fontFamilies); } } } auto style = paramObject->GetProperty("style"); if (!style->IsNull()) { font.fontStyle = static_cast(style->ToNumber()); } TextFieldModel::GetInstance()->SetPlaceholderFont(font); } void JSTextField::SetEnterKeyType(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined()) { TextFieldModel::GetInstance()->SetEnterKeyType(TextInputAction::UNSPECIFIED); return; } if (!jsValue->IsNumber()) { return; } TextInputAction textInputAction = CastToTextInputAction(jsValue->ToNumber()); TextFieldModel::GetInstance()->SetEnterKeyType(textInputAction); } void JSTextField::SetCapitalizationMode(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; auto autoCapitalizationMode = AutoCapitalizationMode::NONE; if (jsValue->IsUndefined() || !jsValue->IsNumber() || jsValue->IsNull()) { TextFieldModel::GetInstance()->SetCapitalizationMode(autoCapitalizationMode); return; } if (jsValue->IsNumber()) { auto emunNumber = jsValue->ToNumber(); autoCapitalizationMode = CastToAutoCapitalizationMode(emunNumber); } TextFieldModel::GetInstance()->SetCapitalizationMode(autoCapitalizationMode); } void JSTextField::SetTextAlign(int32_t value) { if (value >= 0 && value < static_cast(TEXT_ALIGNS.size())) { TextFieldModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]); } } void JSTextField::SetLineBreakStrategy(const JSCallbackInfo& info) { if (info.Length() < 1) { TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY); return; } if (!info[0]->IsNumber()) { TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY); return; } auto index = info[0]->ToNumber(); if (index < 0 || index >= static_cast(LINE_BREAK_STRATEGY_TYPES.size())) { TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY); return; } TextFieldModel::GetInstance()->SetLineBreakStrategy(LINE_BREAK_STRATEGY_TYPES[index]); } void JSTextField::SetInputStyle(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto styleString = info[0]->ToString(); if (styleString == "Inline") { TextFieldModel::GetInstance()->SetInputStyle(InputStyle::INLINE); } else { TextFieldModel::GetInstance()->SetInputStyle(InputStyle::DEFAULT); } } void JSTextField::SetCaretColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color color; RefPtr resourceObject; UnregisterResource("caretColor"); if (!ParseJsColor(info[0], color, resourceObject)) { TextFieldModel::GetInstance()->ResetCaretColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("caretColor", resourceObject, color); } TextFieldModel::GetInstance()->SetCaretColor(color); } void JSTextField::SetCaretStyle(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } UnregisterResource("caretWidth"); UnregisterResource("caretColor"); auto jsValue = info[0]; if (jsValue->IsObject()) { CaretStyle caretStyle; auto paramObject = JSRef::Cast(jsValue); auto caretWidth = paramObject->GetProperty("width"); auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck(); CHECK_NULL_VOID(pipeline); auto theme = pipeline->GetThemeManager()->GetTheme(); CHECK_NULL_VOID(theme); if (caretWidth->IsNull() || caretWidth->IsUndefined()) { caretStyle.caretWidth = theme->GetCursorWidth(); } else { CalcDimension width; RefPtr widthObject; if (!ParseJsDimensionVpNG(caretWidth, width, widthObject, false)) { width = theme->GetCursorWidth(); } if (SystemProperties::ConfigChangePerform() && widthObject) { RegisterResource("caretWidth", widthObject, width); } if (LessNotEqual(width.Value(), 0.0)) { width = theme->GetCursorWidth(); } caretStyle.caretWidth = width; } TextFieldModel::GetInstance()->SetCaretStyle(caretStyle); // set caret color Color caretColor; if (!paramObject->HasProperty("color")) { return; } else { auto caretColorProp = paramObject->GetProperty("color"); RefPtr colorObject; if (caretColorProp->IsUndefined() || caretColorProp->IsNull() || !ParseJsColor(caretColorProp, caretColor, colorObject)) { caretColor = theme->GetCursorColor(); } if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("caretColor", colorObject, caretColor); } TextFieldModel::GetInstance()->SetCaretColor(caretColor); } } } void JSTextField::SetCaretPosition(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } int32_t caretPosition = 0; auto tempInfo = info[0]; if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) { if (!ParseJsInt32(tempInfo, caretPosition) || caretPosition < 0) { caretPosition = 0; } } else { if (!ParseJsInt32(tempInfo, caretPosition)) { return; } if (caretPosition < 0) { return; } } TextFieldModel::GetInstance()->SetCaretPosition(caretPosition); } void JSTextField::SetSelectedBackgroundColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color selectedColor; RefPtr resourceObject; UnregisterResource("selectedBackgroundColor"); if (!ParseJsColor(info[0], selectedColor, resourceObject)) { auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck(); CHECK_NULL_VOID(pipeline); auto theme = pipeline->GetThemeManager()->GetTheme(); CHECK_NULL_VOID(theme); selectedColor = theme->GetSelectedColor(); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("selectedBackgroundColor", resourceObject, selectedColor); } if (selectedColor.GetAlpha() == DEFAULT_ALPHA) { selectedColor = selectedColor.ChangeOpacity(DEFAULT_OPACITY); } TextFieldModel::GetInstance()->SetSelectedBackgroundColor(selectedColor); } void JSTextField::SetMaxLength(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; int32_t maxLength = 0; if (jsValue->IsUndefined()) { TextFieldModel::GetInstance()->ResetMaxLength(); return; } else if (!jsValue->IsNumber()) { TextFieldModel::GetInstance()->ResetMaxLength(); return; } maxLength = jsValue->ToNumber(); if (std::isinf(jsValue->ToNumber())) { maxLength = INT32_MAX; // Infinity } if (GreatOrEqual(maxLength, 0)) { TextFieldModel::GetInstance()->SetMaxLength(maxLength); } else { TextFieldModel::GetInstance()->ResetMaxLength(); } } void JSTextField::SetFontSize(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension fontSize; RefPtr resourceObject; UnregisterResource("fontSize"); if (!ParseJsDimensionNG(info[0], fontSize, DimensionUnit::FP, resourceObject, false)) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); fontSize = theme->GetFontSize(); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("fontSize", resourceObject, fontSize); } TextFieldModel::GetInstance()->SetFontSize(fontSize); } void JSTextField::SetFontWeight(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } UnregisterResource("fontWeight"); JSRef args = info[0]; std::string fontWeight; if (args->IsNumber()) { fontWeight = args->ToString(); } else { RefPtr resourceObject; ParseJsString(args, fontWeight, resourceObject); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("fontWeight", resourceObject, fontWeight); } } FontWeight formatFontWeight = ConvertStrToFontWeight(fontWeight); TextFieldModel::GetInstance()->SetFontWeight(formatFontWeight); } void JSTextField::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)) { TextFieldModel::GetInstance()->SetMinFontScale(0.0f); return; } if (GreatOrEqual(minFontScale, 1.0f)) { TextFieldModel::GetInstance()->SetMinFontScale(1.0f); return; } TextFieldModel::GetInstance()->SetMinFontScale(static_cast(minFontScale)); } void JSTextField::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)) { TextFieldModel::GetInstance()->SetMaxFontScale(1.0f); return; } TextFieldModel::GetInstance()->SetMaxFontScale(static_cast(maxFontScale)); } void JSTextField::SetTextColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color textColor; RefPtr resourceObject; if (!ParseJsColor(info[0], textColor, resourceObject)) { UnregisterResource("fontColor"); TextFieldModel::GetInstance()->ResetTextColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("fontColor", resourceObject, textColor); } TextFieldModel::GetInstance()->SetTextColor(textColor); } void JSTextField::SetWordBreak(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (!jsValue->IsNumber()) { TextFieldModel::GetInstance()->SetWordBreak(WordBreak::BREAK_WORD); return; } auto index = jsValue->ToNumber(); if (index < 0 || index >= static_cast(WORD_BREAK_TYPES.size())) { TextFieldModel::GetInstance()->SetWordBreak(WordBreak::BREAK_WORD); return; } TextFieldModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]); } void JSTextField::SetForegroundColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } UnregisterResource("foregroundColor"); auto jsValue = info[0]; ForegroundColorStrategy strategy; if (ParseJsColorStrategy(jsValue, strategy)) { ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy); TextFieldModel::GetInstance()->SetForegroundColor(Color::FOREGROUND); return; } Color foregroundColor; RefPtr resourceObject; if (!ParseJsColor(jsValue, foregroundColor, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("foregroundColor", resourceObject, foregroundColor); } ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor); TextFieldModel::GetInstance()->SetForegroundColor(foregroundColor); } void JSTextField::SetFontStyle(int32_t value) { if (value >= 0 && value < static_cast(FONT_STYLES.size())) { TextFieldModel::GetInstance()->SetFontStyle(FONT_STYLES[value]); } } void JSTextField::SetFontFamily(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } std::vector fontFamilies; RefPtr resourceObject; if (!ParseJsFontFamilies(info[0], fontFamilies, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource>("fontFamily", resourceObject, fontFamilies); } else { UnregisterResource("fontFamily"); } TextFieldModel::GetInstance()->SetFontFamily(fontFamilies); } void JSTextField::SetInputFilter(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; std::string inputFilter; if (jsValue->IsUndefined()) { UnregisterResource("inputFilter"); TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr); return; } RefPtr resourceObject; if (!ParseJsString(jsValue, inputFilter, resourceObject)) { return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("inputFilter", resourceObject, inputFilter); } else { UnregisterResource("inputFilter"); } if (!CheckRegexValid(inputFilter)) { inputFilter = ""; } if (info.Length() > 1 && info[1]->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef::Cast(info[1])); 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); }; TextFieldModel::GetInstance()->SetInputFilter(inputFilter, resultId); return; } TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr); } void JSTextField::SetShowPasswordIcon(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetShowPasswordIcon(true); return; } bool isShowPasswordIcon = jsValue->ToBoolean(); TextFieldModel::GetInstance()->SetShowPasswordIcon(isShowPasswordIcon); } void JSTextField::ShowPasswordText(const JSCallbackInfo& info) { auto tmpInfo = info[0]; if (!tmpInfo->IsBoolean()) { TextFieldModel::GetInstance()->SetShowPasswordText(false); return; } bool showPassword = tmpInfo->ToBoolean(); TextFieldModel::GetInstance()->SetShowPasswordText(showPassword); } void JSTextField::SetBackgroundColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color backgroundColor; RefPtr resourceObject; if (!ParseJsColor(info[0], backgroundColor, resourceObject)) { UnregisterResource("backgroundColor"); TextFieldModel::GetInstance()->ResetBackgroundColor(); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("backgroundColor", resourceObject, backgroundColor); } TextFieldModel::GetInstance()->SetBackgroundColor(backgroundColor, false); } void JSTextField::JsHeight(const JSCallbackInfo& info) { JSViewAbstract::JsHeight(info); if (info.Length() < 1) { return; } CalcDimension value; auto jsValue = info[0]; if (!ParseJsDimensionVp(jsValue, value)) { SetLayoutPolicy(jsValue, false); return; } if (LessNotEqual(value.Value(), 0.0)) { ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false); return; } TextFieldModel::GetInstance()->SetHeight(value); } void JSTextField::JsWidth(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } UnregisterResource("width"); auto jsValue = info[0]; if (jsValue->IsString() && jsValue->ToString().empty()) { return; } if (jsValue->IsString() && jsValue->ToString() == "auto") { ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true); TextFieldModel::GetInstance()->SetWidthAuto(true); SetLayoutPolicy(jsValue, true); return; } TextFieldModel::GetInstance()->SetWidthAuto(false); CalcDimension value; RefPtr resourceObject; if (!ParseJsDimensionVp(jsValue, value, resourceObject)) { SetLayoutPolicy(jsValue, true); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("width", resourceObject, value); } if (LessNotEqual(value.Value(), 0.0)) { return; } ViewAbstractModel::GetInstance()->SetWidth(value); } bool CheckIsIllegalString(const std::string& value) { if (value.empty()) { return true; } errno = 0; char* pEnd = nullptr; std::strtod(value.c_str(), &pEnd); return (pEnd == value.c_str() || errno == ERANGE); } void JSTextField::JsMargin(const JSCallbackInfo& info) { JSViewAbstract::JsMargin(info); TextFieldModel::GetInstance()->SetMargin(); } void JSTextField::JsPadding(const JSCallbackInfo& info) { auto jsValue = info[0]; if (jsValue->IsUndefined() || (jsValue->IsString() && CheckIsIllegalString(jsValue->ToString()))) { return; }; CalcDimension length; ParseJsDimensionVp(jsValue, length); if (length.IsNegative()) { TextFieldModel::GetInstance()->SetPadding(NG::PaddingProperty(), Edge(), true, false); return; } bool tmp = !jsValue->IsString() && !jsValue->IsNumber() && !jsValue->IsObject(); bool hasRegist = false; NG::PaddingProperty newPadding = GetNewPadding(info, hasRegist); Edge oldPadding = Edge(GetOldPadding(info)); TextFieldModel::GetInstance()->SetPadding(newPadding, oldPadding, tmp, hasRegist); } Edge JSTextField::GetOldPadding(const JSCallbackInfo& info) { Edge padding; auto jsValue = info[0]; if (jsValue->IsNumber() || jsValue->IsString()) { CalcDimension edgeValue; if (ParseJsDimensionVp(jsValue, edgeValue)) { padding = Edge(edgeValue); } } if (jsValue->IsObject()) { JSRef object = JSRef::Cast(jsValue); CalcDimension left = CalcDimension(0.0, DimensionUnit::VP); CalcDimension top = CalcDimension(0.0, DimensionUnit::VP); CalcDimension right = CalcDimension(0.0, DimensionUnit::VP); CalcDimension bottom = CalcDimension(0.0, DimensionUnit::VP); ParseJsDimensionVp(object->GetProperty("left"), left); ParseJsDimensionVp(object->GetProperty("top"), top); ParseJsDimensionVp(object->GetProperty("right"), right); ParseJsDimensionVp(object->GetProperty("bottom"), bottom); padding = Edge(left, top, right, bottom); } return padding; } NG::PaddingProperty JSTextField::GetNewPadding(const JSCallbackInfo& info, bool& hasRegist) { NG::PaddingProperty padding; auto jsValue = info[0]; if (jsValue->IsObject()) { JSRef paddingObj = JSRef::Cast(jsValue); CommonCalcDimension commonCalcDimension; ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension); if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() || commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) { padding = GetEdgePaddingsOrSafeAreaPaddings(commonCalcDimension); return padding; } } CalcDimension length; RefPtr lengthResObj; if (!ParseJsDimensionVp(jsValue, length, lengthResObj)) { // use default value. length.Reset(); } if (SystemProperties::ConfigChangePerform() && lengthResObj) { NG::ViewAbstract::SetPadding(lengthResObj); hasRegist = true; return padding; } padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension())); return padding; } NG::PaddingProperty JSTextField::SetPaddings(const std::optional& top, const std::optional& bottom, const std::optional& left, const std::optional& right) { NG::PaddingProperty paddings; if (top.has_value()) { if (top.value().Unit() == DimensionUnit::CALC) { paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue()); } else { paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension()); } } if (bottom.has_value()) { if (bottom.value().Unit() == DimensionUnit::CALC) { paddings.bottom = NG::CalcLength( bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue()); } else { paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension()); } } if (left.has_value()) { if (left.value().Unit() == DimensionUnit::CALC) { paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue()); } else { paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension()); } } if (right.has_value()) { if (right.value().Unit() == DimensionUnit::CALC) { paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue()); } else { paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension()); } } return paddings; } void JSTextField::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); } // 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); } TextFieldModel::GetInstance()->SetBackBorder(); info.ReturnSelf(); } void JSTextField::JsBorderWidth(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsObject() && !jsValue->IsString() && !jsValue->IsNumber()) { return; } JSViewAbstract::JsBorderWidth(info); TextFieldModel::GetInstance()->SetBackBorder(); } void JSTextField::JsBorderColor(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsObject() && !jsValue->IsString() && !jsValue->IsNumber()) { return; } JSViewAbstract::JsBorderColor(info); TextFieldModel::GetInstance()->SetBackBorder(); } void JSTextField::JsBorderStyle(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsObject() && !jsValue->IsNumber()) { return; } JSViewAbstract::JsBorderStyle(info); TextFieldModel::GetInstance()->SetBackBorder(); } void JSTextField::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 JSTextField::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 JSTextField::ParseBorderRadius(const JSRef& args) { CalcDimension borderRadius; if (ParseJsDimensionVp(args, borderRadius)) { ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius); } else if (args->IsObject()) { JSRef object = JSRef::Cast(args); CalcDimension topLeft; CalcDimension topRight; CalcDimension bottomLeft; CalcDimension bottomRight; 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 JSTextField::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); TextFieldModel::GetInstance()->SetBackBorder(); } void JSTextField::JsHoverEffect(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsNumber()) { return; } TextFieldModel::GetInstance()->SetHoverEffect(static_cast(jsValue->ToNumber())); } void JSTextField::SetOnEditChanged(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnEditChanged(std::move(callback)); } Local JSTextField::JsKeepEditableState(panda::JsiRuntimeCallInfo *info) { Local thisObj = info->GetThisRef(); auto eventInfo = static_cast( panda::Local(thisObj)->GetNativePointerField(info->GetVM(), 0)); if (eventInfo) { eventInfo->SetKeepEditable(true); } return JSValueRef::Undefined(info->GetVM()); } void JSTextField::CreateJsTextFieldCommonEvent(const JSCallbackInfo &info) { if (info.Length() < 1 || !info[0]->IsObject()) { return; } auto jsValue = info[0]; auto jsTextFunc = AceType::MakeRefPtr>( JSRef::Cast(jsValue)); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](int32_t key, 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(JsKeepEditableState)); object->Wrap(&event); JSRef keyEvent = JSRef::Make(ToJSValue(key)); JSRef dataObject = JSRef::Cast(object); JSRef param[2] = {keyEvent, dataObject}; func->Execute(param); UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onSubmit"); }; TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback)); } void JSTextField::SetOnSubmit(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); #ifdef NG_BUILD CreateJsTextFieldCommonEvent(info); #else if (Container::IsCurrentUseNewPipeline()) { CreateJsTextFieldCommonEvent(info); } else { JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback)); } #endif } JSRef JSTextField::CreateJsOnChangeObj(const PreviewText& previewText) { JSRef previewTextObj = JSRef::New(); previewTextObj->SetProperty("offset", previewText.offset); previewTextObj->SetProperty("value", previewText.value); return JSRef::Cast(previewTextObj); } void JSTextField::SetOnChange(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); }; TextFieldModel::GetInstance()->SetOnChange(std::move(onChange)); } void JSTextField::SetOnTextSelectionChange(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnTextSelectionChange(std::move(callback)); } void JSTextField::SetOnSecurityStateChange(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnSecurityStateChange(std::move(callback)); } void JSTextField::SetOnContentScroll(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnContentScroll(std::move(callback)); } void JSTextField::SetOnCopy(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnCopy(std::move(callback)); } void JSTextField::SetOnCut(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(jsValue)); TextFieldModel::GetInstance()->SetOnCut(std::move(callback)); } JSRef JSTextField::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 JSTextField::SetOnPaste(const JSCallbackInfo& info) { auto jsValue = info[0]; CHECK_NULL_VOID(jsValue->IsFunction()); auto jsTextFunc = AceType::MakeRefPtr>( JSRef::Cast(jsValue), 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); }; TextFieldModel::GetInstance()->SetOnPasteWithEvent(std::move(onPaste)); } void JSTextField::SetOnClick(const JSCallbackInfo& info) { if (Container::IsCurrentUseNewPipeline()) { JSInteractableView::JsOnClick(info); return; } JsEventCallback callback(info.GetExecutionContext(), JSRef::Cast(info[0])); TextFieldModel::GetInstance()->SetOnClick(std::move(callback)); info.ReturnSelf(); } void JSTextField::SetCopyOption(const JSCallbackInfo& info) { if (info.Length() == 0) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined()) { TextFieldModel::GetInstance()->SetCopyOption(CopyOptions::Local); return; } auto copyOptions = CopyOptions::Local; if (jsValue->IsNumber()) { auto emunNumber = jsValue->ToNumber(); copyOptions = static_cast(emunNumber); } TextFieldModel::GetInstance()->SetCopyOption(copyOptions); } void JSTextField::SetShowUnderline(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetShowUnderline(false); return; } TextFieldModel::GetInstance()->SetShowUnderline(jsValue->ToBoolean()); } void JSTextField::SetUnderlineColorObject(const JSRef& param) { UnregisterResource("underlineColorTyping"); UnregisterResource("underlineColorNormal"); UnregisterResource("underlineColorError"); UnregisterResource("underlineColorDisable"); UserUnderlineColor userColor = UserUnderlineColor(); auto typingColorProp = param->GetProperty("typing"); Color typing; RefPtr typingObject; if (ParseJsColor(typingColorProp, typing, typingObject)) { userColor.typing = typing; if (SystemProperties::ConfigChangePerform() && typingObject) { RegisterResource("underlineColorTyping", typingObject, typing); } } auto normalColorProp = param->GetProperty("normal"); Color normal; RefPtr normalObject; if (ParseJsColor(normalColorProp, normal, normalObject)) { userColor.normal = normal; if (SystemProperties::ConfigChangePerform() && normalObject) { RegisterResource("underlineColorNormal", normalObject, normal); } } auto errorColorProp = param->GetProperty("error"); Color error; RefPtr errorObject; if (ParseJsColor(errorColorProp, error, errorObject)) { userColor.error = error; if (SystemProperties::ConfigChangePerform() && errorObject) { RegisterResource("underlineColorError", errorObject, error); } } auto disableColorProp = param->GetProperty("disable"); Color disable; RefPtr disableObject; if (ParseJsColor(disableColorProp, disable, disableObject)) { userColor.disable = disable; if (SystemProperties::ConfigChangePerform() && disableObject) { RegisterResource("underlineColorDisable", disableObject, disable); } } TextFieldModel::GetInstance()->SetUserUnderlineColor(userColor); } void JSTextField::SetUnderlineColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; Color underlineColor; RefPtr resourceObject; if (ParseJsColor(jsValue, underlineColor, resourceObject)) { TextFieldModel::GetInstance()->SetNormalUnderlineColor(underlineColor); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("underlineColorNormal", resourceObject, underlineColor); } else { UnregisterResource("underlineColorNormal"); } } else if (jsValue->IsObject()) { SetUnderlineColorObject(JSRef::Cast(jsValue)); } else { TextFieldModel::GetInstance()->SetUserUnderlineColor(UserUnderlineColor()); if (SystemProperties::ConfigChangePerform()) { UnregisterResource("underlineColorTyping"); UnregisterResource("underlineColorNormal"); UnregisterResource("underlineColorError"); UnregisterResource("underlineColorDisable"); } } } void JSTextField::ParseOnIconSrc(const JSRef& showVal, PasswordIcon& passwordIcon) { UnregisterResource("onIconSrc"); if (showVal->IsString()) { passwordIcon.showResult = showVal->ToString(); } if (showVal->IsObject()) { JSRef bundleName = JSRef::Cast(showVal)->GetProperty("bundleName"); JSRef moduleName = JSRef::Cast(showVal)->GetProperty("moduleName"); if (bundleName->IsString()) { passwordIcon.showBundleName = bundleName->ToString(); } if (moduleName->IsString()) { passwordIcon.showModuleName = moduleName->ToString(); } RefPtr resourceObject; ParseJsMedia(JSRef::Cast(showVal), passwordIcon.showResult, resourceObject); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("onIconSrc", resourceObject, passwordIcon.showResult); } } if (!showVal->IsString() && !showVal->IsObject()) { passwordIcon.showResult = ""; } } void JSTextField::ParseOffIconSrc(const JSRef& hideVal, PasswordIcon& passwordIcon) { UnregisterResource("offIconSrc"); if (hideVal->IsString()) { passwordIcon.hideResult = hideVal->ToString(); } if (hideVal->IsObject()) { JSRef bundleName = JSRef::Cast(hideVal)->GetProperty("bundleName"); JSRef moduleName = JSRef::Cast(hideVal)->GetProperty("moduleName"); if (bundleName->IsString()) { passwordIcon.hideBundleName = bundleName->ToString(); } if (moduleName->IsString()) { passwordIcon.hideModuleName = moduleName->ToString(); } RefPtr resourceObject; ParseJsMedia(JSRef::Cast(hideVal), passwordIcon.hideResult); if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("offIconSrc", resourceObject, passwordIcon.hideResult); } } if (!hideVal->IsString() && !hideVal->IsObject()) { passwordIcon.hideResult = ""; } } void JSTextField::SetPasswordIcon(const JSCallbackInfo& info) { if (!Container::IsCurrentUseNewPipeline()) { return; } auto jsValue = info[0]; if (!jsValue->IsObject()) { return; } JSRef jsObj = JSRef::Cast(jsValue); JSRef showVal = jsObj->GetProperty("onIconSrc"); JSRef hideVal = jsObj->GetProperty("offIconSrc"); PasswordIcon passwordIcon; ParseOnIconSrc(showVal, passwordIcon); ParseOffIconSrc(hideVal, passwordIcon); TextFieldModel::GetInstance()->SetPasswordIcon(passwordIcon); } void JSTextField::UpdateDecoration(const RefPtr& boxComponent, const RefPtr& component, const Border& boxBorder, const OHOS::Ace::RefPtr& textFieldTheme) { if (!textFieldTheme) { return; } RefPtr decoration = component->GetDecoration(); RefPtr boxDecoration = boxComponent->GetBackDecoration(); if (!decoration) { decoration = AceType::MakeRefPtr(); } if (boxDecoration) { Border border = decoration->GetBorder(); border.SetLeftEdge(boxBorder.Left()); border.SetRightEdge(boxBorder.Right()); border.SetTopEdge(boxBorder.Top()); border.SetBottomEdge(boxBorder.Bottom()); border.SetBorderRadius(textFieldTheme->GetBorderRadius()); decoration->SetBorder(border); component->SetOriginBorder(decoration->GetBorder()); if (boxDecoration->GetImage() || boxDecoration->GetGradient().IsValid()) { // clear box properties except background image and radius. boxDecoration->SetBackgroundColor(Color::TRANSPARENT); Border border; border.SetBorderRadius(textFieldTheme->GetBorderRadius()); boxDecoration->SetBorder(border); } } else { boxDecoration = AceType::MakeRefPtr(); boxDecoration->SetBorderRadius(textFieldTheme->GetBorderRadius()); boxComponent->SetBackDecoration(boxDecoration); } } void JSTextField::SetShowUnit(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsFunction()) { TextFieldModel::GetInstance()->SetShowUnit(nullptr); return; } auto builderFunc = AceType::MakeRefPtr(JSRef::Cast(jsValue)); auto unitFunc = [builderFunc]() { builderFunc->Execute(); }; TextFieldModel::GetInstance()->SetShowUnit(std::move(unitFunc)); } void JSTextField::SetShowError(const JSCallbackInfo& info) { auto jsValue = info[0]; if (Container::IsCurrentUseNewPipeline()) { bool isVisible = false; std::u16string errorText; RefPtr resourceObject; UnregisterResource("errorString"); if (ParseJsString(jsValue, errorText, resourceObject)) { isVisible = true; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("errorString", resourceObject, errorText); } TextFieldModel::GetInstance()->SetShowError(errorText, isVisible); } } void JSTextField::SetShowCounter(const JSCallbackInfo& info) { auto jsValue = info[0]; auto secondJSValue = info[1]; if ((!jsValue->IsBoolean() && !secondJSValue->IsObject())) { LOGI("The info is wrong, it is supposed to be a boolean"); TextFieldModel::GetInstance()->SetShowCounter(false); return; } if (secondJSValue->IsObject()) { auto paramObject = JSRef::Cast(secondJSValue); auto param = paramObject->GetProperty("highlightBorder"); auto isBorderShow = param->ToBoolean(); if (!param->IsBoolean() || param->IsUndefined() || param->IsNull()) { TextFieldModel::GetInstance()->SetShowCounterBorder(true); } else { TextFieldModel::GetInstance()->SetShowCounterBorder(isBorderShow); } auto parameter = paramObject->GetProperty("thresholdPercentage"); auto inputNumber = parameter->ToNumber(); TextFieldModel::GetInstance()->SetCounterType(inputNumber); if (parameter->IsNull() || parameter->IsUndefined()) { TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean()); TextFieldModel::GetInstance()->SetCounterType(DEFAULT_MODE); return; } if (static_cast(inputNumber) < MINI_VAILD_VALUE || static_cast(inputNumber) > MAX_VAILD_VALUE) { LOGI("The info is wrong, it is supposed to be a right number"); TextFieldModel::GetInstance()->SetCounterType(ILLEGAL_VALUE); TextFieldModel::GetInstance()->SetShowCounter(false); return; } TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean()); return; } TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean()); TextFieldModel::GetInstance()->SetCounterType(DEFAULT_MODE); TextFieldModel::GetInstance()->SetShowCounterBorder(true); } void JSTextField::SetBarState(const JSCallbackInfo& info) { if (info.Length() < 1) { TextFieldModel::GetInstance()->SetBarState(DisplayMode::AUTO); return; } auto jsValue = info[0]; if (!jsValue->IsNumber()) { TextFieldModel::GetInstance()->SetBarState(DisplayMode::AUTO); return; } DisplayMode displayMode = static_cast(jsValue->ToNumber()); TextFieldModel::GetInstance()->SetBarState(displayMode); } void JSTextField::SetMaxLines(const JSCallbackInfo& info) { if (info.Length() < 1) { TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES); return; } auto jsValue = info[0]; if (!jsValue->IsNumber() || jsValue->ToNumber() <= 0) { TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES); return; } TextFieldModel::GetInstance()->SetMaxViewLines(jsValue->ToNumber()); } void JSTextField::SetEnableKeyboardOnFocus(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined() || !jsValue->IsBoolean()) { TextFieldModel::GetInstance()->RequestKeyboardOnFocus(true); return; } TextFieldModel::GetInstance()->RequestKeyboardOnFocus(jsValue->ToBoolean()); } void JSTextField::SetSelectionMenuHidden(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined() || !jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetSelectionMenuHidden(false); return; } TextFieldModel::GetInstance()->SetSelectionMenuHidden(jsValue->ToBoolean()); } bool JSTextField::ParseJsCustomKeyboardBuilder( const JSCallbackInfo& info, int32_t index, std::function& buildFunc) { if (info.Length() <= static_cast(index) || !info[index]->IsObject()) { return false; } JSRef obj = JSRef::Cast(info[index]); auto builder = obj->GetProperty("builder"); if (!builder->IsFunction()) { return false; } auto builderFunc = AceType::MakeRefPtr(JSRef::Cast(builder)); CHECK_NULL_RETURN(builderFunc, false); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc), node = targetNode]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("CustomKeyboard"); PipelineContext::SetCallBackNode(node); func->Execute(); }; return true; } void JSTextField::SetCustomKeyboard(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; if (jsValue->IsUndefined() || jsValue->IsNull() || !jsValue->IsObject()) { TextFieldModel::GetInstance()->SetCustomKeyboard(nullptr); 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 (ParseJsCustomKeyboardBuilder(info, 0, buildFunc)) { TextFieldModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance); } } void JSTextField::SetPasswordRules(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsString()) { return; } auto passwordRules = jsValue->ToString(); TextFieldModel::GetInstance()->SetPasswordRules(passwordRules); } void JSTextField::SetEnableAutoFill(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetEnableAutoFill(true); return; } TextFieldModel::GetInstance()->SetEnableAutoFill(jsValue->ToBoolean()); } void JSTextField::SetEnableAutoFillAnimation(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetEnableAutoFillAnimation(true); return; } TextFieldModel::GetInstance()->SetEnableAutoFillAnimation(jsValue->ToBoolean()); } static CleanNodeStyle ConvertStrToCleanNodeStyle(const std::string& value) { if (value == "CONSTANT") { return CleanNodeStyle::CONSTANT; } else if (value == "INVISIBLE") { return CleanNodeStyle::INVISIBLE; } else { return CleanNodeStyle::INPUT; } } void JSTextField::SetCancelButton(const JSCallbackInfo& info) { UnregisterResource("cancelButtonIconColorDefault"); if (info.Length() < 1 || !info[0]->IsObject()) { return; } auto param = JSRef::Cast(info[0]); auto theme = GetTheme(); CHECK_NULL_VOID(theme); // set style std::string styleStr; CleanNodeStyle cleanNodeStyle; auto styleProp = param->GetProperty("style"); if (!styleProp->IsNull() && ParseJsString(styleProp, styleStr)) { cleanNodeStyle = ConvertStrToCleanNodeStyle(styleStr); } else { cleanNodeStyle = CleanNodeStyle::INPUT; } TextFieldModel::GetInstance()->SetCleanNodeStyle(cleanNodeStyle); TextFieldModel::GetInstance()->SetIsShowCancelButton(true); // set default icon auto iconJsVal = param->GetProperty("icon"); if (iconJsVal->IsUndefined() || iconJsVal->IsNull() || !iconJsVal->IsObject()) { SetCancelDefaultIcon(); return; } auto iconParam = JSRef::Cast(iconJsVal); bool isSymbolIcon = iconParam->HasProperty("fontColor"); // only SymbolGlyph has fontColor property if (isSymbolIcon) { SetCancelSymbolIcon(info); return; } // set icon size CalcDimension iconSize; auto iconSizeProp = iconParam->GetProperty("size"); RefPtr resourceObject; UnregisterResource("cancelButtonIconSize"); if (!iconSizeProp->IsUndefined() && !iconSizeProp->IsNull() && ParseJsDimensionVpNG(iconSizeProp, iconSize, resourceObject)) { if (LessNotEqual(iconSize.Value(), 0.0) || iconSize.Unit() == DimensionUnit::PERCENT) { iconSize = theme->GetCancelIconSize(); } } else { iconSize = theme->GetCancelIconSize(); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("cancelButtonIconSize", resourceObject, iconSize); } TextFieldModel::GetInstance()->SetCancelIconSize(iconSize); SetCancelIconColorAndIconSrc(iconParam); } void JSTextField::SetCancelDefaultIcon() { auto theme = GetTheme(); CHECK_NULL_VOID(theme); if (Container::CurrentColorMode() == ColorMode::DARK) { TextFieldModel::GetInstance()->SetCancelIconColor(theme->GetCancelButtonIconColor()); } else { TextFieldModel::GetInstance()->SetCancelIconColor(Color()); } TextFieldModel::GetInstance()->SetCancelIconSize(theme->GetCancelIconSize()); TextFieldModel::GetInstance()->SetCanacelIconSrc(std::string(), std::string(), std::string()); TextFieldModel::GetInstance()->SetCancelSymbolIcon(nullptr); TextFieldModel::GetInstance()->SetCancelButtonSymbol(true); } void JSTextField::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); TextFieldModel::GetInstance()->SetCancelSymbolIcon(iconSymbol); TextFieldModel::GetInstance()->SetCancelButtonSymbol(true); } } void JSTextField::SetCancelIconColorAndIconSrc(const JSRef& iconParam) { auto theme = GetTheme(); CHECK_NULL_VOID(theme); // set icon src std::string iconSrc; std::string bundleName; std::string moduleName; auto iconSrcProp = iconParam->GetProperty("src"); RefPtr resourceObject; if (iconSrcProp->IsUndefined() || iconSrcProp->IsNull() || !ParseJsMedia(iconSrcProp, iconSrc, resourceObject)) { UnregisterResource("cancelButtonIconSrc"); iconSrc = ""; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("cancelButtonIconSrc", resourceObject, iconSrc); } GetJsMediaBundleInfo(iconSrcProp, bundleName, moduleName); TextFieldModel::GetInstance()->SetCanacelIconSrc(iconSrc, bundleName, moduleName); TextFieldModel::GetInstance()->SetCancelButtonSymbol(false); // set icon color Color iconColor; RefPtr colorObject; UnregisterResource("cancelButtonIconColor"); auto iconColorProp = iconParam->GetProperty("color"); if (!iconColorProp->IsUndefined() && !iconColorProp->IsNull() && ParseJsColor(iconColorProp, iconColor, colorObject)) { if (SystemProperties::ConfigChangePerform() && colorObject) { RegisterResource("cancelButtonIconColor", colorObject, iconColor); } TextFieldModel::GetInstance()->SetCancelIconColor(iconColor); return; } auto info = ImageSourceInfo(iconSrc, bundleName, moduleName); if (info.IsSvg() && iconSrc != "") { // svg need not default color, otherwise multi color svg will render fault return; } if (SystemProperties::ConfigChangePerform()) { RefPtr resObj = AceType::MakeRefPtr("", "", -1); RegisterResource("cancelButtonIconColorDefault", resObj, iconColor); } if (Container::CurrentColorMode() == ColorMode::DARK) { TextFieldModel::GetInstance()->SetCancelIconColor(theme->GetCancelButtonIconColor()); } else { TextFieldModel::GetInstance()->SetCancelIconColor(iconColor); } } void JSTextField::SetSelectAllValue(const JSCallbackInfo& info) { auto infoValue = info[0]; if (!infoValue->IsBoolean() || infoValue->IsUndefined() || infoValue->IsNull()) { TextFieldModel::GetInstance()->SetSelectAllValue(false); return; } bool isSetSelectAllValue = infoValue->ToBoolean(); TextFieldModel::GetInstance()->SetSelectAllValue(isSetSelectAllValue); } void JSTextField::SetFontFeature(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; std::string fontFeatureSettings = ""; if (jsValue->IsString()) { fontFeatureSettings = jsValue->ToString(); } TextFieldModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings)); } void JSTextField::SetKeyboardAppearance(const JSCallbackInfo& info) { if (info.Length() != 1 || !info[0]->IsNumber()) { TextFieldModel::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)) { TextFieldModel::GetInstance()->SetKeyboardAppearance( static_cast(KeyboardAppearance::NONE_IMMERSIVE)); return; } TextFieldModel::GetInstance()-> SetKeyboardAppearance(static_cast(keyboardAppearance)); } void JSTextField::SetDecoration(const JSCallbackInfo& info) { auto tmpInfo = info[0]; UnregisterResource("decorationColor"); if (!tmpInfo->IsObject()) { TextFieldModel::GetInstance()->SetTextDecoration(TextDecoration::NONE); TextFieldModel::GetInstance()->SetTextDecorationColor(Color::BLACK); TextFieldModel::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 (resourceObject && SystemProperties::ConfigChangePerform()) { RegisterResource("decorationColor", resourceObject, result); } std::optional textDecorationStyle; if (styleValue->IsNumber()) { textDecorationStyle = static_cast(styleValue->ToNumber()); } else { textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE; } TextFieldModel::GetInstance()->SetTextDecoration(textDecoration); TextFieldModel::GetInstance()->SetTextDecorationColor(result); if (textDecorationStyle) { TextFieldModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value()); } } void JSTextField::SetMinFontSize(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension minFontSize; RefPtr resourceObject; UnregisterResource("minFontSize"); if (!ParseJsDimensionFpNG(info[0], minFontSize, resourceObject, false)) { TextFieldModel::GetInstance()->SetAdaptMinFontSize(CalcDimension()); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("minFontSize", resourceObject, minFontSize); } if (minFontSize.IsNegative()) { minFontSize = CalcDimension(); } TextFieldModel::GetInstance()->SetAdaptMinFontSize(minFontSize); } void JSTextField::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(); TextFieldModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("maxFontSize", resourceObject, maxFontSize); } if (maxFontSize.IsNegative()) { maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize(); } TextFieldModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize); } void JSTextField::SetHeightAdaptivePolicy(int32_t value) { if (value < 0 || value >= static_cast(HEIGHT_ADAPTIVE_POLICY.size())) { value = 0; } TextFieldModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]); } void JSTextField::SetLetterSpacing(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; if (!ParseJsDimensionFpNG(info[0], value, resourceObject, false)) { value.Reset(); TextFieldModel::GetInstance()->SetLetterSpacing(value); UnregisterResource("letterSpacing"); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("letterSpacing", resourceObject, value); } TextFieldModel::GetInstance()->SetLetterSpacing(value); } void JSTextField::SetLineHeight(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; UnregisterResource("lineHeight"); if (!ParseJsDimensionFpNG(info[0], value, resourceObject)) { value.Reset(); TextFieldModel::GetInstance()->SetLineHeight(value); return; } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("lineHeight", resourceObject, value); } if (value.IsNegative()) { value.Reset(); } TextFieldModel::GetInstance()->SetLineHeight(value); } void JSTextField::SetHalfLeading(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } auto jsValue = info[0]; bool halfLeading = jsValue->IsBoolean() ? jsValue->ToBoolean() : false; TextFieldModel::GetInstance()->SetHalfLeading(halfLeading); } void JSTextField::SetLineSpacing(const JSCallbackInfo& info) { CalcDimension value; if (!ParseLengthMetricsToPositiveDimension(info[0], value)) { value.Reset(); } if (value.IsNegative()) { value.Reset(); } TextFieldModel::GetInstance()->SetLineSpacing(value); if (info.Length() < 2) { // 2 : two args TextFieldModel::GetInstance()->SetIsOnlyBetweenLines(false); return; } auto jsonValue = info[1]; if (!jsonValue->IsObject()) { TextFieldModel::GetInstance()->SetIsOnlyBetweenLines(false); return; } auto paramObject = JSRef::Cast(jsonValue); auto param = paramObject->GetProperty("onlyBetweenLines"); if (!param->IsBoolean() || param->IsUndefined() || param->IsNull()) { TextFieldModel::GetInstance()->SetIsOnlyBetweenLines(false); } else { auto isOnlyBetweenLines = param->ToBoolean(); TextFieldModel::GetInstance()->SetIsOnlyBetweenLines(isOnlyBetweenLines); } } void JSTextField::SetTextOverflow(const JSCallbackInfo& info) { do { if (info.Length() < 1) { break; } auto tmpInfo = info[0]; int32_t overflow = 0; if (tmpInfo->IsUndefined() || tmpInfo->IsNull() || !tmpInfo->IsNumber()) { overflow = DEFAULT_OVERFLOW; } else if (tmpInfo->IsNumber()) { overflow = tmpInfo->ToNumber(); if (overflow < 0 || overflow >= static_cast(TEXT_OVERFLOWS.size())) { overflow = DEFAULT_OVERFLOW; } } TextFieldModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]); } while (false); info.SetReturnValue(info.This()); } void JSTextField::SetTextIndent(const JSCallbackInfo& info) { CalcDimension value; RefPtr resourceObject; if (!ParseJsDimensionVpNG(info[0], value, resourceObject, true)) { value.Reset(); UnregisterResource("textIndent"); } if (SystemProperties::ConfigChangePerform() && resourceObject) { RegisterResource("textIndent", resourceObject, value); } TextFieldModel::GetInstance()->SetTextIndent(value); } JSRef JSTextField::CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue) { JSRef aboutToIMEInputObj = JSRef::New(); aboutToIMEInputObj->SetProperty("insertOffset", insertValue.insertOffset); aboutToIMEInputObj->SetProperty("insertValue", insertValue.insertValue); return JSRef::Cast(aboutToIMEInputObj); } void JSTextField::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; }; TextFieldModel::GetInstance()->SetOnWillInsertValueEvent(std::move(callback)); } JSRef JSTextField::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 JSTextField::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); }; TextFieldModel::GetInstance()->SetOnDidInsertValueEvent(std::move(callback)); } void JSTextField::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; }; TextFieldModel::GetInstance()->SetOnWillDeleteEvent(std::move(callback)); } void JSTextField::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); }; TextFieldModel::GetInstance()->SetOnDidDeleteEvent(std::move(callback)); } void JSTextField::EditMenuOptions(const JSCallbackInfo& info) { NG::OnCreateMenuCallback onCreateMenuCallback; NG::OnMenuItemClickCallback onMenuItemClick; NG::OnPrepareMenuCallback onPrepareMenuCallback; JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick, onPrepareMenuCallback); TextFieldModel::GetInstance()->SetSelectionMenuOptions( std::move(onCreateMenuCallback), std::move(onMenuItemClick), std::move(onPrepareMenuCallback)); } void JSTextField::SetEnablePreviewText(const JSCallbackInfo& info) { auto jsValue = info[0]; if (!jsValue->IsBoolean()) { TextFieldModel::GetInstance()->SetEnablePreviewText(true); return; } TextFieldModel::GetInstance()->SetEnablePreviewText(jsValue->ToBoolean()); } void JSTextField::SetEnableHapticFeedback(const JSCallbackInfo& info) { bool state = true; if (info.Length() > 0 && info[0]->IsBoolean()) { state = info[0]->ToBoolean(); } TextFieldModel::GetInstance()->SetEnableHapticFeedback(state); } void JSTextField::SetEllipsisMode(const JSCallbackInfo& info) { JSRef args = info[0]; if (!args->IsNumber()) { TextFieldModel::GetInstance()->SetEllipsisMode(EllipsisMode::TAIL); return; } uint32_t index = args->ToNumber(); if (index < ELLIPSIS_MODALS.size()) { TextFieldModel::GetInstance()->SetEllipsisMode(ELLIPSIS_MODALS[index]); } } void JSTextField::SetStopBackPress(const JSCallbackInfo& info) { bool isStopBackPress = true; if (info.Length() > 0 && info[0]->IsBoolean()) { isStopBackPress = info[0]->ToBoolean(); } TextFieldModel::GetInstance()->SetStopBackPress(isStopBackPress); } JSRef JSTextField::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 JSTextField::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; }; TextFieldModel::GetInstance()->SetOnWillChangeEvent(std::move(onWillChange)); } void JSTextField::SetEnableAutoSpacing(const JSCallbackInfo& info) { bool enabled = false; if (info.Length() > 0 && info[0]->IsBoolean()) { enabled = info[0]->ToBoolean(); } TextFieldModel::GetInstance()->SetEnableAutoSpacing(enabled); } void JSTextField::SetStrokeWidth(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension value; if (!ParseLengthMetricsToDimension(info[0], value)) { value.Reset(); } TextFieldModel::GetInstance()->SetStrokeWidth(value); } void JSTextField::SetStrokeColor(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } Color strokeColor; if (!ParseJsColor(info[0], strokeColor)) { TextFieldModel::GetInstance()->ResetStrokeColor(); return; } TextFieldModel::GetInstance()->SetStrokeColor(strokeColor); } NG::KeyboardAppearanceConfig JSTextField::ParseKeyboardAppearanceConfig(const JSRef& obj) { NG::KeyboardAppearanceConfig config; auto gradientModeJsVal = obj->GetProperty("gradientMode"); if (gradientModeJsVal->IsNull() || gradientModeJsVal->IsUndefined() || !gradientModeJsVal->IsNumber()) { config.gradientMode = NG::KeyboardGradientMode::NONE; } else { int32_t value = gradientModeJsVal->ToNumber(); if (value <= static_cast(NG::KeyboardGradientMode::BEGIN) || value > static_cast(NG::KeyboardGradientMode::END)) { config.gradientMode = NG::KeyboardGradientMode::NONE; } else { config.gradientMode = static_cast(value); } } auto fluidLightModeJsVal = obj->GetProperty("fluidLightMode"); if (fluidLightModeJsVal->IsNull() || fluidLightModeJsVal->IsUndefined() || !fluidLightModeJsVal->IsNumber()) { config.fluidLightMode = NG::KeyboardFluidLightMode::NONE; } else { int32_t value = fluidLightModeJsVal->ToNumber(); if (value <= static_cast(NG::KeyboardFluidLightMode::BEGIN) || value > static_cast(NG::KeyboardFluidLightMode::END)) { config.fluidLightMode = NG::KeyboardFluidLightMode::NONE; } else { config.fluidLightMode = static_cast(value); } } return config; } void JSTextField::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); }; TextFieldModel::GetInstance()->SetOnWillAttachIME(std::move(onWillAttachIME)); } void JSTextField::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 = ParseKeyboardAppearanceConfig(JSRef::Cast(info[1])); NG::TextFieldModelNG::SetKeyboardAppearanceConfig(frameNode, config); } void JSTextField::SetLayoutPolicy(const JSRef& jsValue, bool isWidth) { if (!jsValue->IsObject()) { ViewAbstractModel::GetInstance()->UpdateLayoutPolicyProperty(LayoutCalPolicy::NO_MATCH, isWidth); return; } JSRef object = JSRef::Cast(jsValue); JSRef layoutPolicy = object->GetProperty("id_"); if (layoutPolicy->IsString()) { auto policy = ParseLayoutPolicy(layoutPolicy->ToString()); ViewAbstractModel::GetInstance()->UpdateLayoutPolicyProperty(policy, isWidth); } } void JSTextField::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); } } // namespace OHOS::Ace::Framework