1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/jsview/js_textfield.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <string>
21 #include <vector>
22 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
23 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
24 #endif
25
26 #include "base/geometry/dimension.h"
27 #include "base/log/ace_scoring_log.h"
28 #include "base/utils/utils.h"
29 #include "bridge/common/utils/utils.h"
30 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
31 #include "bridge/declarative_frontend/engine/functions/js_clipboard_function.h"
32 #include "bridge/declarative_frontend/engine/functions/js_function.h"
33 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
34 #include "bridge/declarative_frontend/jsview/js_container_base.h"
35 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
36 #include "bridge/declarative_frontend/jsview/js_text_editable_controller.h"
37 #include "bridge/declarative_frontend/jsview/js_textarea.h"
38 #include "bridge/declarative_frontend/jsview/js_textinput.h"
39 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
40 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
41 #include "bridge/declarative_frontend/jsview/models/text_field_model_impl.h"
42 #include "core/common/container.h"
43 #include "core/common/ime/text_input_action.h"
44 #include "core/common/ime/text_input_type.h"
45 #include "core/components/common/layout/constants.h"
46 #include "core/components/common/properties/text_style_parser.h"
47 #include "core/components/text_field/textfield_theme.h"
48 #include "core/components_ng/base/view_abstract.h"
49 #include "core/components_ng/pattern/text_field/text_content_type.h"
50 #include "core/components_ng/pattern/text_field/text_field_model_ng.h"
51 #include "core/image/image_source_info.h"
52
53 namespace OHOS::Ace {
54
55 std::unique_ptr<TextFieldModel> TextFieldModel::instance_ = nullptr;
56 std::mutex TextFieldModel::mutex_;
57
GetInstance()58 TextFieldModel* TextFieldModel::GetInstance()
59 {
60 #ifdef NG_BUILD
61 static NG::TextFieldModelNG instance;
62 return &instance;
63 #else
64 if (Container::IsCurrentUseNewPipeline()) {
65 static NG::TextFieldModelNG instance;
66 return &instance;
67 } else {
68 static Framework::TextFieldModelImpl instance;
69 return &instance;
70 }
71 #endif
72 }
73
74 } // namespace OHOS::Ace
75
76 namespace OHOS::Ace::Framework {
77
78 namespace {
79
80 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END, TextAlign::JUSTIFY };
81 const std::vector<LineBreakStrategy> LINE_BREAK_STRATEGY_TYPES = { LineBreakStrategy::GREEDY,
82 LineBreakStrategy::HIGH_QUALITY, LineBreakStrategy::BALANCED };
83 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
84 const std::vector<std::string> INPUT_FONT_FAMILY_VALUE = { "sans-serif" };
85 const std::vector<WordBreak> WORD_BREAK_TYPES = { WordBreak::NORMAL, WordBreak::BREAK_ALL, WordBreak::BREAK_WORD };
86 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
87 TextOverflow::MARQUEE, TextOverflow::DEFAULT };
88 constexpr uint32_t MAX_LINES = 3;
89 constexpr uint32_t MINI_VAILD_VALUE = 1;
90 constexpr uint32_t MAX_VAILD_VALUE = 100;
91 constexpr uint32_t ILLEGAL_VALUE = 0;
92 constexpr uint32_t DEFAULT_MODE = -1;
93 constexpr uint32_t DEFAULT_OVERFLOW = 4;
94 const char* TOP_START_PROPERTY = "topStart";
95 const char* TOP_END_PROPERTY = "topEnd";
96 const char* BOTTOM_START_PROPERTY = "bottomStart";
97 const char* BOTTOM_END_PROPERTY = "bottomEnd";
98 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICY = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
99 TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
100 constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID;
101
ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)102 bool ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)
103 {
104 auto value = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::VALUE));
105 if (!value->IsNumber()) {
106 return false;
107 }
108 auto unit = DimensionUnit::VP;
109 auto jsUnit = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::UNIT));
110 if (jsUnit->IsNumber()) {
111 unit = static_cast<DimensionUnit>(jsUnit->ToNumber<int32_t>());
112 }
113 CalcDimension dimension(value->ToNumber<double>(), unit);
114 result = dimension;
115 return true;
116 }
117 } // namespace
118
ParseTextFieldTextObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)119 void ParseTextFieldTextObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
120 {
121 CHECK_NULL_VOID(changeEventVal->IsFunction());
122
123 JsEventCallback<void(const std::string&)> onChangeEvent(
124 info.GetExecutionContext(), JSRef<JSFunc>::Cast(changeEventVal));
125 TextFieldModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
126 }
127
CreateTextInput(const JSCallbackInfo& info)128 void JSTextField::CreateTextInput(const JSCallbackInfo& info)
129 {
130 std::optional<std::string> placeholderSrc;
131 std::optional<std::string> value;
132 JSTextEditableController* jsController = nullptr;
133 JSRef<JSVal> changeEventVal = JSRef<JSVal>::Make();
134 auto jsValue = info[0];
135 if (jsValue->IsObject()) {
136 auto paramObject = JSRef<JSObject>::Cast(jsValue);
137 std::string placeholder;
138 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
139 placeholderSrc = placeholder;
140 }
141 std::string text;
142 JSRef<JSVal> textValue = paramObject->GetProperty("text");
143 if (textValue->IsObject()) {
144 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(textValue);
145 changeEventVal = valueObj->GetProperty("changeEvent");
146 if (changeEventVal->IsFunction()) {
147 textValue = valueObj->GetProperty("value");
148 }
149 value = "";
150 if (ParseJsString(textValue, text)) {
151 value = text;
152 }
153 } else if (paramObject->HasProperty("text")) {
154 if (ParseJsString(textValue, text)) {
155 value = text;
156 }
157 if (textValue->IsUndefined()) {
158 value = "";
159 }
160 }
161 auto controllerObj = paramObject->GetProperty("controller");
162 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
163 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextEditableController>();
164 }
165 }
166
167 auto controller = TextFieldModel::GetInstance()->CreateTextInput(placeholderSrc, value);
168 if (jsController) {
169 jsController->SetController(controller);
170 }
171 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
172 ParseTextFieldTextObject(info, changeEventVal);
173 }
174
175 TextFieldModel::GetInstance()->SetFocusableAndFocusNode();
176 }
177
CreateTextArea(const JSCallbackInfo& info)178 void JSTextField::CreateTextArea(const JSCallbackInfo& info)
179 {
180 std::optional<std::string> placeholderSrc;
181 std::optional<std::string> value;
182 JSTextEditableController* jsController = nullptr;
183 JSRef<JSVal> changeEventVal = JSRef<JSVal>::Make();
184 auto jsValue = info[0];
185 if (jsValue->IsObject()) {
186 auto paramObject = JSRef<JSObject>::Cast(jsValue);
187 std::string placeholder;
188 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
189 placeholderSrc = placeholder;
190 }
191 std::string text;
192 JSRef<JSVal> textValue = paramObject->GetProperty("text");
193 if (textValue->IsObject()) {
194 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(textValue);
195 changeEventVal = valueObj->GetProperty("changeEvent");
196 if (changeEventVal->IsFunction()) {
197 textValue = valueObj->GetProperty("value");
198 }
199 if (ParseJsString(textValue, text)) {
200 value = text;
201 }
202 } else if (paramObject->HasProperty("text")) {
203 if (ParseJsString(textValue, text)) {
204 value = text;
205 }
206 if (textValue->IsUndefined()) {
207 value = "";
208 }
209 }
210 auto controllerObj = paramObject->GetProperty("controller");
211 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
212 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextEditableController>();
213 }
214 }
215 auto controller = TextFieldModel::GetInstance()->CreateTextArea(placeholderSrc, value);
216 if (jsController) {
217 jsController->SetController(controller);
218 }
219 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
220 ParseTextFieldTextObject(info, changeEventVal);
221 }
222
223 TextFieldModel::GetInstance()->SetFocusableAndFocusNode();
224 }
225
SetType(const JSCallbackInfo& info)226 void JSTextField::SetType(const JSCallbackInfo& info)
227 {
228 if (info.Length() < 1) {
229 return;
230 }
231 auto jsValue = info[0];
232 if (jsValue->IsUndefined()) {
233 TextFieldModel::GetInstance()->SetType(TextInputType::UNSPECIFIED);
234 return;
235 }
236 if (!jsValue->IsNumber()) {
237 return;
238 }
239 TextInputType textInputType = CastToTextInputType(jsValue->ToNumber<int32_t>());
240 TextFieldModel::GetInstance()->SetType(textInputType);
241 }
242
SetContentType(const JSCallbackInfo& info)243 void JSTextField::SetContentType(const JSCallbackInfo& info)
244 {
245 if (info.Length() < 1) {
246 return;
247 }
248 auto jsValue = info[0];
249 if (jsValue->IsUndefined()) {
250 TextFieldModel::GetInstance()->SetContentType(NG::TextContentType::UNSPECIFIED);
251 return;
252 }
253 if (!jsValue->IsNumber()) {
254 return;
255 }
256 NG::TextContentType textContentType = static_cast<NG::TextContentType>(jsValue->ToNumber<int32_t>());
257 TextFieldModel::GetInstance()->SetContentType(textContentType);
258 }
259
SetPlaceholderColor(const JSCallbackInfo& info)260 void JSTextField::SetPlaceholderColor(const JSCallbackInfo& info)
261 {
262 if (info.Length() < 1) {
263 return;
264 }
265
266 auto theme = GetTheme<TextFieldTheme>();
267 CHECK_NULL_VOID(theme);
268 Color color = theme->GetPlaceholderColor();
269 CheckColor(info[0], color, V2::TEXTINPUT_ETS_TAG, "PlaceholderColor");
270 TextFieldModel::GetInstance()->SetPlaceholderColor(color);
271 }
272
SetPlaceholderFont(const JSCallbackInfo& info)273 void JSTextField::SetPlaceholderFont(const JSCallbackInfo& info)
274 {
275 if (info.Length() < 1 || !info[0]->IsObject()) {
276 return;
277 }
278 Font font;
279 auto paramObject = JSRef<JSObject>::Cast(info[0]);
280 auto fontSize = paramObject->GetProperty("size");
281 if (fontSize->IsNull() || fontSize->IsUndefined()) {
282 font.fontSize = Dimension(-1);
283 } else {
284 CalcDimension size;
285 auto theme = GetTheme<TextFieldTheme>();
286 CHECK_NULL_VOID(theme);
287 if (fontSize->IsString()) {
288 auto result = StringUtils::StringToDimensionWithThemeValue(
289 fontSize->ToString(), true, Dimension(theme->GetFontSize()));
290 if (result.Unit() == DimensionUnit::PERCENT) {
291 result = theme->GetFontSize();
292 }
293 font.fontSize = result;
294 } else if (ParseJsDimensionFp(fontSize, size) && size.Unit() != DimensionUnit::PERCENT) {
295 font.fontSize = size;
296 } else {
297 font.fontSize = Dimension(theme->GetFontSize());
298 }
299 }
300
301 std::string weight;
302 auto fontWeight = paramObject->GetProperty("weight");
303 if (!fontWeight->IsNull()) {
304 if (fontWeight->IsNumber()) {
305 weight = std::to_string(fontWeight->ToNumber<int32_t>());
306 } else {
307 ParseJsString(fontWeight, weight);
308 }
309 font.fontWeight = ConvertStrToFontWeight(weight);
310 }
311
312 auto fontFamily = paramObject->GetProperty("family");
313 if (!fontFamily->IsNull()) {
314 std::vector<std::string> fontFamilies;
315 if (ParseJsFontFamilies(fontFamily, fontFamilies)) {
316 font.fontFamilies = fontFamilies;
317 }
318 }
319
320 auto style = paramObject->GetProperty("style");
321 if (!style->IsNull()) {
322 font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
323 }
324 TextFieldModel::GetInstance()->SetPlaceholderFont(font);
325 }
326
SetEnterKeyType(const JSCallbackInfo& info)327 void JSTextField::SetEnterKeyType(const JSCallbackInfo& info)
328 {
329 if (info.Length() < 1) {
330 return;
331 }
332 auto jsValue = info[0];
333 if (jsValue->IsUndefined()) {
334 TextFieldModel::GetInstance()->SetEnterKeyType(TextInputAction::UNSPECIFIED);
335 return;
336 }
337 if (!jsValue->IsNumber()) {
338 return;
339 }
340 TextInputAction textInputAction = CastToTextInputAction(jsValue->ToNumber<int32_t>());
341 TextFieldModel::GetInstance()->SetEnterKeyType(textInputAction);
342 }
343
SetTextAlign(int32_t value)344 void JSTextField::SetTextAlign(int32_t value)
345 {
346 if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
347 TextFieldModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
348 }
349 }
350
SetLineBreakStrategy(const JSCallbackInfo& info)351 void JSTextField::SetLineBreakStrategy(const JSCallbackInfo& info)
352 {
353 if (info.Length() < 1) {
354 TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
355 return;
356 }
357 if (!info[0]->IsNumber()) {
358 TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
359 return;
360 }
361 auto index = info[0]->ToNumber<int32_t>();
362 if (index < 0 || index >= static_cast<int32_t>(LINE_BREAK_STRATEGY_TYPES.size())) {
363 TextFieldModel::GetInstance()->SetLineBreakStrategy(LineBreakStrategy::GREEDY);
364 return;
365 }
366 TextFieldModel::GetInstance()->SetLineBreakStrategy(LINE_BREAK_STRATEGY_TYPES[index]);
367 }
368
SetInputStyle(const JSCallbackInfo& info)369 void JSTextField::SetInputStyle(const JSCallbackInfo& info)
370 {
371 if (info.Length() < 1) {
372 return;
373 }
374 auto styleString = info[0]->ToString();
375 if (styleString == "Inline") {
376 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::INLINE);
377 } else {
378 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::DEFAULT);
379 }
380 }
381
SetCaretColor(const JSCallbackInfo& info)382 void JSTextField::SetCaretColor(const JSCallbackInfo& info)
383 {
384 if (info.Length() < 1) {
385 return;
386 }
387
388 Color color;
389 if (!ParseJsColor(info[0], color)) {
390 return;
391 }
392
393 TextFieldModel::GetInstance()->SetCaretColor(color);
394 }
395
SetCaretStyle(const JSCallbackInfo& info)396 void JSTextField::SetCaretStyle(const JSCallbackInfo& info)
397 {
398 if (info.Length() < 1) {
399 return;
400 }
401 auto jsValue = info[0];
402 if (jsValue->IsObject()) {
403 CaretStyle caretStyle;
404 auto paramObject = JSRef<JSObject>::Cast(jsValue);
405 auto caretWidth = paramObject->GetProperty("width");
406
407 auto pipeline = PipelineBase::GetCurrentContext();
408 CHECK_NULL_VOID(pipeline);
409 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
410 CHECK_NULL_VOID(theme);
411 if (caretWidth->IsNull() || caretWidth->IsUndefined()) {
412 caretStyle.caretWidth = theme->GetCursorWidth();
413 } else {
414 CalcDimension width;
415 if (!ParseJsDimensionVpNG(caretWidth, width, false)) {
416 width = theme->GetCursorWidth();
417 }
418 if (LessNotEqual(width.Value(), 0.0)) {
419 width = theme->GetCursorWidth();
420 }
421 caretStyle.caretWidth = width;
422 }
423 TextFieldModel::GetInstance()->SetCaretStyle(caretStyle);
424
425 // set caret color
426 Color caretColor;
427 if (!paramObject->HasProperty("color")) {
428 return;
429 } else {
430 auto caretColorProp = paramObject->GetProperty("color");
431 if (caretColorProp->IsUndefined() || caretColorProp->IsNull()
432 || !ParseJsColor(caretColorProp, caretColor)) {
433 caretColor = theme->GetCursorColor();
434 }
435 TextFieldModel::GetInstance()->SetCaretColor(caretColor);
436 }
437 }
438 }
439
SetCaretPosition(const JSCallbackInfo& info)440 void JSTextField::SetCaretPosition(const JSCallbackInfo& info)
441 {
442 if (info.Length() < 1) {
443 return;
444 }
445 int32_t caretPosition = 0;
446 auto tempInfo = info[0];
447 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
448 if (!ParseJsInt32(tempInfo, caretPosition) || caretPosition < 0) {
449 caretPosition = 0;
450 }
451 } else {
452 if (!ParseJsInt32(tempInfo, caretPosition)) {
453 return;
454 }
455 if (caretPosition < 0) {
456 return;
457 }
458 }
459 TextFieldModel::GetInstance()->SetCaretPosition(caretPosition);
460 }
461
SetSelectedBackgroundColor(const JSCallbackInfo& info)462 void JSTextField::SetSelectedBackgroundColor(const JSCallbackInfo& info)
463 {
464 if (info.Length() < 1) {
465 return;
466 }
467
468 Color selectedColor;
469 if (!ParseJsColor(info[0], selectedColor)) {
470 auto pipeline = PipelineBase::GetCurrentContext();
471 CHECK_NULL_VOID(pipeline);
472 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
473 CHECK_NULL_VOID(theme);
474 selectedColor = theme->GetSelectedColor();
475 }
476 // Alpha = 255 means opaque
477 if (selectedColor.GetAlpha() == 255) {
478 // Default setting of 20% opacity
479 selectedColor = selectedColor.ChangeOpacity(0.2);
480 }
481 TextFieldModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
482 }
483
SetMaxLength(const JSCallbackInfo& info)484 void JSTextField::SetMaxLength(const JSCallbackInfo& info)
485 {
486 if (info.Length() < 1) {
487 return;
488 }
489 auto jsValue = info[0];
490 int32_t maxLength = 0;
491 if (jsValue->IsUndefined()) {
492 TextFieldModel::GetInstance()->ResetMaxLength();
493 return;
494 } else if (!jsValue->IsNumber()) {
495 TextFieldModel::GetInstance()->ResetMaxLength();
496 return;
497 }
498 maxLength = jsValue->ToNumber<int32_t>();
499 if (std::isinf(jsValue->ToNumber<float>())) {
500 maxLength = INT32_MAX; // Infinity
501 }
502 if (GreatOrEqual(maxLength, 0)) {
503 TextFieldModel::GetInstance()->SetMaxLength(maxLength);
504 } else {
505 TextFieldModel::GetInstance()->ResetMaxLength();
506 }
507 }
508
SetFontSize(const JSCallbackInfo& info)509 void JSTextField::SetFontSize(const JSCallbackInfo& info)
510 {
511 if (info.Length() < 1) {
512 return;
513 }
514 CalcDimension fontSize;
515 if (!ParseJsDimensionNG(info[0], fontSize, DimensionUnit::FP, false)) {
516 auto theme = GetTheme<TextFieldTheme>();
517 CHECK_NULL_VOID(theme);
518 fontSize = theme->GetFontSize();
519 }
520 TextFieldModel::GetInstance()->SetFontSize(fontSize);
521 }
522
SetFontWeight(const std::string& value)523 void JSTextField::SetFontWeight(const std::string& value)
524 {
525 TextFieldModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
526 }
527
SetTextColor(const JSCallbackInfo& info)528 void JSTextField::SetTextColor(const JSCallbackInfo& info)
529 {
530 if (info.Length() < 1) {
531 return;
532 }
533 Color textColor;
534 if (!ParseJsColor(info[0], textColor)) {
535 auto theme = GetTheme<TextFieldTheme>();
536 CHECK_NULL_VOID(theme);
537 textColor = theme->GetTextColor();
538 }
539 TextFieldModel::GetInstance()->SetTextColor(textColor);
540 }
541
SetWordBreak(const JSCallbackInfo& info)542 void JSTextField::SetWordBreak(const JSCallbackInfo& info)
543 {
544 if (info.Length() < 1) {
545 return;
546 }
547 auto jsValue = info[0];
548 if (!jsValue->IsNumber()) {
549 TextFieldModel::GetInstance()->SetWordBreak(WordBreak::BREAK_WORD);
550 return;
551 }
552 auto index = jsValue->ToNumber<int32_t>();
553 if (index < 0 || index >= static_cast<int32_t>(WORD_BREAK_TYPES.size())) {
554 TextFieldModel::GetInstance()->SetWordBreak(WordBreak::BREAK_WORD);
555 return;
556 }
557 TextFieldModel::GetInstance()->SetWordBreak(WORD_BREAK_TYPES[index]);
558 }
559
SetForegroundColor(const JSCallbackInfo& info)560 void JSTextField::SetForegroundColor(const JSCallbackInfo& info)
561 {
562 if (info.Length() < 1) {
563 return;
564 }
565 auto jsValue = info[0];
566 ForegroundColorStrategy strategy;
567 if (ParseJsColorStrategy(jsValue, strategy)) {
568 ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
569 TextFieldModel::GetInstance()->SetForegroundColor(Color::FOREGROUND);
570 return;
571 }
572 Color foregroundColor;
573 if (!ParseJsColor(jsValue, foregroundColor)) {
574 return;
575 }
576 ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor);
577 TextFieldModel::GetInstance()->SetForegroundColor(foregroundColor);
578 }
579
SetFontStyle(int32_t value)580 void JSTextField::SetFontStyle(int32_t value)
581 {
582 if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
583 TextFieldModel::GetInstance()->SetFontStyle(FONT_STYLES[value]);
584 }
585 }
586
SetFontFamily(const JSCallbackInfo& info)587 void JSTextField::SetFontFamily(const JSCallbackInfo& info)
588 {
589 if (info.Length() < 1) {
590 return;
591 }
592 std::vector<std::string> fontFamilies;
593 if (!ParseJsFontFamilies(info[0], fontFamilies)) {
594 return;
595 }
596 TextFieldModel::GetInstance()->SetFontFamily(fontFamilies);
597 }
598
SetInputFilter(const JSCallbackInfo& info)599 void JSTextField::SetInputFilter(const JSCallbackInfo& info)
600 {
601 if (info.Length() < 1) {
602 return;
603 }
604 auto jsValue = info[0];
605 std::string inputFilter;
606 if (jsValue->IsUndefined()) {
607 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
608 return;
609 }
610 if (!ParseJsString(jsValue, inputFilter)) {
611 return;
612 }
613 if (!CheckRegexValid(inputFilter)) {
614 inputFilter = "";
615 }
616 if (info.Length() > 1 && info[1]->IsFunction()) {
617 auto jsFunc = AceType::MakeRefPtr<JsClipboardFunction>(JSRef<JSFunc>::Cast(info[1]));
618 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
619 auto resultId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
620 const std::string& info) {
621 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
622 PipelineContext::SetCallBackNode(node);
623 func->Execute(info);
624 };
625 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, resultId);
626 return;
627 }
628 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
629 }
630
SetShowPasswordIcon(const JSCallbackInfo& info)631 void JSTextField::SetShowPasswordIcon(const JSCallbackInfo& info)
632 {
633 auto jsValue = info[0];
634 if (!jsValue->IsBoolean()) {
635 TextFieldModel::GetInstance()->SetShowPasswordIcon(true);
636 return;
637 }
638
639 bool isShowPasswordIcon = jsValue->ToBoolean();
640 TextFieldModel::GetInstance()->SetShowPasswordIcon(isShowPasswordIcon);
641 }
642
ShowPasswordText(const JSCallbackInfo& info)643 void JSTextField::ShowPasswordText(const JSCallbackInfo& info)
644 {
645 auto tmpInfo = info[0];
646 if (!tmpInfo->IsBoolean()) {
647 TextFieldModel::GetInstance()->SetShowPasswordText(false);
648 return;
649 }
650
651 bool showPassword = tmpInfo->ToBoolean();
652 TextFieldModel::GetInstance()->SetShowPasswordText(showPassword);
653 }
654
SetBackgroundColor(const JSCallbackInfo& info)655 void JSTextField::SetBackgroundColor(const JSCallbackInfo& info)
656 {
657 if (info.Length() < 1) {
658 return;
659 }
660 Color backgroundColor;
661 bool tmp = !ParseJsColor(info[0], backgroundColor);
662 TextFieldModel::GetInstance()->SetBackgroundColor(backgroundColor, tmp);
663 }
664
JsHeight(const JSCallbackInfo& info)665 void JSTextField::JsHeight(const JSCallbackInfo& info)
666 {
667 JSViewAbstract::JsHeight(info);
668 if (info.Length() < 1) {
669 return;
670 }
671 CalcDimension value;
672 if (!ParseJsDimensionVp(info[0], value)) {
673 return;
674 }
675 if (LessNotEqual(value.Value(), 0.0)) {
676 ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
677 return;
678 }
679 TextFieldModel::GetInstance()->SetHeight(value);
680 }
681
JsWidth(const JSCallbackInfo& info)682 void JSTextField::JsWidth(const JSCallbackInfo& info)
683 {
684 if (info.Length() < 1) {
685 return;
686 }
687 auto jsValue = info[0];
688 if (jsValue->IsString() && jsValue->ToString().empty()) {
689 return;
690 }
691 if (jsValue->IsString() && jsValue->ToString() == "auto") {
692 ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
693 TextFieldModel::GetInstance()->SetWidthAuto(true);
694 return;
695 }
696
697 TextFieldModel::GetInstance()->SetWidthAuto(false);
698 CalcDimension value;
699 if (!ParseJsDimensionVp(jsValue, value)) {
700 return;
701 }
702 if (LessNotEqual(value.Value(), 0.0)) {
703 return;
704 }
705 ViewAbstractModel::GetInstance()->SetWidth(value);
706 }
707
CheckIsIllegalString(const std::string& value)708 bool CheckIsIllegalString(const std::string& value)
709 {
710 if (value.empty()) {
711 return true;
712 }
713 errno = 0;
714 char* pEnd = nullptr;
715 std::strtod(value.c_str(), &pEnd);
716 return (pEnd == value.c_str() || errno == ERANGE);
717 }
718
JsMargin(const JSCallbackInfo& info)719 void JSTextField::JsMargin(const JSCallbackInfo& info)
720 {
721 JSViewAbstract::JsMargin(info);
722 TextFieldModel::GetInstance()->SetMargin();
723 }
724
JsPadding(const JSCallbackInfo& info)725 void JSTextField::JsPadding(const JSCallbackInfo& info)
726 {
727 auto jsValue = info[0];
728 if (jsValue->IsUndefined() || (jsValue->IsString() && CheckIsIllegalString(jsValue->ToString()))) {
729 return;
730 };
731 CalcDimension length;
732 ParseJsDimensionVp(jsValue, length);
733 if (length.IsNegative()) {
734 TextFieldModel::GetInstance()->SetPadding(NG::PaddingProperty(), Edge(), true);
735 return;
736 }
737 bool tmp = !jsValue->IsString() && !jsValue->IsNumber() && !jsValue->IsObject();
738
739 NG::PaddingProperty newPadding = GetNewPadding(info);
740 Edge oldPadding = Edge(GetOldPadding(info));
741 TextFieldModel::GetInstance()->SetPadding(newPadding, oldPadding, tmp);
742 }
743
GetOldPadding(const JSCallbackInfo& info)744 Edge JSTextField::GetOldPadding(const JSCallbackInfo& info)
745 {
746 Edge padding;
747 auto jsValue = info[0];
748 if (jsValue->IsNumber() || jsValue->IsString()) {
749 CalcDimension edgeValue;
750 if (ParseJsDimensionVp(jsValue, edgeValue)) {
751 padding = Edge(edgeValue);
752 }
753 }
754 if (jsValue->IsObject()) {
755 JSRef<JSObject> object = JSRef<JSObject>::Cast(jsValue);
756 CalcDimension left = CalcDimension(0.0, DimensionUnit::VP);
757 CalcDimension top = CalcDimension(0.0, DimensionUnit::VP);
758 CalcDimension right = CalcDimension(0.0, DimensionUnit::VP);
759 CalcDimension bottom = CalcDimension(0.0, DimensionUnit::VP);
760 ParseJsDimensionVp(object->GetProperty("left"), left);
761 ParseJsDimensionVp(object->GetProperty("top"), top);
762 ParseJsDimensionVp(object->GetProperty("right"), right);
763 ParseJsDimensionVp(object->GetProperty("bottom"), bottom);
764 padding = Edge(left, top, right, bottom);
765 }
766 return padding;
767 }
768
GetNewPadding(const JSCallbackInfo& info)769 NG::PaddingProperty JSTextField::GetNewPadding(const JSCallbackInfo& info)
770 {
771 NG::PaddingProperty padding;
772 auto jsValue = info[0];
773 if (jsValue->IsObject()) {
774 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(jsValue);
775 CommonCalcDimension commonCalcDimension;
776 ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension);
777 if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() ||
778 commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) {
779 padding = SetPaddings(commonCalcDimension.top, commonCalcDimension.bottom, commonCalcDimension.left,
780 commonCalcDimension.right);
781 return padding;
782 }
783 }
784
785 CalcDimension length;
786 if (!ParseJsDimensionVp(jsValue, length)) {
787 // use default value.
788 length.Reset();
789 }
790 padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
791 return padding;
792 }
793
SetPaddings(const std::optional<CalcDimension>& top, const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left, const std::optional<CalcDimension>& right)794 NG::PaddingProperty JSTextField::SetPaddings(const std::optional<CalcDimension>& top,
795 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
796 const std::optional<CalcDimension>& right)
797 {
798 NG::PaddingProperty paddings;
799 if (top.has_value()) {
800 if (top.value().Unit() == DimensionUnit::CALC) {
801 paddings.top =
802 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
803 } else {
804 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
805 }
806 }
807 if (bottom.has_value()) {
808 if (bottom.value().Unit() == DimensionUnit::CALC) {
809 paddings.bottom = NG::CalcLength(
810 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
811 } else {
812 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
813 }
814 }
815 if (left.has_value()) {
816 if (left.value().Unit() == DimensionUnit::CALC) {
817 paddings.left =
818 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
819 } else {
820 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
821 }
822 }
823 if (right.has_value()) {
824 if (right.value().Unit() == DimensionUnit::CALC) {
825 paddings.right =
826 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
827 } else {
828 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
829 }
830 }
831
832 return paddings;
833 }
834
JsBorder(const JSCallbackInfo& info)835 void JSTextField::JsBorder(const JSCallbackInfo& info)
836 {
837 if (!info[0]->IsObject()) {
838 CalcDimension borderWidth;
839 ViewAbstractModel::GetInstance()->SetBorderWidth(borderWidth);
840 ViewAbstractModel::GetInstance()->SetBorderColor(Color::BLACK);
841 ViewAbstractModel::GetInstance()->SetBorderRadius(borderWidth);
842 ViewAbstractModel::GetInstance()->SetBorderStyle(BorderStyle::SOLID);
843 ViewAbstractModel::GetInstance()->SetDashGap(Dimension(-1));
844 ViewAbstractModel::GetInstance()->SetDashWidth(Dimension(-1));
845 return;
846 }
847 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
848
849 auto valueWidth = object->GetProperty(static_cast<int32_t>(ArkUIIndex::WIDTH));
850 if (!valueWidth->IsUndefined()) {
851 JSViewAbstract::ParseBorderWidth(valueWidth);
852 }
853
854 // use default value when undefined.
855 JSViewAbstract::ParseBorderColor(object->GetProperty(static_cast<int32_t>(ArkUIIndex::COLOR)));
856
857 auto valueRadius = object->GetProperty(static_cast<int32_t>(ArkUIIndex::RADIUS));
858 if (!valueRadius->IsUndefined()) {
859 ParseBorderRadius(valueRadius);
860 }
861 // use default value when undefined.
862 JSViewAbstract::ParseBorderStyle(object->GetProperty(static_cast<int32_t>(ArkUIIndex::STYLE)));
863
864 auto dashGap = object->GetProperty("dashGap");
865 if (!dashGap->IsUndefined()) {
866 JSViewAbstract::ParseDashGap(dashGap);
867 }
868 auto dashWidth = object->GetProperty("dashWidth");
869 if (!dashWidth->IsUndefined()) {
870 JSViewAbstract::ParseDashWidth(dashWidth);
871 }
872
873 TextFieldModel::GetInstance()->SetBackBorder();
874 info.ReturnSelf();
875 }
876
JsBorderWidth(const JSCallbackInfo& info)877 void JSTextField::JsBorderWidth(const JSCallbackInfo& info)
878 {
879 auto jsValue = info[0];
880 if (!jsValue->IsObject() && !jsValue->IsString() && !jsValue->IsNumber()) {
881 return;
882 }
883 JSViewAbstract::JsBorderWidth(info);
884 TextFieldModel::GetInstance()->SetBackBorder();
885 }
886
JsBorderColor(const JSCallbackInfo& info)887 void JSTextField::JsBorderColor(const JSCallbackInfo& info)
888 {
889 auto jsValue = info[0];
890 if (!jsValue->IsObject() && !jsValue->IsString() && !jsValue->IsNumber()) {
891 return;
892 }
893 JSViewAbstract::JsBorderColor(info);
894 TextFieldModel::GetInstance()->SetBackBorder();
895 }
896
JsBorderStyle(const JSCallbackInfo& info)897 void JSTextField::JsBorderStyle(const JSCallbackInfo& info)
898 {
899 auto jsValue = info[0];
900 if (!jsValue->IsObject() && !jsValue->IsNumber()) {
901 return;
902 }
903 JSViewAbstract::JsBorderStyle(info);
904 TextFieldModel::GetInstance()->SetBackBorder();
905 }
906
GetBorderRadiusByLengthMetrics(const char* key, JSRef<JSObject>& object, std::optional<CalcDimension>& radius)907 void JSTextField::GetBorderRadiusByLengthMetrics(const char* key, JSRef<JSObject>& object,
908 std::optional<CalcDimension>& radius)
909 {
910 if (object->HasProperty(key) && object->GetProperty(key)->IsObject()) {
911 JSRef<JSObject> startObj = JSRef<JSObject>::Cast(object->GetProperty(key));
912 CalcDimension value;
913 ParseJsLengthMetrics(startObj, value);
914 radius = value;
915 }
916 }
917
ParseAllBorderRadiuses(JSRef<JSObject>& object, CalcDimension& topLeft, CalcDimension& topRight, CalcDimension& bottomLeft, CalcDimension& bottomRight)918 bool JSTextField::ParseAllBorderRadiuses(JSRef<JSObject>& object, CalcDimension& topLeft,
919 CalcDimension& topRight, CalcDimension& bottomLeft, CalcDimension& bottomRight)
920 {
921 if (object->HasProperty(TOP_START_PROPERTY) || object->HasProperty(TOP_END_PROPERTY) ||
922 object->HasProperty(BOTTOM_START_PROPERTY) || object->HasProperty(BOTTOM_END_PROPERTY)) {
923 std::optional<CalcDimension> topStart;
924 std::optional<CalcDimension> topEnd;
925 std::optional<CalcDimension> bottomStart;
926 std::optional<CalcDimension> bottomEnd;
927 GetBorderRadiusByLengthMetrics(TOP_START_PROPERTY, object, topStart);
928 GetBorderRadiusByLengthMetrics(TOP_END_PROPERTY, object, topEnd);
929 GetBorderRadiusByLengthMetrics(BOTTOM_START_PROPERTY, object, bottomStart);
930 GetBorderRadiusByLengthMetrics(BOTTOM_END_PROPERTY, object, bottomEnd);
931 topLeft = topStart.has_value() ? topStart.value() : topLeft;
932 topRight = topEnd.has_value() ? topEnd.value() : topRight;
933 bottomLeft = bottomStart.has_value() ? bottomStart.value() : bottomLeft;
934 bottomRight = bottomEnd.has_value() ? bottomEnd.value() : bottomRight;
935 return true;
936 }
937 JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topLeft"), topLeft);
938 JSViewAbstract::ParseJsDimensionVp(object->GetProperty("topRight"), topRight);
939 JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomLeft"), bottomLeft);
940 JSViewAbstract::ParseJsDimensionVp(object->GetProperty("bottomRight"), bottomRight);
941 return false;
942 }
943
ParseBorderRadius(const JSRef<JSVal>& args)944 void JSTextField::ParseBorderRadius(const JSRef<JSVal>& args)
945 {
946 CalcDimension borderRadius;
947 if (ParseJsDimensionVp(args, borderRadius)) {
948 ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius);
949 } else if (args->IsObject()) {
950 auto textFieldTheme = GetTheme<TextFieldTheme>();
951 CHECK_NULL_VOID(textFieldTheme);
952 auto borderRadiusTheme = textFieldTheme->GetBorderRadius();
953 NG::BorderRadiusProperty defaultBorderRadius {
954 borderRadiusTheme.GetX(), borderRadiusTheme.GetY(),
955 borderRadiusTheme.GetY(), borderRadiusTheme.GetX(),
956 };
957
958 JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
959 CalcDimension topLeft = defaultBorderRadius.radiusTopLeft.value();
960 CalcDimension topRight = defaultBorderRadius.radiusTopRight.value();
961 CalcDimension bottomLeft = defaultBorderRadius.radiusBottomLeft.value();
962 CalcDimension bottomRight = defaultBorderRadius.radiusBottomRight.value();
963 if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) {
964 ViewAbstractModel::GetInstance()->SetBorderRadius(
965 JSViewAbstract::GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight));
966 return;
967 }
968 ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight);
969 }
970 }
971
JsBorderRadius(const JSCallbackInfo& info)972 void JSTextField::JsBorderRadius(const JSCallbackInfo& info)
973 {
974 auto jsValue = info[0];
975 static std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING,
976 JSCallbackInfoType::NUMBER, JSCallbackInfoType::OBJECT };
977 if (!CheckJSCallbackInfo("JsBorderRadius", jsValue, checkList)) {
978 auto textFieldTheme = GetTheme<TextFieldTheme>();
979 CHECK_NULL_VOID(textFieldTheme);
980 auto borderRadiusTheme = textFieldTheme->GetBorderRadius();
981 NG::BorderRadiusProperty defaultBorderRadius {
982 borderRadiusTheme.GetX(), borderRadiusTheme.GetY(),
983 borderRadiusTheme.GetY(), borderRadiusTheme.GetX(),
984 };
985 ViewAbstractModel::GetInstance()->SetBorderRadius(defaultBorderRadius);
986 return;
987 }
988 ParseBorderRadius(jsValue);
989 TextFieldModel::GetInstance()->SetBackBorder();
990 }
991
JsHoverEffect(const JSCallbackInfo& info)992 void JSTextField::JsHoverEffect(const JSCallbackInfo& info)
993 {
994 auto jsValue = info[0];
995 if (!jsValue->IsNumber()) {
996 return;
997 }
998 TextFieldModel::GetInstance()->SetHoverEffect(static_cast<HoverEffectType>(jsValue->ToNumber<int32_t>()));
999 }
1000
SetOnEditChanged(const JSCallbackInfo& info)1001 void JSTextField::SetOnEditChanged(const JSCallbackInfo& info)
1002 {
1003 auto jsValue = info[0];
1004 CHECK_NULL_VOID(jsValue->IsFunction());
1005 JsEventCallback<void(bool)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1006 TextFieldModel::GetInstance()->SetOnEditChanged(std::move(callback));
1007 }
1008
JsKeepEditableState(panda::JsiRuntimeCallInfo *info)1009 Local<JSValueRef> JSTextField::JsKeepEditableState(panda::JsiRuntimeCallInfo *info)
1010 {
1011 Local<JSValueRef> thisObj = info->GetThisRef();
1012 auto eventInfo = static_cast<NG::TextFieldCommonEvent*>(
1013 panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(info->GetVM(), 0));
1014 if (eventInfo) {
1015 eventInfo->SetKeepEditable(true);
1016 }
1017 return JSValueRef::Undefined(info->GetVM());
1018 }
1019
CreateJsTextFieldCommonEvent(const JSCallbackInfo &info)1020 void JSTextField::CreateJsTextFieldCommonEvent(const JSCallbackInfo &info)
1021 {
1022 if (info.Length() < 1 || !info[0]->IsObject()) {
1023 return;
1024 }
1025 auto jsValue = info[0];
1026 auto jsTextFunc = AceType::MakeRefPtr<JsCommonEventFunction<NG::TextFieldCommonEvent, 2>>(
1027 JSRef<JSFunc>::Cast(jsValue));
1028 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1029 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](int32_t key,
1030 NG::TextFieldCommonEvent& event) {
1031 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1032 ACE_SCORING_EVENT("onSubmit");
1033 PipelineContext::SetCallBackNode(node);
1034 JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1035 objectTemplate->SetInternalFieldCount(2);
1036 JSRef<JSObject> object = objectTemplate->NewInstance();
1037 object->SetProperty<std::string>("text", event.GetText());
1038 object->SetPropertyObject("keepEditableState", JSRef<JSFunc>::New<FunctionCallback>(JsKeepEditableState));
1039 object->Wrap<NG::TextFieldCommonEvent>(&event);
1040 JSRef<JSVal> keyEvent = JSRef<JSVal>::Make(ToJSValue(key));
1041 JSRef<JSVal> dataObject = JSRef<JSVal>::Cast(object);
1042 JSRef<JSVal> param[2] = {keyEvent, dataObject};
1043 func->Execute(param);
1044 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
1045 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onSubmit");
1046 #endif
1047 };
1048 TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback));
1049 }
1050
SetOnSubmit(const JSCallbackInfo& info)1051 void JSTextField::SetOnSubmit(const JSCallbackInfo& info)
1052 {
1053 auto jsValue = info[0];
1054 CHECK_NULL_VOID(jsValue->IsFunction());
1055 #ifdef NG_BUILD
1056 CreateJsTextFieldCommonEvent(info);
1057 #else
1058 if (Container::IsCurrentUseNewPipeline()) {
1059 CreateJsTextFieldCommonEvent(info);
1060 } else {
1061 JsEventCallback<void(int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1062 TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback));
1063 }
1064 #endif
1065 }
1066
CreateJsOnChangeObj(const PreviewText& previewText)1067 JSRef<JSVal> JSTextField::CreateJsOnChangeObj(const PreviewText& previewText)
1068 {
1069 JSRef<JSObject> previewTextObj = JSRef<JSObject>::New();
1070 previewTextObj->SetProperty<int32_t>("offset", previewText.offset);
1071 previewTextObj->SetProperty<std::string>("value", previewText.value);
1072 return JSRef<JSVal>::Cast(previewTextObj);
1073 }
1074
SetOnChange(const JSCallbackInfo& info)1075 void JSTextField::SetOnChange(const JSCallbackInfo& info)
1076 {
1077 auto jsValue = info[0];
1078 CHECK_NULL_VOID(jsValue->IsFunction());
1079 auto jsChangeFunc = AceType::MakeRefPtr<JsCitedEventFunction<PreviewText, 2>>(
1080 JSRef<JSFunc>::Cast(jsValue), CreateJsOnChangeObj);
1081 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsChangeFunc)](
1082 const std::string& val, PreviewText& previewText) {
1083 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1084 ACE_SCORING_EVENT("onChange");
1085 func->Execute(val, previewText);
1086 };
1087 TextFieldModel::GetInstance()->SetOnChange(std::move(onChange));
1088 }
1089
SetOnTextSelectionChange(const JSCallbackInfo& info)1090 void JSTextField::SetOnTextSelectionChange(const JSCallbackInfo& info)
1091 {
1092 auto jsValue = info[0];
1093 CHECK_NULL_VOID(jsValue->IsFunction());
1094 JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1095 TextFieldModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
1096 }
1097
SetOnSecurityStateChange(const JSCallbackInfo& info)1098 void JSTextField::SetOnSecurityStateChange(const JSCallbackInfo& info)
1099 {
1100 auto jsValue = info[0];
1101 CHECK_NULL_VOID(jsValue->IsFunction());
1102 JsEventCallback<void(bool)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1103 TextFieldModel::GetInstance()->SetOnSecurityStateChange(std::move(callback));
1104 }
1105
SetOnContentScroll(const JSCallbackInfo& info)1106 void JSTextField::SetOnContentScroll(const JSCallbackInfo& info)
1107 {
1108 auto jsValue = info[0];
1109 CHECK_NULL_VOID(jsValue->IsFunction());
1110 JsEventCallback<void(float, float)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1111 TextFieldModel::GetInstance()->SetOnContentScroll(std::move(callback));
1112 }
1113
SetOnCopy(const JSCallbackInfo& info)1114 void JSTextField::SetOnCopy(const JSCallbackInfo& info)
1115 {
1116 auto jsValue = info[0];
1117 CHECK_NULL_VOID(jsValue->IsFunction());
1118 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1119 TextFieldModel::GetInstance()->SetOnCopy(std::move(callback));
1120 }
1121
SetOnCut(const JSCallbackInfo& info)1122 void JSTextField::SetOnCut(const JSCallbackInfo& info)
1123 {
1124 auto jsValue = info[0];
1125 CHECK_NULL_VOID(jsValue->IsFunction());
1126 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(jsValue));
1127 TextFieldModel::GetInstance()->SetOnCut(std::move(callback));
1128 }
1129
CreateJSTextCommonEvent(NG::TextCommonEvent& event)1130 JSRef<JSVal> JSTextField::CreateJSTextCommonEvent(NG::TextCommonEvent& event)
1131 {
1132 JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1133 objectTemplate->SetInternalFieldCount(1);
1134 JSRef<JSObject> object = objectTemplate->NewInstance();
1135 object->SetPropertyObject("preventDefault", JSRef<JSFunc>::New<FunctionCallback>(JsPreventDefault));
1136 object->Wrap<NG::TextCommonEvent>(&event);
1137 return JSRef<JSVal>::Cast(object);
1138 }
1139
SetOnPaste(const JSCallbackInfo& info)1140 void JSTextField::SetOnPaste(const JSCallbackInfo& info)
1141 {
1142 auto jsValue = info[0];
1143 CHECK_NULL_VOID(jsValue->IsFunction());
1144 auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 2>>(
1145 JSRef<JSFunc>::Cast(jsValue), CreateJSTextCommonEvent);
1146
1147 auto onPaste = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc)](
1148 const std::string& val, NG::TextCommonEvent& info) {
1149 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1150 ACE_SCORING_EVENT("onPaste");
1151 func->Execute(val, info);
1152 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
1153 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onPaste");
1154 #endif
1155 };
1156 TextFieldModel::GetInstance()->SetOnPasteWithEvent(std::move(onPaste));
1157 }
1158
SetOnClick(const JSCallbackInfo& info)1159 void JSTextField::SetOnClick(const JSCallbackInfo& info)
1160 {
1161 if (Container::IsCurrentUseNewPipeline()) {
1162 JSInteractableView::JsOnClick(info);
1163 return;
1164 }
1165 JsEventCallback<void(const ClickInfo&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
1166 TextFieldModel::GetInstance()->SetOnClick(std::move(callback));
1167 info.ReturnSelf();
1168 }
1169
SetCopyOption(const JSCallbackInfo& info)1170 void JSTextField::SetCopyOption(const JSCallbackInfo& info)
1171 {
1172 if (info.Length() == 0) {
1173 return;
1174 }
1175 auto jsValue = info[0];
1176 if (jsValue->IsUndefined()) {
1177 TextFieldModel::GetInstance()->SetCopyOption(CopyOptions::Local);
1178 return;
1179 }
1180 auto copyOptions = CopyOptions::Local;
1181 if (jsValue->IsNumber()) {
1182 auto emunNumber = jsValue->ToNumber<int>();
1183 copyOptions = static_cast<CopyOptions>(emunNumber);
1184 }
1185 TextFieldModel::GetInstance()->SetCopyOption(copyOptions);
1186 }
1187
SetShowUnderline(const JSCallbackInfo& info)1188 void JSTextField::SetShowUnderline(const JSCallbackInfo& info)
1189 {
1190 auto jsValue = info[0];
1191 if (!jsValue->IsBoolean()) {
1192 TextFieldModel::GetInstance()->SetShowUnderline(false);
1193 return;
1194 }
1195 TextFieldModel::GetInstance()->SetShowUnderline(jsValue->ToBoolean());
1196 }
1197
SetUnderlineColor(const JSCallbackInfo& info)1198 void JSTextField::SetUnderlineColor(const JSCallbackInfo& info)
1199 {
1200 if (info.Length() < 1) {
1201 return;
1202 }
1203 auto jsValue = info[0];
1204 Color underlineColor;
1205 if (ParseJsColor(jsValue, underlineColor)) {
1206 TextFieldModel::GetInstance()->SetNormalUnderlineColor(underlineColor);
1207 } else if (jsValue->IsObject()) {
1208 auto param = JSRef<JSObject>::Cast(jsValue);
1209 UserUnderlineColor userColor = UserUnderlineColor();
1210 auto typingColorProp = param->GetProperty("typing");
1211 Color typing;
1212 if (ParseJsColor(typingColorProp, typing)) {
1213 userColor.typing = typing;
1214 }
1215 auto normalColorProp = param->GetProperty("normal");
1216 Color normal;
1217 if (ParseJsColor(normalColorProp, normal)) {
1218 userColor.normal = normal;
1219 }
1220 auto errorColorProp = param->GetProperty("error");
1221 Color error;
1222 if (ParseJsColor(errorColorProp, error)) {
1223 userColor.error = error;
1224 }
1225 auto disableColorProp = param->GetProperty("disable");
1226 Color disable;
1227 if (ParseJsColor(disableColorProp, disable)) {
1228 userColor.disable = disable;
1229 }
1230 TextFieldModel::GetInstance()->SetUserUnderlineColor(userColor);
1231 } else {
1232 TextFieldModel::GetInstance()->SetUserUnderlineColor(UserUnderlineColor());
1233 }
1234 }
1235
SetPasswordIcon(const JSCallbackInfo& info)1236 void JSTextField::SetPasswordIcon(const JSCallbackInfo& info)
1237 {
1238 if (!Container::IsCurrentUseNewPipeline()) {
1239 return;
1240 }
1241 auto jsValue = info[0];
1242 if (!jsValue->IsObject()) {
1243 return;
1244 }
1245 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
1246 JSRef<JSVal> showVal = jsObj->GetProperty("onIconSrc");
1247 JSRef<JSVal> hideVal = jsObj->GetProperty("offIconSrc");
1248 PasswordIcon passwordIcon;
1249 if (showVal->IsString()) {
1250 passwordIcon.showResult = showVal->ToString();
1251 }
1252 if (hideVal->IsString()) {
1253 passwordIcon.hideResult = hideVal->ToString();
1254 }
1255 if (showVal->IsObject()) {
1256 JSRef<JSVal> bundleName = JSRef<JSObject>::Cast(showVal)->GetProperty("bundleName");
1257 JSRef<JSVal> moduleName = JSRef<JSObject>::Cast(showVal)->GetProperty("moduleName");
1258 if (bundleName->IsString()) {
1259 passwordIcon.showBundleName = bundleName->ToString();
1260 }
1261 if (moduleName->IsString()) {
1262 passwordIcon.showModuleName = moduleName->ToString();
1263 }
1264 ParseJsMedia(JSRef<JSObject>::Cast(showVal), passwordIcon.showResult);
1265 }
1266 if (hideVal->IsObject()) {
1267 JSRef<JSVal> bundleName = JSRef<JSObject>::Cast(hideVal)->GetProperty("bundleName");
1268 JSRef<JSVal> moduleName = JSRef<JSObject>::Cast(hideVal)->GetProperty("moduleName");
1269 if (bundleName->IsString()) {
1270 passwordIcon.hideBundleName = bundleName->ToString();
1271 }
1272 if (moduleName->IsString()) {
1273 passwordIcon.hideModuleName = moduleName->ToString();
1274 }
1275 ParseJsMedia(JSRef<JSObject>::Cast(hideVal), passwordIcon.hideResult);
1276 }
1277 if (!showVal->IsString() && !showVal->IsObject()) {
1278 passwordIcon.showResult = "";
1279 }
1280 if (!hideVal->IsString() && !hideVal->IsObject()) {
1281 passwordIcon.hideResult = "";
1282 }
1283 TextFieldModel::GetInstance()->SetPasswordIcon(passwordIcon);
1284 }
1285
UpdateDecoration(const RefPtr<BoxComponent>& boxComponent, const RefPtr<TextFieldComponent>& component, const Border& boxBorder, const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)1286 void JSTextField::UpdateDecoration(const RefPtr<BoxComponent>& boxComponent,
1287 const RefPtr<TextFieldComponent>& component, const Border& boxBorder,
1288 const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)
1289 {
1290 if (!textFieldTheme) {
1291 return;
1292 }
1293
1294 RefPtr<Decoration> decoration = component->GetDecoration();
1295 RefPtr<Decoration> boxDecoration = boxComponent->GetBackDecoration();
1296 if (!decoration) {
1297 decoration = AceType::MakeRefPtr<Decoration>();
1298 }
1299 if (boxDecoration) {
1300 Border border = decoration->GetBorder();
1301 border.SetLeftEdge(boxBorder.Left());
1302 border.SetRightEdge(boxBorder.Right());
1303 border.SetTopEdge(boxBorder.Top());
1304 border.SetBottomEdge(boxBorder.Bottom());
1305 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
1306 decoration->SetBorder(border);
1307 component->SetOriginBorder(decoration->GetBorder());
1308
1309 if (boxDecoration->GetImage() || boxDecoration->GetGradient().IsValid()) {
1310 // clear box properties except background image and radius.
1311 boxDecoration->SetBackgroundColor(Color::TRANSPARENT);
1312 Border border;
1313 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
1314 boxDecoration->SetBorder(border);
1315 }
1316 } else {
1317 boxDecoration = AceType::MakeRefPtr<Decoration>();
1318 boxDecoration->SetBorderRadius(textFieldTheme->GetBorderRadius());
1319 boxComponent->SetBackDecoration(boxDecoration);
1320 }
1321 }
1322
SetShowUnit(const JSCallbackInfo& info)1323 void JSTextField::SetShowUnit(const JSCallbackInfo& info)
1324 {
1325 auto jsValue = info[0];
1326 if (!jsValue->IsFunction()) {
1327 TextFieldModel::GetInstance()->SetShowUnit(nullptr);
1328 return;
1329 }
1330
1331 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(jsValue));
1332 auto unitFunc = [builderFunc]() { builderFunc->Execute(); };
1333 TextFieldModel::GetInstance()->SetShowUnit(std::move(unitFunc));
1334 }
1335
SetShowError(const JSCallbackInfo& info)1336 void JSTextField::SetShowError(const JSCallbackInfo& info)
1337 {
1338 auto jsValue = info[0];
1339 if (Container::IsCurrentUseNewPipeline()) {
1340 bool isVisible = false;
1341 std::string errorText;
1342 if (ParseJsString(jsValue, errorText)) {
1343 isVisible = true;
1344 }
1345 TextFieldModel::GetInstance()->SetShowError(errorText, isVisible);
1346 }
1347 }
1348
SetShowCounter(const JSCallbackInfo& info)1349 void JSTextField::SetShowCounter(const JSCallbackInfo& info)
1350 {
1351 auto jsValue = info[0];
1352 auto secondJSValue = info[1];
1353 if ((!jsValue->IsBoolean() && !secondJSValue->IsObject())) {
1354 TextFieldModel::GetInstance()->SetShowCounter(false);
1355 return;
1356 }
1357 if (secondJSValue->IsObject()) {
1358 auto paramObject = JSRef<JSObject>::Cast(secondJSValue);
1359 auto param = paramObject->GetProperty("highlightBorder");
1360 auto isBorderShow = param->ToBoolean();
1361 if (!param->IsBoolean() || param->IsUndefined() || param->IsNull()) {
1362 TextFieldModel::GetInstance()->SetShowCounterBorder(true);
1363 } else {
1364 TextFieldModel::GetInstance()->SetShowCounterBorder(isBorderShow);
1365 }
1366 auto parameter = paramObject->GetProperty("thresholdPercentage");
1367 auto inputNumber = parameter->ToNumber<int32_t>();
1368 TextFieldModel::GetInstance()->SetCounterType(inputNumber);
1369 if (parameter->IsNull() || parameter->IsUndefined()) {
1370 TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean());
1371 TextFieldModel::GetInstance()->SetCounterType(DEFAULT_MODE);
1372 return;
1373 }
1374 if (static_cast<uint32_t>(inputNumber) < MINI_VAILD_VALUE ||
1375 static_cast<uint32_t>(inputNumber) > MAX_VAILD_VALUE) {
1376 LOGI("The info is wrong, it is supposed to be a right number");
1377 TextFieldModel::GetInstance()->SetCounterType(ILLEGAL_VALUE);
1378 TextFieldModel::GetInstance()->SetShowCounter(false);
1379 return;
1380 }
1381 TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean());
1382 return;
1383 }
1384 TextFieldModel::GetInstance()->SetShowCounter(jsValue->ToBoolean());
1385 TextFieldModel::GetInstance()->SetCounterType(DEFAULT_MODE);
1386 TextFieldModel::GetInstance()->SetShowCounterBorder(true);
1387 }
1388
SetBarState(const JSCallbackInfo& info)1389 void JSTextField::SetBarState(const JSCallbackInfo& info)
1390 {
1391 if (info.Length() < 1) {
1392 TextFieldModel::GetInstance()->SetBarState(DisplayMode::AUTO);
1393 return;
1394 }
1395 auto jsValue = info[0];
1396 if (!jsValue->IsNumber()) {
1397 TextFieldModel::GetInstance()->SetBarState(DisplayMode::AUTO);
1398 return;
1399 }
1400 DisplayMode displayMode = static_cast<DisplayMode>(jsValue->ToNumber<int32_t>());
1401 TextFieldModel::GetInstance()->SetBarState(displayMode);
1402 }
1403
SetMaxLines(const JSCallbackInfo& info)1404 void JSTextField::SetMaxLines(const JSCallbackInfo& info)
1405 {
1406 if (info.Length() < 1) {
1407 TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES);
1408 return;
1409 }
1410 auto jsValue = info[0];
1411 if (!jsValue->IsNumber() || jsValue->ToNumber<int32_t>() <= 0) {
1412 TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES);
1413 return;
1414 }
1415 TextFieldModel::GetInstance()->SetMaxViewLines(jsValue->ToNumber<uint32_t>());
1416 }
1417
SetEnableKeyboardOnFocus(const JSCallbackInfo& info)1418 void JSTextField::SetEnableKeyboardOnFocus(const JSCallbackInfo& info)
1419 {
1420 if (info.Length() < 1) {
1421 return;
1422 }
1423 auto jsValue = info[0];
1424 if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1425 TextFieldModel::GetInstance()->RequestKeyboardOnFocus(true);
1426 return;
1427 }
1428 TextFieldModel::GetInstance()->RequestKeyboardOnFocus(jsValue->ToBoolean());
1429 }
1430
SetSelectionMenuHidden(const JSCallbackInfo& info)1431 void JSTextField::SetSelectionMenuHidden(const JSCallbackInfo& info)
1432 {
1433 if (info.Length() < 1) {
1434 return;
1435 }
1436 auto jsValue = info[0];
1437 if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1438 TextFieldModel::GetInstance()->SetSelectionMenuHidden(false);
1439 return;
1440 }
1441 TextFieldModel::GetInstance()->SetSelectionMenuHidden(jsValue->ToBoolean());
1442 }
1443
ParseJsCustomKeyboardBuilder( const JSCallbackInfo& info, int32_t index, std::function<void()>& buildFunc)1444 bool JSTextField::ParseJsCustomKeyboardBuilder(
1445 const JSCallbackInfo& info, int32_t index, std::function<void()>& buildFunc)
1446 {
1447 if (info.Length() <= index || !info[index]->IsObject()) {
1448 return false;
1449 }
1450 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[index]);
1451 auto builder = obj->GetProperty("builder");
1452 if (!builder->IsFunction()) {
1453 return false;
1454 }
1455 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
1456 CHECK_NULL_RETURN(builderFunc, false);
1457 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1458 buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc), node = targetNode]() {
1459 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1460 ACE_SCORING_EVENT("CustomKeyboard");
1461 PipelineContext::SetCallBackNode(node);
1462 func->Execute();
1463 };
1464 return true;
1465 }
1466
SetCustomKeyboard(const JSCallbackInfo& info)1467 void JSTextField::SetCustomKeyboard(const JSCallbackInfo& info)
1468 {
1469 if (info.Length() < 1) {
1470 return;
1471 }
1472 auto jsValue = info[0];
1473 if (jsValue->IsUndefined() || jsValue->IsNull() || !jsValue->IsObject()) {
1474 TextFieldModel::GetInstance()->SetCustomKeyboard(nullptr);
1475 return;
1476 }
1477 bool supportAvoidance = false;
1478 if (info.Length() == 2 && info[1]->IsObject()) { // 2 here refers to the number of parameters
1479 auto paramObject = JSRef<JSObject>::Cast(info[1]);
1480 auto isSupportAvoidance = paramObject->GetProperty("supportAvoidance");
1481 if (!isSupportAvoidance->IsNull() && isSupportAvoidance->IsBoolean()) {
1482 supportAvoidance = isSupportAvoidance->ToBoolean();
1483 }
1484 }
1485 std::function<void()> buildFunc;
1486 if (ParseJsCustomKeyboardBuilder(info, 0, buildFunc)) {
1487 TextFieldModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance);
1488 }
1489 }
1490
SetPasswordRules(const JSCallbackInfo& info)1491 void JSTextField::SetPasswordRules(const JSCallbackInfo& info)
1492 {
1493 auto jsValue = info[0];
1494 if (!jsValue->IsString()) {
1495 return;
1496 }
1497 auto passwordRules = jsValue->ToString();
1498 TextFieldModel::GetInstance()->SetPasswordRules(passwordRules);
1499 }
1500
SetEnableAutoFill(const JSCallbackInfo& info)1501 void JSTextField::SetEnableAutoFill(const JSCallbackInfo& info)
1502 {
1503 auto jsValue = info[0];
1504 if (!jsValue->IsBoolean()) {
1505 TextFieldModel::GetInstance()->SetEnableAutoFill(true);
1506 return;
1507 }
1508 TextFieldModel::GetInstance()->SetEnableAutoFill(jsValue->ToBoolean());
1509 }
1510
ConvertStrToCleanNodeStyle(const std::string& value)1511 static CleanNodeStyle ConvertStrToCleanNodeStyle(const std::string& value)
1512 {
1513 if (value == "CONSTANT") {
1514 return CleanNodeStyle::CONSTANT;
1515 } else if (value == "INVISIBLE") {
1516 return CleanNodeStyle::INVISIBLE;
1517 } else {
1518 return CleanNodeStyle::INPUT;
1519 }
1520 }
1521
SetCancelButton(const JSCallbackInfo& info)1522 void JSTextField::SetCancelButton(const JSCallbackInfo& info)
1523 {
1524 if (info.Length() < 1 || !info[0]->IsObject()) {
1525 return;
1526 }
1527 auto param = JSRef<JSObject>::Cast(info[0]);
1528 auto theme = GetTheme<TextFieldTheme>();
1529 CHECK_NULL_VOID(theme);
1530
1531 // set style
1532 std::string styleStr;
1533 CleanNodeStyle cleanNodeStyle;
1534 auto styleProp = param->GetProperty("style");
1535 if (!styleProp->IsNull() && ParseJsString(styleProp, styleStr)) {
1536 cleanNodeStyle = ConvertStrToCleanNodeStyle(styleStr);
1537 } else {
1538 cleanNodeStyle = CleanNodeStyle::INPUT;
1539 }
1540 TextFieldModel::GetInstance()->SetCleanNodeStyle(cleanNodeStyle);
1541 TextFieldModel::GetInstance()->SetIsShowCancelButton(true);
1542
1543 // set default icon
1544 auto iconJsVal = param->GetProperty("icon");
1545 if (iconJsVal->IsUndefined() || iconJsVal->IsNull() || !iconJsVal->IsObject()) {
1546 SetCancelDefaultIcon();
1547 return;
1548 }
1549
1550 auto iconParam = JSRef<JSObject>::Cast(iconJsVal);
1551 bool isSymbolIcon = iconParam->HasProperty("fontColor"); // only SymbolGlyph has fontColor property
1552 if (isSymbolIcon) {
1553 SetCancelSymbolIcon(info);
1554 return;
1555 }
1556
1557 // set icon size
1558 CalcDimension iconSize;
1559 auto iconSizeProp = iconParam->GetProperty("size");
1560 if (!iconSizeProp->IsUndefined() && !iconSizeProp->IsNull() && ParseJsDimensionVpNG(iconSizeProp, iconSize)) {
1561 if (LessNotEqual(iconSize.Value(), 0.0) || iconSize.Unit() == DimensionUnit::PERCENT) {
1562 iconSize = theme->GetIconSize();
1563 }
1564 } else {
1565 iconSize = theme->GetIconSize();
1566 }
1567 TextFieldModel::GetInstance()->SetCancelIconSize(iconSize);
1568 SetCancelIconColorAndIconSrc(iconParam);
1569 }
1570
SetCancelDefaultIcon()1571 void JSTextField::SetCancelDefaultIcon()
1572 {
1573 auto theme = GetTheme<TextFieldTheme>();
1574 CHECK_NULL_VOID(theme);
1575 if (SystemProperties::GetColorMode() == ColorMode::DARK) {
1576 TextFieldModel::GetInstance()->SetCancelIconColor(theme->GetCancelButtonIconColor());
1577 } else {
1578 TextFieldModel::GetInstance()->SetCancelIconColor(Color());
1579 }
1580 TextFieldModel::GetInstance()->SetCancelIconSize(theme->GetIconSize());
1581 TextFieldModel::GetInstance()->SetCanacelIconSrc(std::string(), std::string(), std::string());
1582 TextFieldModel::GetInstance()->SetCancelSymbolIcon(nullptr);
1583 TextFieldModel::GetInstance()->SetCancelButtonSymbol(true);
1584 }
1585
SetCancelSymbolIcon(const JSCallbackInfo& info)1586 void JSTextField::SetCancelSymbolIcon(const JSCallbackInfo& info)
1587 {
1588 if (info[0]->IsObject()) {
1589 std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
1590 auto param = JSRef<JSObject>::Cast(info[0]);
1591 auto iconProp = param->GetProperty("icon");
1592 SetSymbolOptionApply(info, iconSymbol, iconProp);
1593 TextFieldModel::GetInstance()->SetCancelSymbolIcon(iconSymbol);
1594 TextFieldModel::GetInstance()->SetCancelButtonSymbol(true);
1595 }
1596 }
1597
SetCancelIconColorAndIconSrc(const JSRef<JSObject>& iconParam)1598 void JSTextField::SetCancelIconColorAndIconSrc(const JSRef<JSObject>& iconParam)
1599 {
1600 auto theme = GetTheme<TextFieldTheme>();
1601 CHECK_NULL_VOID(theme);
1602 // set icon src
1603 std::string iconSrc;
1604 std::string bundleName;
1605 std::string moduleName;
1606 auto iconSrcProp = iconParam->GetProperty("src");
1607 if (iconSrcProp->IsUndefined() || iconSrcProp->IsNull() || !ParseJsMedia(iconSrcProp, iconSrc)) {
1608 iconSrc = "";
1609 }
1610 GetJsMediaBundleInfo(iconSrcProp, bundleName, moduleName);
1611 TextFieldModel::GetInstance()->SetCanacelIconSrc(iconSrc, bundleName, moduleName);
1612 TextFieldModel::GetInstance()->SetCancelButtonSymbol(false);
1613 // set icon color
1614 Color iconColor;
1615 auto iconColorProp = iconParam->GetProperty("color");
1616 if (!iconColorProp->IsUndefined() && !iconColorProp->IsNull() && ParseJsColor(iconColorProp, iconColor)) {
1617 TextFieldModel::GetInstance()->SetCancelIconColor(iconColor);
1618 return;
1619 }
1620 auto info = ImageSourceInfo(iconSrc, bundleName, moduleName);
1621 if (info.IsSvg() && iconSrc != "") {
1622 // svg need not default color, otherwise multi color svg will render fault
1623 return;
1624 }
1625 if (SystemProperties::GetColorMode() == ColorMode::DARK) {
1626 TextFieldModel::GetInstance()->SetCancelIconColor(theme->GetCancelButtonIconColor());
1627 } else {
1628 TextFieldModel::GetInstance()->SetCancelIconColor(iconColor);
1629 }
1630 }
1631
SetSelectAllValue(const JSCallbackInfo& info)1632 void JSTextField::SetSelectAllValue(const JSCallbackInfo& info)
1633 {
1634 auto infoValue = info[0];
1635 if (!infoValue->IsBoolean() || infoValue->IsUndefined() || infoValue->IsNull()) {
1636 TextFieldModel::GetInstance()->SetSelectAllValue(false);
1637 return;
1638 }
1639
1640 bool isSetSelectAllValue = infoValue->ToBoolean();
1641 TextFieldModel::GetInstance()->SetSelectAllValue(isSetSelectAllValue);
1642 }
1643
SetDecoration(const JSCallbackInfo& info)1644 void JSTextField::SetDecoration(const JSCallbackInfo& info)
1645 {
1646 do {
1647 auto tmpInfo = info[0];
1648 if (!tmpInfo->IsObject()) {
1649 TextFieldModel::GetInstance()->SetTextDecoration(TextDecoration::NONE);
1650 TextFieldModel::GetInstance()->SetTextDecorationColor(Color::BLACK);
1651 TextFieldModel::GetInstance()->SetTextDecorationStyle(TextDecorationStyle::SOLID);
1652 break;
1653 }
1654 JSRef<JSObject> obj = JSRef<JSObject>::Cast(tmpInfo);
1655 JSRef<JSVal> typeValue = obj->GetProperty("type");
1656 JSRef<JSVal> colorValue = obj->GetProperty("color");
1657 JSRef<JSVal> styleValue = obj->GetProperty("style");
1658
1659 auto pipelineContext = PipelineBase::GetCurrentContext();
1660 CHECK_NULL_VOID(pipelineContext);
1661 auto theme = pipelineContext->GetTheme<TextFieldTheme>();
1662 CHECK_NULL_VOID(theme);
1663 TextDecoration textDecoration = theme->GetTextStyle().GetTextDecoration();
1664 if (typeValue->IsNumber()) {
1665 textDecoration = static_cast<TextDecoration>(typeValue->ToNumber<int32_t>());
1666 }
1667 Color result = theme->GetTextStyle().GetTextDecorationColor();
1668 ParseJsColor(colorValue, result, Color::BLACK);
1669 std::optional<TextDecorationStyle> textDecorationStyle;
1670 if (styleValue->IsNumber()) {
1671 textDecorationStyle = static_cast<TextDecorationStyle>(styleValue->ToNumber<int32_t>());
1672 } else {
1673 textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE;
1674 }
1675 TextFieldModel::GetInstance()->SetTextDecoration(textDecoration);
1676 TextFieldModel::GetInstance()->SetTextDecorationColor(result);
1677 if (textDecorationStyle) {
1678 TextFieldModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value());
1679 }
1680 } while (false);
1681 }
1682
SetMinFontSize(const JSCallbackInfo& info)1683 void JSTextField::SetMinFontSize(const JSCallbackInfo& info)
1684 {
1685 if (info.Length() < 1) {
1686 return;
1687 }
1688 CalcDimension minFontSize;
1689 if (!ParseJsDimensionFpNG(info[0], minFontSize, false)) {
1690 TextFieldModel::GetInstance()->SetAdaptMinFontSize(CalcDimension());
1691 return;
1692 }
1693 if (minFontSize.IsNegative()) {
1694 minFontSize = CalcDimension();
1695 }
1696 TextFieldModel::GetInstance()->SetAdaptMinFontSize(minFontSize);
1697 }
1698
SetMaxFontSize(const JSCallbackInfo& info)1699 void JSTextField::SetMaxFontSize(const JSCallbackInfo& info)
1700 {
1701 if (info.Length() < 1) {
1702 return;
1703 }
1704 auto pipelineContext = PipelineBase::GetCurrentContext();
1705 CHECK_NULL_VOID(pipelineContext);
1706 auto theme = pipelineContext->GetTheme<TextFieldTheme>();
1707 CHECK_NULL_VOID(theme);
1708 CalcDimension maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1709 if (!ParseJsDimensionFpNG(info[0], maxFontSize, false)) {
1710 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1711 TextFieldModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
1712 return;
1713 }
1714 if (maxFontSize.IsNegative()) {
1715 maxFontSize = theme->GetTextStyle().GetAdaptMaxFontSize();
1716 }
1717 TextFieldModel::GetInstance()->SetAdaptMaxFontSize(maxFontSize);
1718 }
1719
SetHeightAdaptivePolicy(int32_t value)1720 void JSTextField::SetHeightAdaptivePolicy(int32_t value)
1721 {
1722 if (value < 0 || value >= static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICY.size())) {
1723 value = 0;
1724 }
1725 TextFieldModel::GetInstance()->SetHeightAdaptivePolicy(HEIGHT_ADAPTIVE_POLICY[value]);
1726 }
1727
SetLetterSpacing(const JSCallbackInfo& info)1728 void JSTextField::SetLetterSpacing(const JSCallbackInfo& info)
1729 {
1730 CalcDimension value;
1731 if (!ParseJsDimensionFpNG(info[0], value, false)) {
1732 value.Reset();
1733 TextFieldModel::GetInstance()->SetLetterSpacing(value);
1734 return;
1735 }
1736 TextFieldModel::GetInstance()->SetLetterSpacing(value);
1737 }
1738
SetLineHeight(const JSCallbackInfo& info)1739 void JSTextField::SetLineHeight(const JSCallbackInfo& info)
1740 {
1741 CalcDimension value;
1742 if (!ParseJsDimensionFpNG(info[0], value)) {
1743 value.Reset();
1744 TextFieldModel::GetInstance()->SetLineHeight(value);
1745 return;
1746 }
1747 if (value.IsNegative()) {
1748 value.Reset();
1749 }
1750 TextFieldModel::GetInstance()->SetLineHeight(value);
1751 }
1752
SetLineSpacing(const JSCallbackInfo& info)1753 void JSTextField::SetLineSpacing(const JSCallbackInfo& info)
1754 {
1755 CalcDimension value;
1756 if (!ParseLengthMetricsToPositiveDimension(info[0], value)) {
1757 value.Reset();
1758 }
1759 if (value.IsNegative()) {
1760 value.Reset();
1761 }
1762 TextFieldModel::GetInstance()->SetLineSpacing(value);
1763 }
1764
SetFontFeature(const JSCallbackInfo& info)1765 void JSTextField::SetFontFeature(const JSCallbackInfo& info)
1766 {
1767 if (info.Length() < 1) {
1768 return;
1769 }
1770 auto jsValue = info[0];
1771 std::string fontFeatureSettings = "";
1772 if (jsValue->IsString()) {
1773 fontFeatureSettings = jsValue->ToString();
1774 }
1775 TextFieldModel::GetInstance()->SetFontFeature(ParseFontFeatureSettings(fontFeatureSettings));
1776 }
1777
SetTextOverflow(const JSCallbackInfo& info)1778 void JSTextField::SetTextOverflow(const JSCallbackInfo& info)
1779 {
1780 do {
1781 auto tmpInfo = info[0];
1782 int32_t overflow = 0;
1783 if (info.Length() < 1) {
1784 break;
1785 }
1786 if (tmpInfo->IsUndefined() || tmpInfo->IsNull() || !tmpInfo->IsNumber()) {
1787 overflow = DEFAULT_OVERFLOW;
1788 } else if (tmpInfo->IsNumber()) {
1789 overflow = tmpInfo->ToNumber<int32_t>();
1790 if (overflow < 0 || overflow >= static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
1791 overflow = DEFAULT_OVERFLOW;
1792 }
1793 }
1794 TextFieldModel::GetInstance()->SetTextOverflow(TEXT_OVERFLOWS[overflow]);
1795 } while (false);
1796
1797 info.SetReturnValue(info.This());
1798 }
1799
SetTextIndent(const JSCallbackInfo& info)1800 void JSTextField::SetTextIndent(const JSCallbackInfo& info)
1801 {
1802 CalcDimension value;
1803 if (!ParseJsDimensionVpNG(info[0], value, true)) {
1804 value.Reset();
1805 }
1806 TextFieldModel::GetInstance()->SetTextIndent(value);
1807 }
1808
CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue)1809 JSRef<JSVal> JSTextField::CreateJsAboutToIMEInputObj(const InsertValueInfo& insertValue)
1810 {
1811 JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
1812 aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.insertOffset);
1813 aboutToIMEInputObj->SetProperty<std::string>("insertValue", insertValue.insertValue);
1814 return JSRef<JSVal>::Cast(aboutToIMEInputObj);
1815 }
1816
OnWillInsertValue(const JSCallbackInfo& info)1817 void JSTextField::OnWillInsertValue(const JSCallbackInfo& info)
1818 {
1819 auto jsValue = info[0];
1820 CHECK_NULL_VOID(jsValue->IsFunction());
1821 auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<InsertValueInfo, 1>>(
1822 JSRef<JSFunc>::Cast(jsValue), CreateJsAboutToIMEInputObj);
1823 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1824 const InsertValueInfo& insertValue) -> bool {
1825 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
1826 auto ret = func->ExecuteWithValue(insertValue);
1827 if (ret->IsBoolean()) {
1828 return ret->ToBoolean();
1829 }
1830 return true;
1831 };
1832 TextFieldModel::GetInstance()->SetOnWillInsertValueEvent(std::move(callback));
1833 }
1834
CreateJsDeleteToIMEObj(const DeleteValueInfo& deleteValueInfo)1835 JSRef<JSVal> JSTextField::CreateJsDeleteToIMEObj(const DeleteValueInfo& deleteValueInfo)
1836 {
1837 JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
1838 aboutToIMEInputObj->SetProperty<int32_t>("deleteOffset", deleteValueInfo.deleteOffset);
1839 aboutToIMEInputObj->SetProperty<int32_t>("direction", static_cast<int32_t>(deleteValueInfo.direction));
1840 aboutToIMEInputObj->SetProperty<std::string>("deleteValue", deleteValueInfo.deleteValue);
1841 return JSRef<JSVal>::Cast(aboutToIMEInputObj);
1842 }
1843
OnDidInsertValue(const JSCallbackInfo& info)1844 void JSTextField::OnDidInsertValue(const JSCallbackInfo& info)
1845 {
1846 auto jsValue = info[0];
1847 CHECK_NULL_VOID(jsValue->IsFunction());
1848 auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<InsertValueInfo, 1>>(
1849 JSRef<JSFunc>::Cast(jsValue), CreateJsAboutToIMEInputObj);
1850 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1851 const InsertValueInfo& insertValue) {
1852 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1853 func->ExecuteWithValue(insertValue);
1854 };
1855 TextFieldModel::GetInstance()->SetOnDidInsertValueEvent(std::move(callback));
1856 }
1857
OnWillDelete(const JSCallbackInfo& info)1858 void JSTextField::OnWillDelete(const JSCallbackInfo& info)
1859 {
1860 auto jsValue = info[0];
1861 CHECK_NULL_VOID(jsValue->IsFunction());
1862 auto jsAboutToIMEInputFunc =
1863 AceType::MakeRefPtr<JsEventFunction<DeleteValueInfo, 1>>(JSRef<JSFunc>::Cast(jsValue), CreateJsDeleteToIMEObj);
1864 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1865 const DeleteValueInfo& deleteValue) {
1866 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
1867 auto ret = func->ExecuteWithValue(deleteValue);
1868 if (ret->IsBoolean()) {
1869 return ret->ToBoolean();
1870 }
1871 return true;
1872 };
1873 TextFieldModel::GetInstance()->SetOnWillDeleteEvent(std::move(callback));
1874 }
1875
OnDidDelete(const JSCallbackInfo& info)1876 void JSTextField::OnDidDelete(const JSCallbackInfo& info)
1877 {
1878 auto jsValue = info[0];
1879 CHECK_NULL_VOID(jsValue->IsFunction());
1880 auto jsAboutToIMEInputFunc =
1881 AceType::MakeRefPtr<JsEventFunction<DeleteValueInfo, 1>>(JSRef<JSFunc>::Cast(jsValue), CreateJsDeleteToIMEObj);
1882 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
1883 const DeleteValueInfo& deleteValue) {
1884 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1885 func->ExecuteWithValue(deleteValue);
1886 };
1887 TextFieldModel::GetInstance()->SetOnDidDeleteEvent(std::move(callback));
1888 }
1889
EditMenuOptions(const JSCallbackInfo& info)1890 void JSTextField::EditMenuOptions(const JSCallbackInfo& info)
1891 {
1892 NG::OnCreateMenuCallback onCreateMenuCallback;
1893 NG::OnMenuItemClickCallback onMenuItemClick;
1894 JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
1895 TextFieldModel::GetInstance()->SetSelectionMenuOptions(std::move(onCreateMenuCallback), std::move(onMenuItemClick));
1896 }
1897
SetEnablePreviewText(const JSCallbackInfo& info)1898 void JSTextField::SetEnablePreviewText(const JSCallbackInfo& info)
1899 {
1900 auto jsValue = info[0];
1901 if (!jsValue->IsBoolean()) {
1902 TextFieldModel::GetInstance()->SetEnablePreviewText(true);
1903 return;
1904 }
1905 TextFieldModel::GetInstance()->SetEnablePreviewText(jsValue->ToBoolean());
1906 }
1907
SetEnableHapticFeedback(const JSCallbackInfo& info)1908 void JSTextField::SetEnableHapticFeedback(const JSCallbackInfo& info)
1909 {
1910 bool state = true;
1911 if (info.Length() > 0 && info[0]->IsBoolean()) {
1912 state = info[0]->ToBoolean();
1913 }
1914 TextFieldModel::GetInstance()->SetEnableHapticFeedback(state);
1915 }
1916
1917 } // namespace OHOS::Ace::Framework
1918