1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/jsview/js_textfield.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <vector>
21
22 #include "base/geometry/dimension.h"
23 #include "base/log/ace_scoring_log.h"
24 #include "base/utils/utils.h"
25 #include "bridge/common/utils/utils.h"
26 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
27 #include "bridge/declarative_frontend/engine/functions/js_clipboard_function.h"
28 #include "bridge/declarative_frontend/engine/functions/js_function.h"
29 #include "bridge/declarative_frontend/jsview/js_container_base.h"
30 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
31 #include "bridge/declarative_frontend/jsview/js_textarea.h"
32 #include "bridge/declarative_frontend/jsview/js_textinput.h"
33 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
34 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
35 #include "bridge/declarative_frontend/jsview/models/text_field_model_impl.h"
36 #include "core/common/container.h"
37 #include "core/common/ime/text_input_action.h"
38 #include "core/common/ime/text_input_type.h"
39 #include "core/components/common/layout/constants.h"
40 #include "core/components/text_field/textfield_theme.h"
41 #include "core/components_ng/base/view_abstract.h"
42 #include "core/components_ng/pattern/text_field/text_field_model.h"
43 #include "core/components_ng/pattern/text_field/text_field_model_ng.h"
44 #include "core/pipeline/pipeline_base.h"
45
46 namespace OHOS::Ace {
47
48 std::unique_ptr<TextFieldModel> TextFieldModel::instance_ = nullptr;
49 std::mutex TextFieldModel::mutex_;
50
GetInstance()51 TextFieldModel* TextFieldModel::GetInstance()
52 {
53 if (!instance_) {
54 std::lock_guard<std::mutex> lock(mutex_);
55 if (!instance_) {
56 #ifdef NG_BUILD
57 instance_.reset(new NG::TextFieldModelNG());
58 #else
59 if (Container::IsCurrentUseNewPipeline()) {
60 instance_.reset(new NG::TextFieldModelNG());
61 } else {
62 instance_.reset(new Framework::TextFieldModelImpl());
63 }
64 #endif
65 }
66 }
67 return instance_.get();
68 }
69
70 } // namespace OHOS::Ace
71
72 namespace OHOS::Ace::Framework {
73
74 namespace {
75
76 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END };
77 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
78 const std::vector<std::string> INPUT_FONT_FAMILY_VALUE = { "sans-serif" };
79 const uint32_t MAX_LINES = 3;
80 } // namespace
81
ParseTextFieldTextObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)82 void ParseTextFieldTextObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
83 {
84 CHECK_NULL_VOID(changeEventVal->IsFunction());
85
86 JsEventCallback<void(const std::string&)> onChangeEvent(
87 info.GetExecutionContext(), JSRef<JSFunc>::Cast(changeEventVal));
88 TextFieldModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
89 }
90
CreateTextInput(const JSCallbackInfo & info)91 void JSTextField::CreateTextInput(const JSCallbackInfo& info)
92 {
93 std::optional<std::string> placeholderSrc;
94 std::optional<std::string> value;
95 JSTextInputController* jsController = nullptr;
96 JSRef<JSVal> changeEventVal = JSRef<JSVal>::Make();
97 if (info[0]->IsObject()) {
98 auto paramObject = JSRef<JSObject>::Cast(info[0]);
99 std::string placeholder;
100 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
101 placeholderSrc = placeholder;
102 }
103 std::string text;
104 JSRef<JSVal> textValue = paramObject->GetProperty("text");
105 if (textValue->IsObject()) {
106 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(textValue);
107 changeEventVal = valueObj->GetProperty("changeEvent");
108 if (changeEventVal->IsFunction()) {
109 textValue = valueObj->GetProperty("value");
110 }
111 if (ParseJsString(textValue, text)) {
112 value = text;
113 }
114 } else if (paramObject->HasProperty("text")) {
115 if (ParseJsString(textValue, text)) {
116 value = text;
117 }
118 if (textValue->IsUndefined()) {
119 value = "";
120 }
121 }
122 auto controllerObj = paramObject->GetProperty("controller");
123 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
124 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextInputController>();
125 }
126 }
127
128 auto controller = TextFieldModel::GetInstance()->CreateTextInput(placeholderSrc, value);
129 if (jsController) {
130 jsController->SetController(controller);
131 }
132 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
133 ParseTextFieldTextObject(info, changeEventVal);
134 }
135
136 TextFieldModel::GetInstance()->SetFocusableAndFocusNode();
137 }
138
CreateTextArea(const JSCallbackInfo & info)139 void JSTextField::CreateTextArea(const JSCallbackInfo& info)
140 {
141 std::optional<std::string> placeholderSrc;
142 std::optional<std::string> value;
143 JSTextAreaController* jsController = nullptr;
144 JSRef<JSVal> changeEventVal = JSRef<JSVal>::Make();
145 if (info[0]->IsObject()) {
146 auto paramObject = JSRef<JSObject>::Cast(info[0]);
147 std::string placeholder;
148 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
149 placeholderSrc = placeholder;
150 }
151 std::string text;
152 JSRef<JSVal> textValue = paramObject->GetProperty("text");
153 if (textValue->IsObject()) {
154 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(textValue);
155 changeEventVal = valueObj->GetProperty("changeEvent");
156 if (changeEventVal->IsFunction()) {
157 textValue = valueObj->GetProperty("value");
158 }
159 if (ParseJsString(textValue, text)) {
160 value = text;
161 }
162 } else if (paramObject->HasProperty("text")) {
163 if (ParseJsString(textValue, text)) {
164 value = text;
165 }
166 if (textValue->IsUndefined()) {
167 value = "";
168 }
169 }
170 auto controllerObj = paramObject->GetProperty("controller");
171 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
172 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextAreaController>();
173 }
174 }
175 auto controller = TextFieldModel::GetInstance()->CreateTextArea(placeholderSrc, value);
176 if (jsController) {
177 jsController->SetController(controller);
178 }
179 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
180 ParseTextFieldTextObject(info, changeEventVal);
181 }
182
183 TextFieldModel::GetInstance()->SetFocusableAndFocusNode();
184 }
185
SetType(const JSCallbackInfo & info)186 void JSTextField::SetType(const JSCallbackInfo& info)
187 {
188 if (info.Length() < 1) {
189 LOGI("SetType create error, info is non-valid");
190 return;
191 }
192 if (!info[0]->IsNumber()) {
193 LOGI("The inputType is not number");
194 return;
195 }
196 TextInputType textInputType = static_cast<TextInputType>(info[0]->ToNumber<int32_t>());
197 TextFieldModel::GetInstance()->SetType(textInputType);
198 }
199
SetPlaceholderColor(const JSCallbackInfo & info)200 void JSTextField::SetPlaceholderColor(const JSCallbackInfo& info)
201 {
202 if (info.Length() < 1) {
203 LOGI("The arg(SetPlaceholderColor) is wrong, it is supposed to have atleast 1 argument");
204 return;
205 }
206
207 auto theme = GetTheme<TextFieldTheme>();
208 CHECK_NULL_VOID(theme);
209 Color color = theme->GetPlaceholderColor();
210 CheckColor(info[0], color, V2::TEXTINPUT_ETS_TAG, "PlaceholderColor");
211 TextFieldModel::GetInstance()->SetPlaceholderColor(color);
212 }
213
SetPlaceholderFont(const JSCallbackInfo & info)214 void JSTextField::SetPlaceholderFont(const JSCallbackInfo& info)
215 {
216 if (info.Length() < 1 || !info[0]->IsObject()) {
217 LOGI("PlaceholderFont create error, info is non-valid");
218 return;
219 }
220 Font font;
221 auto paramObject = JSRef<JSObject>::Cast(info[0]);
222 auto fontSize = paramObject->GetProperty("size");
223 if (fontSize->IsNull() || fontSize->IsUndefined()) {
224 font.fontSize = Dimension(-1);
225 } else {
226 CalcDimension size;
227 if (fontSize->IsString()) {
228 auto result = StringUtils::StringToDimensionWithThemeValue(fontSize->ToString(), true, Dimension(-1));
229 font.fontSize = result;
230 } else if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
231 font.fontSize = Dimension(-1);
232 LOGW("Parse to dimension FP failed.");
233 } else {
234 font.fontSize = size;
235 }
236 }
237
238 std::string weight;
239 auto fontWeight = paramObject->GetProperty("weight");
240 if (!fontWeight->IsNull()) {
241 if (fontWeight->IsNumber()) {
242 weight = std::to_string(fontWeight->ToNumber<int32_t>());
243 } else {
244 ParseJsString(fontWeight, weight);
245 }
246 font.fontWeight = ConvertStrToFontWeight(weight);
247 }
248
249 auto fontFamily = paramObject->GetProperty("family");
250 if (!fontFamily->IsNull()) {
251 std::vector<std::string> fontFamilies;
252 if (ParseJsFontFamilies(fontFamily, fontFamilies)) {
253 font.fontFamilies = fontFamilies;
254 }
255 }
256
257 auto style = paramObject->GetProperty("style");
258 if (!style->IsNull()) {
259 font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
260 }
261 TextFieldModel::GetInstance()->SetPlaceholderFont(font);
262 }
263
SetEnterKeyType(const JSCallbackInfo & info)264 void JSTextField::SetEnterKeyType(const JSCallbackInfo& info)
265 {
266 if (info.Length() < 1) {
267 return;
268 }
269 if (!info[0]->IsNumber()) {
270 LOGI("Info(SetEnterKeyType) is not number");
271 return;
272 }
273 TextInputAction textInputAction = static_cast<TextInputAction>(info[0]->ToNumber<int32_t>());
274 TextFieldModel::GetInstance()->SetEnterKeyType(textInputAction);
275 }
276
SetTextAlign(int32_t value)277 void JSTextField::SetTextAlign(int32_t value)
278 {
279 if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
280 TextFieldModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
281 } else {
282 LOGI("the value is error");
283 }
284 }
285
SetInputStyle(const JSCallbackInfo & info)286 void JSTextField::SetInputStyle(const JSCallbackInfo& info)
287 {
288 if (info.Length() < 1) {
289 LOGI("The arg(SetInputStyle) is wrong, it is supposed to have at least 1 argument");
290 return;
291 }
292 auto styleString = info[0]->ToString();
293 if (styleString == "Inline") {
294 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::INLINE);
295 } else {
296 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::DEFAULT);
297 }
298 }
299
SetCaretColor(const JSCallbackInfo & info)300 void JSTextField::SetCaretColor(const JSCallbackInfo& info)
301 {
302 if (info.Length() < 1) {
303 LOGI("The arg(SetCareColor) is wrong, it is supposed to have atleast 1 argument");
304 return;
305 }
306
307 Color color;
308 if (!ParseJsColor(info[0], color)) {
309 LOGI("info[0] is null");
310 return;
311 }
312
313 TextFieldModel::GetInstance()->SetCaretColor(color);
314 }
315
SetCaretStyle(const JSCallbackInfo & info)316 void JSTextField::SetCaretStyle(const JSCallbackInfo& info)
317 {
318 if (info.Length() < 1 || !info[0]->IsObject()) {
319 LOGW("CaretStyle create error, info is non-valid");
320 return;
321 }
322 CaretStyle caretStyle;
323 auto paramObject = JSRef<JSObject>::Cast(info[0]);
324 auto caretWidth = paramObject->GetProperty("width");
325
326 auto pipeline = PipelineBase::GetCurrentContext();
327 CHECK_NULL_VOID(pipeline);
328 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
329 CHECK_NULL_VOID_NOLOG(theme);
330 if (caretWidth->IsNull() || caretWidth->IsUndefined()) {
331 caretStyle.caretWidth = theme->GetCursorWidth();
332 } else {
333 CalcDimension width;
334 if (!ParseJsDimensionVpNG(caretWidth, width, false)) {
335 width = theme->GetCursorWidth();
336 }
337 if (LessNotEqual(width.Value(), 0.0)) {
338 width = theme->GetCursorWidth();
339 }
340 caretStyle.caretWidth = width;
341 }
342 TextFieldModel::GetInstance()->SetCaretStyle(caretStyle);
343 }
344
SetCaretPosition(const JSCallbackInfo & info)345 void JSTextField::SetCaretPosition(const JSCallbackInfo& info)
346 {
347 if (info.Length() < 1) {
348 LOGW("The arg(SetCaretPosition) is wrong, it is supposed to have at least 1 arguments");
349 return;
350 }
351
352 int32_t caretPosition = 0;
353 if (!ParseJsInt32(info[0], caretPosition)) {
354 return;
355 }
356 if (caretPosition < 0) {
357 return;
358 }
359 TextFieldModel::GetInstance()->SetCaretPosition(caretPosition);
360 }
361
SetSelectedBackgroundColor(const JSCallbackInfo & info)362 void JSTextField::SetSelectedBackgroundColor(const JSCallbackInfo& info)
363 {
364 if (info.Length() < 1) {
365 LOGW("The arg(SetSelectedBackgroundColor) is wrong, it is supposed to have atleast 1 argument");
366 return;
367 }
368
369 Color selectedColor;
370 if (!ParseJsColor(info[0], selectedColor)) {
371 auto pipeline = PipelineBase::GetCurrentContext();
372 CHECK_NULL_VOID(pipeline);
373 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
374 CHECK_NULL_VOID_NOLOG(theme);
375 selectedColor = theme->GetSelectedColor();
376 }
377 TextFieldModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
378 }
379
SetMaxLength(const JSCallbackInfo & info)380 void JSTextField::SetMaxLength(const JSCallbackInfo& info)
381 {
382 if (info.Length() < 1) {
383 LOGI("The arg(SetMaxLength) is wrong, it is supposed to have atleast 1 argument");
384 return;
385 }
386 int32_t maxLength = 0;
387 if (info[0]->IsUndefined()) {
388 TextFieldModel::GetInstance()->ResetMaxLength();
389 return;
390 } else if (!info[0]->IsNumber()) {
391 LOGI("Max length should be number");
392 TextFieldModel::GetInstance()->ResetMaxLength();
393 return;
394 }
395 maxLength = info[0]->ToNumber<int32_t>();
396 if (GreatOrEqual(maxLength, 0)) {
397 TextFieldModel::GetInstance()->SetMaxLength(maxLength);
398 } else {
399 TextFieldModel::GetInstance()->ResetMaxLength();
400 }
401 }
402
SetFontSize(const JSCallbackInfo & info)403 void JSTextField::SetFontSize(const JSCallbackInfo& info)
404 {
405 if (info.Length() < 1) {
406 LOGI("JSTextField::SetFontSize The argv is wrong, it is supposed to have at least 1 argument");
407 return;
408 }
409 CalcDimension fontSize;
410 if (!ParseJsDimensionNG(info[0], fontSize, DimensionUnit::FP, false)) {
411 LOGI("Parse to dimension FP failed!");
412 auto theme = GetTheme<TextFieldTheme>();
413 CHECK_NULL_VOID(theme);
414 fontSize = theme->GetFontSize();
415 }
416 TextFieldModel::GetInstance()->SetFontSize(fontSize);
417 }
418
SetFontWeight(const std::string & value)419 void JSTextField::SetFontWeight(const std::string& value)
420 {
421 TextFieldModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
422 }
423
SetTextColor(const JSCallbackInfo & info)424 void JSTextField::SetTextColor(const JSCallbackInfo& info)
425 {
426 if (info.Length() < 1) {
427 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
428 return;
429 }
430 Color textColor;
431 if (!ParseJsColor(info[0], textColor)) {
432 auto theme = GetTheme<TextFieldTheme>();
433 CHECK_NULL_VOID_NOLOG(theme);
434 textColor = theme->GetTextColor();
435 }
436 TextFieldModel::GetInstance()->SetTextColor(textColor);
437 }
438
SetForegroundColor(const JSCallbackInfo & info)439 void JSTextField::SetForegroundColor(const JSCallbackInfo& info)
440 {
441 if (info.Length() < 1) {
442 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
443 return;
444 }
445 ForegroundColorStrategy strategy;
446 if (ParseJsColorStrategy(info[0], strategy)) {
447 ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
448 TextFieldModel::GetInstance()->SetForegroundColor(Color::FOREGROUND);
449 return;
450 }
451 Color foregroundColor;
452 if (!ParseJsColor(info[0], foregroundColor)) {
453 return;
454 }
455 ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor);
456 TextFieldModel::GetInstance()->SetForegroundColor(foregroundColor);
457 }
458
SetFontStyle(int32_t value)459 void JSTextField::SetFontStyle(int32_t value)
460 {
461 if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
462 TextFieldModel::GetInstance()->SetFontStyle(FONT_STYLES[value]);
463 } else {
464 LOGI("TextInput fontStyle(%{public}d) illegal value", value);
465 }
466 }
467
SetFontFamily(const JSCallbackInfo & info)468 void JSTextField::SetFontFamily(const JSCallbackInfo& info)
469 {
470 if (info.Length() < 1) {
471 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
472 return;
473 }
474 std::vector<std::string> fontFamilies;
475 if (!ParseJsFontFamilies(info[0], fontFamilies)) {
476 LOGI("Parse FontFamilies failed");
477 return;
478 }
479 TextFieldModel::GetInstance()->SetFontFamily(fontFamilies);
480 }
481
SetInputFilter(const JSCallbackInfo & info)482 void JSTextField::SetInputFilter(const JSCallbackInfo& info)
483 {
484 if (info.Length() < 1) {
485 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
486 return;
487 }
488 std::string inputFilter;
489 if (info[0]->IsUndefined()) {
490 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
491 return;
492 }
493 if (!ParseJsString(info[0], inputFilter)) {
494 LOGI("Parse inputFilter failed");
495 return;
496 }
497 if (info.Length() > 1 && info[1]->IsFunction()) {
498 auto jsFunc = AceType::MakeRefPtr<JsClipboardFunction>(JSRef<JSFunc>::Cast(info[1]));
499 auto resultId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
500 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
501 func->Execute(info);
502 };
503 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, resultId);
504 return;
505 }
506 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
507 }
508
SetShowPasswordIcon(const JSCallbackInfo & info)509 void JSTextField::SetShowPasswordIcon(const JSCallbackInfo& info)
510 {
511 if (!info[0]->IsBoolean()) {
512 LOGI("The info is wrong, it is supposed to be an boolean");
513 return;
514 }
515
516 bool isShowPasswordIcon = info[0]->ToBoolean();
517 TextFieldModel::GetInstance()->SetShowPasswordIcon(isShowPasswordIcon);
518 }
519
SetBackgroundColor(const JSCallbackInfo & info)520 void JSTextField::SetBackgroundColor(const JSCallbackInfo& info)
521 {
522 if (info.Length() < 1) {
523 LOGI("The argv is wrong, it is supposed to have at least 1 argument");
524 return;
525 }
526 Color backgroundColor;
527 bool tmp = !ParseJsColor(info[0], backgroundColor);
528 TextFieldModel::GetInstance()->SetBackgroundColor(backgroundColor, tmp);
529 }
530
JsHeight(const JSCallbackInfo & info)531 void JSTextField::JsHeight(const JSCallbackInfo& info)
532 {
533 JSViewAbstract::JsHeight(info);
534 if (info.Length() < 1) {
535 LOGI("The arg is wrong, it is supposed to have at least 1 arguments");
536 return;
537 }
538 CalcDimension value;
539 if (!ParseJsDimensionVp(info[0], value)) {
540 LOGI("Parse to dimension VP failed!");
541 return;
542 }
543 if (LessNotEqual(value.Value(), 0.0)) {
544 LOGI("dimension value: %{public}f is invalid!", value.Value());
545 ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
546 return;
547 }
548 TextFieldModel::GetInstance()->SetHeight(value);
549 }
550
JsWidth(const JSCallbackInfo & info)551 void JSTextField::JsWidth(const JSCallbackInfo& info)
552 {
553 if (info.Length() < 1) {
554 LOGW("The arg is wrong, it is supposed to have atleast 1 arguments");
555 return;
556 }
557 if (info[0]->IsString() && info[0]->ToString() == "auto") {
558 ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
559 TextFieldModel::GetInstance()->SetWidthAuto(true);
560 return;
561 }
562
563 TextFieldModel::GetInstance()->SetWidthAuto(false);
564 CalcDimension value;
565 if (!ParseJsDimensionVp(info[0], value)) {
566 LOGW("Parse width fail");
567 return;
568 }
569 if (LessNotEqual(value.Value(), 0.0)) {
570 return;
571 }
572 ViewAbstractModel::GetInstance()->SetWidth(value);
573 }
574
CheckIsIllegalString(const std::string & value)575 bool CheckIsIllegalString(const std::string& value)
576 {
577 if (value.empty()) {
578 return true;
579 }
580 errno = 0;
581 char* pEnd = nullptr;
582 std::strtod(value.c_str(), &pEnd);
583 return (pEnd == value.c_str() || errno == ERANGE);
584 }
585
JsPadding(const JSCallbackInfo & info)586 void JSTextField::JsPadding(const JSCallbackInfo& info)
587 {
588 if (info[0]->IsUndefined() || (info[0]->IsString() && CheckIsIllegalString(info[0]->ToString()))) {
589 return;
590 };
591 CalcDimension length;
592 ParseJsDimensionVp(info[0], length);
593 if (length.IsNegative()) {
594 return;
595 }
596 bool tmp = !info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject();
597
598 NG::PaddingProperty newPadding = GetNewPadding(info);
599 Edge oldPadding = Edge(GetOldPadding(info));
600 TextFieldModel::GetInstance()->SetPadding(newPadding, oldPadding, tmp);
601 }
602
GetOldPadding(const JSCallbackInfo & info)603 Edge JSTextField::GetOldPadding(const JSCallbackInfo& info)
604 {
605 Edge padding;
606 if (info[0]->IsNumber() || info[0]->IsString()) {
607 CalcDimension edgeValue;
608 if (ParseJsDimensionVp(info[0], edgeValue)) {
609 padding = Edge(edgeValue);
610 }
611 }
612 if (info[0]->IsObject()) {
613 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
614 CalcDimension left = CalcDimension(0.0, DimensionUnit::VP);
615 CalcDimension top = CalcDimension(0.0, DimensionUnit::VP);
616 CalcDimension right = CalcDimension(0.0, DimensionUnit::VP);
617 CalcDimension bottom = CalcDimension(0.0, DimensionUnit::VP);
618 ParseJsDimensionVp(object->GetProperty("left"), left);
619 ParseJsDimensionVp(object->GetProperty("top"), top);
620 ParseJsDimensionVp(object->GetProperty("right"), right);
621 ParseJsDimensionVp(object->GetProperty("bottom"), bottom);
622 padding = Edge(left, top, right, bottom);
623 }
624 return padding;
625 }
626
GetNewPadding(const JSCallbackInfo & info)627 NG::PaddingProperty JSTextField::GetNewPadding(const JSCallbackInfo& info)
628 {
629 NG::PaddingProperty padding;
630 if (info[0]->IsObject()) {
631 std::optional<CalcDimension> left;
632 std::optional<CalcDimension> right;
633 std::optional<CalcDimension> top;
634 std::optional<CalcDimension> bottom;
635 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
636
637 CalcDimension leftDimen;
638 if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
639 left = leftDimen;
640 }
641 CalcDimension rightDimen;
642 if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
643 right = rightDimen;
644 }
645 CalcDimension topDimen;
646 if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
647 top = topDimen;
648 }
649 CalcDimension bottomDimen;
650 if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
651 bottom = bottomDimen;
652 }
653 if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
654 padding = SetPaddings(top, bottom, left, right);
655 return padding;
656 }
657 }
658
659 CalcDimension length;
660 if (!ParseJsDimensionVp(info[0], length)) {
661 // use default value.
662 length.Reset();
663 }
664 padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
665 return padding;
666 }
667
SetPaddings(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)668 NG::PaddingProperty JSTextField::SetPaddings(const std::optional<CalcDimension>& top,
669 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
670 const std::optional<CalcDimension>& right)
671 {
672 NG::PaddingProperty paddings;
673 if (top.has_value()) {
674 if (top.value().Unit() == DimensionUnit::CALC) {
675 paddings.top =
676 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
677 } else {
678 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
679 }
680 }
681 if (bottom.has_value()) {
682 if (bottom.value().Unit() == DimensionUnit::CALC) {
683 paddings.bottom = NG::CalcLength(
684 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
685 } else {
686 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
687 }
688 }
689 if (left.has_value()) {
690 if (left.value().Unit() == DimensionUnit::CALC) {
691 paddings.left =
692 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
693 } else {
694 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
695 }
696 }
697 if (right.has_value()) {
698 if (right.value().Unit() == DimensionUnit::CALC) {
699 paddings.right =
700 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
701 } else {
702 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
703 }
704 }
705
706 return paddings;
707 }
708
JsBorder(const JSCallbackInfo & info)709 void JSTextField::JsBorder(const JSCallbackInfo& info)
710 {
711 if (!info[0]->IsObject()) {
712 LOGI("args is not a object. %s", info[0]->ToString().c_str());
713 return;
714 }
715 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
716 auto valueWidth = object->GetProperty("width");
717 if (!valueWidth->IsUndefined()) {
718 ParseBorderWidth(valueWidth);
719 }
720 auto valueColor = object->GetProperty("color");
721 if (!valueColor->IsUndefined()) {
722 ParseBorderColor(valueColor);
723 }
724 auto valueRadius = object->GetProperty("radius");
725 if (!valueRadius->IsUndefined()) {
726 ParseBorderRadius(valueRadius);
727 }
728 auto valueStyle = object->GetProperty("style");
729 if (!valueStyle->IsUndefined()) {
730 ParseBorderStyle(valueStyle);
731 }
732 JSViewAbstract::JsBorder(info);
733 TextFieldModel::GetInstance()->SetBackBorder();
734 info.ReturnSelf();
735 }
736
JsBorderWidth(const JSCallbackInfo & info)737 void JSTextField::JsBorderWidth(const JSCallbackInfo& info)
738 {
739 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
740 LOGI("args need a string or number or object");
741 return;
742 }
743 JSViewAbstract::JsBorderWidth(info);
744 TextFieldModel::GetInstance()->SetBackBorder();
745 }
746
JsBorderColor(const JSCallbackInfo & info)747 void JSTextField::JsBorderColor(const JSCallbackInfo& info)
748 {
749 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
750 LOGI("args need a string or number or object");
751 return;
752 }
753 JSViewAbstract::JsBorderColor(info);
754 TextFieldModel::GetInstance()->SetBackBorder();
755 }
756
JsBorderStyle(const JSCallbackInfo & info)757 void JSTextField::JsBorderStyle(const JSCallbackInfo& info)
758 {
759 if (!info[0]->IsObject() && !info[0]->IsNumber()) {
760 LOGI("args need a string or number or object");
761 return;
762 }
763 JSViewAbstract::JsBorderStyle(info);
764 TextFieldModel::GetInstance()->SetBackBorder();
765 }
766
JsBorderRadius(const JSCallbackInfo & info)767 void JSTextField::JsBorderRadius(const JSCallbackInfo& info)
768 {
769 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
770 LOGI("args need a string or number or object");
771 return;
772 }
773 JSViewAbstract::JsBorderRadius(info);
774 TextFieldModel::GetInstance()->SetBackBorder();
775 }
776
JsHoverEffect(const JSCallbackInfo & info)777 void JSTextField::JsHoverEffect(const JSCallbackInfo& info)
778 {
779 if (!info[0]->IsNumber()) {
780 LOGI("info[0] is not a number");
781 return;
782 }
783 TextFieldModel::GetInstance()->SetHoverEffect(static_cast<HoverEffectType>(info[0]->ToNumber<int32_t>()));
784 }
785
SetOnEditChanged(const JSCallbackInfo & info)786 void JSTextField::SetOnEditChanged(const JSCallbackInfo& info)
787 {
788 CHECK_NULL_VOID(info[0]->IsFunction());
789 JsEventCallback<void(bool)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
790 TextFieldModel::GetInstance()->SetOnEditChanged(std::move(callback));
791 }
792
SetOnSubmit(const JSCallbackInfo & info)793 void JSTextField::SetOnSubmit(const JSCallbackInfo& info)
794 {
795 CHECK_NULL_VOID(info[0]->IsFunction());
796 JsEventCallback<void(int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
797 TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback));
798 }
799
SetOnChange(const JSCallbackInfo & info)800 void JSTextField::SetOnChange(const JSCallbackInfo& info)
801 {
802 CHECK_NULL_VOID(info[0]->IsFunction());
803 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
804 TextFieldModel::GetInstance()->SetOnChange(std::move(callback));
805 }
806
SetOnTextSelectionChange(const JSCallbackInfo & info)807 void JSTextField::SetOnTextSelectionChange(const JSCallbackInfo& info)
808 {
809 CHECK_NULL_VOID(info[0]->IsFunction());
810 JsEventCallback<void(int32_t, int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
811 TextFieldModel::GetInstance()->SetOnTextSelectionChange(std::move(callback));
812 }
813
SetOnContentScroll(const JSCallbackInfo & info)814 void JSTextField::SetOnContentScroll(const JSCallbackInfo& info)
815 {
816 CHECK_NULL_VOID(info[0]->IsFunction());
817 JsEventCallback<void(float, float)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
818 TextFieldModel::GetInstance()->SetOnContentScroll(std::move(callback));
819 }
820
SetOnCopy(const JSCallbackInfo & info)821 void JSTextField::SetOnCopy(const JSCallbackInfo& info)
822 {
823 CHECK_NULL_VOID(info[0]->IsFunction());
824 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
825 TextFieldModel::GetInstance()->SetOnCopy(std::move(callback));
826 }
827
SetOnCut(const JSCallbackInfo & info)828 void JSTextField::SetOnCut(const JSCallbackInfo& info)
829 {
830 CHECK_NULL_VOID(info[0]->IsFunction());
831 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
832 TextFieldModel::GetInstance()->SetOnCut(std::move(callback));
833 }
834
SetOnPaste(const JSCallbackInfo & info)835 void JSTextField::SetOnPaste(const JSCallbackInfo& info)
836 {
837 CHECK_NULL_VOID(info[0]->IsFunction());
838 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
839 TextFieldModel::GetInstance()->SetOnPaste(std::move(callback));
840 }
841
SetOnClick(const JSCallbackInfo & info)842 void JSTextField::SetOnClick(const JSCallbackInfo& info)
843 {
844 if (Container::IsCurrentUseNewPipeline()) {
845 JSInteractableView::JsOnClick(info);
846 return;
847 }
848 JsEventCallback<void(const ClickInfo&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
849 TextFieldModel::GetInstance()->SetOnClick(std::move(callback));
850 info.ReturnSelf();
851 }
852
SetCopyOption(const JSCallbackInfo & info)853 void JSTextField::SetCopyOption(const JSCallbackInfo& info)
854 {
855 if (info.Length() == 0) {
856 return;
857 }
858 if (info[0]->IsUndefined()) {
859 TextFieldModel::GetInstance()->SetCopyOption(CopyOptions::Local);
860 return;
861 }
862 auto copyOptions = CopyOptions::None;
863 if (info[0]->IsNumber()) {
864 auto emunNumber = info[0]->ToNumber<int>();
865 copyOptions = static_cast<CopyOptions>(emunNumber);
866 }
867 TextFieldModel::GetInstance()->SetCopyOption(copyOptions);
868 }
869
JsMenuOptionsExtension(const JSCallbackInfo & info)870 void JSTextField::JsMenuOptionsExtension(const JSCallbackInfo& info)
871 {
872 if (info[0]->IsArray()) {
873 std::vector<NG::MenuOptionsParam> menuOptionsItems;
874 JSViewAbstract::ParseMenuOptions(info, JSRef<JSArray>::Cast(info[0]), menuOptionsItems);
875 TextFieldModel::GetInstance()->SetMenuOptionItems(std::move(menuOptionsItems));
876 }
877 }
878
SetShowUnderline(const JSCallbackInfo & info)879 void JSTextField::SetShowUnderline(const JSCallbackInfo& info)
880 {
881 if (!info[0]->IsBoolean()) {
882 LOGI("The info is wrong, it is supposed to be an boolean");
883 TextFieldModel::GetInstance()->SetShowUnderline(false);
884 return;
885 }
886 TextFieldModel::GetInstance()->SetShowUnderline(info[0]->ToBoolean());
887 }
888
SetPasswordIcon(const JSCallbackInfo & info)889 void JSTextField::SetPasswordIcon(const JSCallbackInfo& info)
890 {
891 if (!Container::IsCurrentUseNewPipeline()) {
892 return;
893 }
894 if (!info[0]->IsObject()) {
895 return;
896 }
897 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
898 JSRef<JSVal> showVal = jsObj->GetProperty("onIconSrc");
899 JSRef<JSVal> hideVal = jsObj->GetProperty("offIconSrc");
900 PasswordIcon passwordIcon;
901 if (showVal->IsString()) {
902 passwordIcon.showResult = showVal->ToString();
903 }
904 if (hideVal->IsString()) {
905 passwordIcon.hideResult = hideVal->ToString();
906 }
907 if (showVal->IsObject()) {
908 JSRef<JSVal> bundleName = JSRef<JSObject>::Cast(showVal)->GetProperty("bundleName");
909 JSRef<JSVal> moduleName = JSRef<JSObject>::Cast(showVal)->GetProperty("moduleName");
910 if (bundleName->IsString()) {
911 passwordIcon.showBundleName = bundleName->ToString();
912 }
913 if (moduleName->IsString()) {
914 passwordIcon.showModuleName = moduleName->ToString();
915 }
916 ParseJsMedia(JSRef<JSObject>::Cast(showVal), passwordIcon.showResult);
917 }
918 if (hideVal->IsObject()) {
919 JSRef<JSVal> bundleName = JSRef<JSObject>::Cast(hideVal)->GetProperty("bundleName");
920 JSRef<JSVal> moduleName = JSRef<JSObject>::Cast(hideVal)->GetProperty("moduleName");
921 if (bundleName->IsString()) {
922 passwordIcon.hideBundleName = bundleName->ToString();
923 }
924 if (moduleName->IsString()) {
925 passwordIcon.hideModuleName = moduleName->ToString();
926 }
927 ParseJsMedia(JSRef<JSObject>::Cast(hideVal), passwordIcon.hideResult);
928 }
929 if (!showVal->IsString() && !showVal->IsObject()) {
930 passwordIcon.showResult = "";
931 }
932 if (!hideVal->IsString() && !hideVal->IsObject()) {
933 passwordIcon.hideResult = "";
934 }
935 TextFieldModel::GetInstance()->SetPasswordIcon(passwordIcon);
936 }
937
UpdateDecoration(const RefPtr<BoxComponent> & boxComponent,const RefPtr<TextFieldComponent> & component,const Border & boxBorder,const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme> & textFieldTheme)938 void JSTextField::UpdateDecoration(const RefPtr<BoxComponent>& boxComponent,
939 const RefPtr<TextFieldComponent>& component, const Border& boxBorder,
940 const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)
941 {
942 if (!textFieldTheme) {
943 LOGI("UpdateDecoration: textFieldTheme is null.");
944 return;
945 }
946
947 RefPtr<Decoration> decoration = component->GetDecoration();
948 RefPtr<Decoration> boxDecoration = boxComponent->GetBackDecoration();
949 if (!decoration) {
950 decoration = AceType::MakeRefPtr<Decoration>();
951 }
952 if (boxDecoration) {
953 Border border = decoration->GetBorder();
954 border.SetLeftEdge(boxBorder.Left());
955 border.SetRightEdge(boxBorder.Right());
956 border.SetTopEdge(boxBorder.Top());
957 border.SetBottomEdge(boxBorder.Bottom());
958 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
959 decoration->SetBorder(border);
960 component->SetOriginBorder(decoration->GetBorder());
961
962 if (boxDecoration->GetImage() || boxDecoration->GetGradient().IsValid()) {
963 // clear box properties except background image and radius.
964 boxDecoration->SetBackgroundColor(Color::TRANSPARENT);
965 Border border;
966 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
967 boxDecoration->SetBorder(border);
968 }
969 } else {
970 boxDecoration = AceType::MakeRefPtr<Decoration>();
971 boxDecoration->SetBorderRadius(textFieldTheme->GetBorderRadius());
972 boxComponent->SetBackDecoration(boxDecoration);
973 }
974 }
975
SetShowUnit(const JSCallbackInfo & info)976 void JSTextField::SetShowUnit(const JSCallbackInfo& info)
977 {
978 if (!info[0]->IsFunction()) {
979 LOGI("fail to bind SetShowUnit event due to info is not object");
980 return;
981 }
982
983 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(info[0]));
984 auto unitFunc = [builderFunc]() { builderFunc->Execute(); };
985 TextFieldModel::GetInstance()->SetShowUnit(std::move(unitFunc));
986 }
987
SetShowError(const JSCallbackInfo & info)988 void JSTextField::SetShowError(const JSCallbackInfo& info)
989 {
990 if (Container::IsCurrentUseNewPipeline()) {
991 if (!info[0]->IsUndefined() && !info[0]->IsString()) {
992 LOGI("args need a string or undefined");
993 TextFieldModel::GetInstance()->SetShowError("", false);
994 return;
995 }
996 TextFieldModel::GetInstance()->SetShowError(
997 info[0]->IsString() ? info[0]->ToString() : "", info[0]->IsUndefined() ? false : true);
998 }
999 }
1000
SetShowCounter(const JSCallbackInfo & info)1001 void JSTextField::SetShowCounter(const JSCallbackInfo& info)
1002 {
1003 if (!info[0]->IsBoolean()) {
1004 LOGI("The info is wrong, it is supposed to be an boolean");
1005 TextFieldModel::GetInstance()->SetShowCounter(false);
1006 return;
1007 }
1008
1009 TextFieldModel::GetInstance()->SetShowCounter(info[0]->ToBoolean());
1010 }
1011
SetBarState(const JSCallbackInfo & info)1012 void JSTextField::SetBarState(const JSCallbackInfo& info)
1013 {
1014 if (info.Length() < 1 || !info[0]->IsNumber()) {
1015 LOGI("SetBarState create error, info is not number or non-valid");
1016 TextFieldModel::GetInstance()->SetBarState(DisplayMode::AUTO);
1017 return;
1018 }
1019 DisplayMode displayMode = static_cast<DisplayMode>(info[0]->ToNumber<int32_t>());
1020 TextFieldModel::GetInstance()->SetBarState(displayMode);
1021 }
1022
SetMaxLines(const JSCallbackInfo & info)1023 void JSTextField::SetMaxLines(const JSCallbackInfo& info)
1024 {
1025 if (info.Length() < 1 || !info[0]->IsNumber()) {
1026 LOGI("SetMaxLines create error, info is not number or non-valid");
1027 TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES);
1028 return;
1029 }
1030 if (info[0]->ToNumber<int32_t>() <= 0) {
1031 TextFieldModel::GetInstance()->SetMaxViewLines(MAX_LINES);
1032 return;
1033 }
1034 TextFieldModel::GetInstance()->SetMaxViewLines(info[0]->ToNumber<uint32_t>());
1035 }
1036
SetEnableKeyboardOnFocus(const JSCallbackInfo & info)1037 void JSTextField::SetEnableKeyboardOnFocus(const JSCallbackInfo& info)
1038 {
1039 if (info.Length() < 1) {
1040 LOGW("EnableKeyboardOnFocus should have at least 1 param");
1041 return;
1042 }
1043 if (info[0]->IsUndefined() || !info[0]->IsBoolean()) {
1044 LOGI("The info of SetEnableKeyboardOnFocus is not correct, using default");
1045 TextFieldModel::GetInstance()->RequestKeyboardOnFocus(true);
1046 return;
1047 }
1048 TextFieldModel::GetInstance()->RequestKeyboardOnFocus(info[0]->ToBoolean());
1049 }
1050
SetSelectionMenuHidden(const JSCallbackInfo & info)1051 void JSTextField::SetSelectionMenuHidden(const JSCallbackInfo& info)
1052 {
1053 if (info.Length() < 1) {
1054 LOGW("SelectionMenuHidden should have at least 1 param");
1055 return;
1056 }
1057 if (info[0]->IsUndefined() || !info[0]->IsBoolean()) {
1058 LOGI("The info of SetSelectionMenuHidden is not correct, using default");
1059 TextFieldModel::GetInstance()->SetSelectionMenuHidden(false);
1060 return;
1061 }
1062 TextFieldModel::GetInstance()->SetSelectionMenuHidden(info[0]->ToBoolean());
1063 }
1064
ParseJsCustomKeyboardBuilder(const JSCallbackInfo & info,int32_t index,std::function<void ()> & buildFunc)1065 bool JSTextField::ParseJsCustomKeyboardBuilder(
1066 const JSCallbackInfo& info, int32_t index, std::function<void()>& buildFunc)
1067 {
1068 if (info.Length() <= index) {
1069 return false;
1070 }
1071 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[index]);
1072 auto builder = obj->GetProperty("builder");
1073 if (!builder->IsFunction()) {
1074 return false;
1075 }
1076 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
1077 CHECK_NULL_RETURN(builderFunc, false);
1078 buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
1079 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1080 ACE_SCORING_EVENT("CustomKeyboard");
1081 func->Execute();
1082 };
1083 return true;
1084 }
1085
SetCustomKeyboard(const JSCallbackInfo & info)1086 void JSTextField::SetCustomKeyboard(const JSCallbackInfo& info)
1087 {
1088 if (info.Length() > 0 && (info[0]->IsUndefined() || info[0]->IsNull())) {
1089 TextFieldModel::GetInstance()->SetCustomKeyboard(nullptr);
1090 return;
1091 }
1092 if (info.Length() < 1 || !info[0]->IsObject()) {
1093 return;
1094 }
1095 std::function<void()> buildFunc;
1096 if (ParseJsCustomKeyboardBuilder(info, 0, buildFunc)) {
1097 TextFieldModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc));
1098 }
1099 }
1100 } // namespace OHOS::Ace::Framework
1101