1 /*
2 * Copyright (c) 2022 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 <cstdint>
19 #include <vector>
20
21 #include "base/geometry/dimension.h"
22 #include "base/utils/utils.h"
23 #include "bridge/common/utils/utils.h"
24 #include "bridge/declarative_frontend/engine/functions/js_clipboard_function.h"
25 #include "bridge/declarative_frontend/engine/functions/js_function.h"
26 #include "bridge/declarative_frontend/jsview/js_container_base.h"
27 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
28 #include "bridge/declarative_frontend/jsview/js_textarea.h"
29 #include "bridge/declarative_frontend/jsview/js_textinput.h"
30 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
31 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
32 #include "bridge/declarative_frontend/jsview/models/text_field_model_impl.h"
33 #include "bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h"
34 #include "bridge/declarative_frontend/view_stack_processor.h"
35 #include "core/common/container.h"
36 #include "core/common/ime/text_input_action.h"
37 #include "core/common/ime/text_input_type.h"
38 #include "core/components/text_field/text_field_component.h"
39 #include "core/components/text_field/textfield_theme.h"
40 #include "core/components_ng/base/view_abstract.h"
41 #include "core/components_ng/pattern/text_field/text_field_model.h"
42 #include "core/components_ng/pattern/text_field/text_field_model_ng.h"
43 #include "core/pipeline/pipeline_base.h"
44
45 namespace OHOS::Ace {
46
47 std::unique_ptr<TextFieldModel> TextFieldModel::instance_ = nullptr;
48
GetInstance()49 TextFieldModel* TextFieldModel::GetInstance()
50 {
51 if (!instance_) {
52 #ifdef NG_BUILD
53 instance.reset(new NG::TextFieldModelNG());
54 #else
55 if (Container::IsCurrentUseNewPipeline()) {
56 instance_.reset(new NG::TextFieldModelNG());
57 } else {
58 instance_.reset(new Framework::TextFieldModelImpl());
59 }
60 #endif
61 }
62 return instance_.get();
63 }
64
65 } // namespace OHOS::Ace
66
67 namespace OHOS::Ace::Framework {
68
69 namespace {
70
71 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END };
72 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
73 const std::vector<std::string> INPUT_FONT_FAMILY_VALUE = { "sans-serif" };
74 constexpr uint32_t TEXTAREA_MAXLENGTH_VALUE_DEFAULT = std::numeric_limits<uint32_t>::max();
75
InitTextAreaDefaultStyle()76 void InitTextAreaDefaultStyle()
77 {
78 auto boxComponent = ViewStackProcessor::GetInstance()->GetBoxComponent();
79 auto* stack = ViewStackProcessor::GetInstance();
80 auto textAreaComponent = AceType::DynamicCast<OHOS::Ace::TextFieldComponent>(stack->GetMainComponent());
81 auto pipeline = PipelineBase::GetCurrentContext();
82 CHECK_NULL_VOID(pipeline);
83 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
84 if (!boxComponent || !textAreaComponent || !theme) {
85 LOGE("boxComponent or textAreaComponent or theme is null");
86 return;
87 }
88
89 textAreaComponent->SetTextMaxLines(TEXTAREA_MAXLENGTH_VALUE_DEFAULT);
90 textAreaComponent->SetCursorColor(theme->GetCursorColor());
91 textAreaComponent->SetPlaceholderColor(theme->GetPlaceholderColor());
92 textAreaComponent->SetFocusBgColor(theme->GetFocusBgColor());
93 textAreaComponent->SetFocusPlaceholderColor(theme->GetFocusPlaceholderColor());
94 textAreaComponent->SetFocusTextColor(theme->GetFocusTextColor());
95 textAreaComponent->SetBgColor(theme->GetBgColor());
96 textAreaComponent->SetTextColor(theme->GetTextColor());
97 textAreaComponent->SetSelectedColor(theme->GetSelectedColor());
98 textAreaComponent->SetHoverColor(theme->GetHoverColor());
99 textAreaComponent->SetPressColor(theme->GetPressColor());
100
101 TextStyle textStyle = textAreaComponent->GetTextStyle();
102 textStyle.SetTextColor(theme->GetTextColor());
103 textStyle.SetFontSize(theme->GetFontSize());
104 textStyle.SetFontWeight(theme->GetFontWeight());
105 textStyle.SetFontFamilies(INPUT_FONT_FAMILY_VALUE);
106 textAreaComponent->SetTextStyle(textStyle);
107 textAreaComponent->SetEditingStyle(textStyle);
108 textAreaComponent->SetPlaceHoldStyle(textStyle);
109
110 textAreaComponent->SetCountTextStyle(theme->GetCountTextStyle());
111 textAreaComponent->SetOverCountStyle(theme->GetOverCountStyle());
112 textAreaComponent->SetCountTextStyleOuter(theme->GetCountTextStyleOuter());
113 textAreaComponent->SetOverCountStyleOuter(theme->GetOverCountStyleOuter());
114 textAreaComponent->SetErrorBorderWidth(theme->GetErrorBorderWidth());
115 textAreaComponent->SetErrorBorderColor(theme->GetErrorBorderColor());
116
117 RefPtr<Decoration> backDecoration = AceType::MakeRefPtr<Decoration>();
118 backDecoration->SetPadding(theme->GetPadding());
119 backDecoration->SetBackgroundColor(theme->GetBgColor());
120 backDecoration->SetBorderRadius(theme->GetBorderRadius());
121 const auto& boxDecoration = boxComponent->GetBackDecoration();
122 if (boxDecoration) {
123 backDecoration->SetImage(boxDecoration->GetImage());
124 backDecoration->SetGradient(boxDecoration->GetGradient());
125 }
126 textAreaComponent->SetOriginBorder(backDecoration->GetBorder());
127 textAreaComponent->SetDecoration(backDecoration);
128 textAreaComponent->SetIconSize(theme->GetIconSize());
129 textAreaComponent->SetIconHotZoneSize(theme->GetIconHotZoneSize());
130 textAreaComponent->SetHeight(theme->GetHeight());
131
132 // text area need to extend height.
133 textAreaComponent->SetExtend(true);
134 boxComponent->SetHeight(-1.0, DimensionUnit::VP);
135 }
136
137 } // namespace
138
CreateTextInput(const JSCallbackInfo & info)139 void JSTextField::CreateTextInput(const JSCallbackInfo& info)
140 {
141 std::optional<std::string> placeholderSrc;
142 std::optional<std::string> value;
143 JSTextInputController* jsController = nullptr;
144 if (info[0]->IsObject()) {
145 auto paramObject = JSRef<JSObject>::Cast(info[0]);
146 std::string placeholder;
147 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
148 placeholderSrc = placeholder;
149 }
150 std::string text;
151 if (ParseJsString(paramObject->GetProperty("text"), text)) {
152 value = text;
153 }
154 auto controllerObj = paramObject->GetProperty("controller");
155 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
156 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextInputController>();
157 }
158 }
159
160 auto controller = TextFieldModel::GetInstance()->CreateTextInput(placeholderSrc, value);
161 if (jsController) {
162 jsController->SetController(controller);
163 }
164
165 if (!Container::IsCurrentUseNewPipeline()) {
166 JSInteractableView::SetFocusable(true);
167 JSInteractableView::SetFocusNode(true);
168 }
169 }
170
CreateTextArea(const JSCallbackInfo & info)171 void JSTextField::CreateTextArea(const JSCallbackInfo& info)
172 {
173 std::optional<std::string> placeholderSrc;
174 std::optional<std::string> value;
175 JSTextAreaController* jsController = nullptr;
176 if (info[0]->IsObject()) {
177 auto paramObject = JSRef<JSObject>::Cast(info[0]);
178 std::string placeholder;
179 if (ParseJsString(paramObject->GetProperty("placeholder"), placeholder)) {
180 placeholderSrc = placeholder;
181 }
182 std::string text;
183 if (ParseJsString(paramObject->GetProperty("text"), text)) {
184 value = text;
185 }
186 auto controllerObj = paramObject->GetProperty("controller");
187 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
188 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextAreaController>();
189 }
190 }
191
192 if (Container::IsCurrentUseNewPipeline()) {
193 auto controller = TextFieldModel::GetInstance()->CreateTextArea(placeholderSrc, value);
194 if (jsController) {
195 jsController->SetController(controller);
196 }
197 return;
198 }
199
200 RefPtr<TextFieldComponent> textAreaComponent = AceType::MakeRefPtr<TextFieldComponent>();
201 textAreaComponent->SetTextFieldController(AceType::MakeRefPtr<TextFieldController>());
202 textAreaComponent->SetTextInputType(TextInputType::MULTILINE);
203 textAreaComponent->SetHoverAnimationType(HoverAnimationType::BOARD);
204 auto paramObject = JSRef<JSObject>::Cast(info[0]);
205
206 ViewStackProcessor::GetInstance()->ClaimElementId(textAreaComponent);
207 ViewStackProcessor::GetInstance()->Push(textAreaComponent);
208 InitTextAreaDefaultStyle();
209 Border boxBorder;
210 auto boxComponent = ViewStackProcessor::GetInstance()->GetBoxComponent();
211 auto theme = GetTheme<TextFieldTheme>();
212 if (boxComponent->GetBackDecoration()) {
213 boxBorder = boxComponent->GetBackDecoration()->GetBorder();
214 }
215 if (value) {
216 textAreaComponent->SetValue(value.value());
217 }
218 if (placeholderSrc) {
219 textAreaComponent->SetPlaceholder(placeholderSrc.value());
220 }
221 JSTextField::UpdateDecoration(boxComponent, textAreaComponent, boxBorder, theme);
222 if (jsController) {
223 jsController->SetController(textAreaComponent->GetTextFieldController());
224 }
225
226 JSInteractableView::SetFocusable(true);
227 JSInteractableView::SetFocusNode(true);
228 }
229
SetType(const JSCallbackInfo & info)230 void JSTextField::SetType(const JSCallbackInfo& info)
231 {
232 if (info.Length() < 1) {
233 LOGE("SetType create error, info is non-valid");
234 return;
235 }
236 if (!info[0]->IsNumber()) {
237 LOGE("The inputType is not number");
238 return;
239 }
240 TextInputType textInputType = static_cast<TextInputType>(info[0]->ToNumber<int32_t>());
241 TextFieldModel::GetInstance()->SetType(textInputType);
242 }
243
SetPlaceholderColor(const JSCallbackInfo & info)244 void JSTextField::SetPlaceholderColor(const JSCallbackInfo& info)
245 {
246 if (info.Length() < 1) {
247 LOGE("The arg(SetPlaceholderColor) is wrong, it is supposed to have atleast 1 argument");
248 return;
249 }
250
251 Color color;
252 if (!ParseJsColor(info[0], color)) {
253 LOGE("the info[0] is null");
254 return;
255 }
256 TextFieldModel::GetInstance()->SetPlaceholderColor(color);
257 }
258
SetPlaceholderFont(const JSCallbackInfo & info)259 void JSTextField::SetPlaceholderFont(const JSCallbackInfo& info)
260 {
261 if (info.Length() < 1 || !info[0]->IsObject()) {
262 LOGE("PlaceholderFont create error, info is non-valid");
263 return;
264 }
265 Font font;
266 auto paramObject = JSRef<JSObject>::Cast(info[0]);
267 auto fontSize = paramObject->GetProperty("size");
268 if (fontSize->IsNull() || fontSize->IsUndefined()) {
269 font.fontSize = Dimension(-1);
270 } else {
271 Dimension size;
272 if (fontSize->IsString()) {
273 auto result = StringUtils::StringToDimensionWithThemeValue(fontSize->ToString(), true, Dimension(-1));
274 font.fontSize = result;
275 } else if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
276 font.fontSize = Dimension(-1);
277 LOGW("Parse to dimension FP failed.");
278 } else {
279 font.fontSize = size;
280 }
281 }
282
283 std::string weight;
284 auto fontWeight = paramObject->GetProperty("weight");
285 if (!fontWeight->IsNull()) {
286 if (fontWeight->IsNumber()) {
287 weight = std::to_string(fontWeight->ToNumber<int32_t>());
288 } else {
289 ParseJsString(fontWeight, weight);
290 }
291 font.fontWeight = ConvertStrToFontWeight(weight);
292 }
293
294 auto fontFamily = paramObject->GetProperty("family");
295 if (!fontFamily->IsNull()) {
296 std::vector<std::string> fontFamilies;
297 if (ParseJsFontFamilies(fontFamily, fontFamilies)) {
298 font.fontFamilies = fontFamilies;
299 }
300 }
301
302 auto style = paramObject->GetProperty("style");
303 if (!style->IsNull()) {
304 font.fontStyle = static_cast<FontStyle>(style->ToNumber<int32_t>());
305 }
306 TextFieldModel::GetInstance()->SetPlaceholderFont(font);
307 }
308
SetEnterKeyType(const JSCallbackInfo & info)309 void JSTextField::SetEnterKeyType(const JSCallbackInfo& info)
310 {
311 if (info.Length() < 1) {
312 return;
313 }
314 if (!info[0]->IsNumber()) {
315 LOGE("Info(SetEnterKeyType) is not number");
316 return;
317 }
318 TextInputAction textInputAction = static_cast<TextInputAction>(info[0]->ToNumber<int32_t>());
319 TextFieldModel::GetInstance()->SetEnterKeyType(textInputAction);
320 }
321
SetTextAlign(int32_t value)322 void JSTextField::SetTextAlign(int32_t value)
323 {
324 if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
325 TextFieldModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
326 } else {
327 LOGE("the value is error");
328 }
329 }
330
SetInputStyle(const JSCallbackInfo & info)331 void JSTextField::SetInputStyle(const JSCallbackInfo& info)
332 {
333 if (info.Length() < 1) {
334 LOGE("The arg(SetInputStyle) is wrong, it is supposed to have at least 1 argument");
335 return;
336 }
337 auto styleString = info[0]->ToString();
338 if (styleString == "Inline") {
339 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::INLINE);
340 } else {
341 TextFieldModel::GetInstance()->SetInputStyle(InputStyle::DEFAULT);
342 }
343 }
344
SetCaretColor(const JSCallbackInfo & info)345 void JSTextField::SetCaretColor(const JSCallbackInfo& info)
346 {
347 if (info.Length() < 1) {
348 LOGE("The arg(SetCareColor) is wrong, it is supposed to have atleast 1 argument");
349 return;
350 }
351
352 Color color;
353 if (!ParseJsColor(info[0], color)) {
354 LOGE("info[0] is null");
355 return;
356 }
357
358 TextFieldModel::GetInstance()->SetCaretColor(color);
359 }
360
SetMaxLength(const JSCallbackInfo & info)361 void JSTextField::SetMaxLength(const JSCallbackInfo& info)
362 {
363 if (info.Length() < 1) {
364 LOGI("The arg(SetMaxLength) is wrong, it is supposed to have atleast 1 argument");
365 return;
366 }
367 int32_t maxLength = 0;
368 if (info[0]->IsUndefined()) {
369 TextFieldModel::GetInstance()->ResetMaxLength();
370 return;
371 } else if (!info[0]->IsNumber()) {
372 LOGI("Max length should be number");
373 TextFieldModel::GetInstance()->ResetMaxLength();
374 return;
375 }
376 maxLength = info[0]->ToNumber<int32_t>();
377 if (GreatOrEqual(maxLength, 0)) {
378 TextFieldModel::GetInstance()->SetMaxLength(maxLength);
379 } else {
380 TextFieldModel::GetInstance()->ResetMaxLength();
381 }
382 }
383
SetFontSize(const JSCallbackInfo & info)384 void JSTextField::SetFontSize(const JSCallbackInfo& info)
385 {
386 if (info.Length() < 1) {
387 LOGE("JSTextField::SetFontSize The argv is wrong, it is supposed to have at least 1 argument");
388 return;
389 }
390 Dimension fontSize;
391 if (!ParseJsDimensionFp(info[0], fontSize)) {
392 LOGE("Parse to dimension FP failed!");
393 return;
394 }
395 TextFieldModel::GetInstance()->SetFontSize(fontSize);
396 }
397
SetFontWeight(const std::string & value)398 void JSTextField::SetFontWeight(const std::string& value)
399 {
400 TextFieldModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
401 }
402
SetTextColor(const JSCallbackInfo & info)403 void JSTextField::SetTextColor(const JSCallbackInfo& info)
404 {
405 if (info.Length() < 1) {
406 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
407 return;
408 }
409 Color textColor;
410 if (!ParseJsColor(info[0], textColor)) {
411 LOGE("Parse to dimension FP failed!");
412 return;
413 }
414 TextFieldModel::GetInstance()->SetTextColor(textColor);
415 }
416
SetFontStyle(int32_t value)417 void JSTextField::SetFontStyle(int32_t value)
418 {
419 if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
420 TextFieldModel::GetInstance()->SetFontStyle(FONT_STYLES[value]);
421 } else {
422 LOGE("TextInput fontStyle(%{public}d) illegal value", value);
423 }
424 }
425
SetFontFamily(const JSCallbackInfo & info)426 void JSTextField::SetFontFamily(const JSCallbackInfo& info)
427 {
428 if (info.Length() < 1) {
429 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
430 return;
431 }
432 std::vector<std::string> fontFamilies;
433 if (!ParseJsFontFamilies(info[0], fontFamilies)) {
434 LOGE("Parse FontFamilies failed");
435 return;
436 }
437 TextFieldModel::GetInstance()->SetFontFamily(fontFamilies);
438 }
439
SetInputFilter(const JSCallbackInfo & info)440 void JSTextField::SetInputFilter(const JSCallbackInfo& info)
441 {
442 if (info.Length() < 1) {
443 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
444 return;
445 }
446 std::string inputFilter;
447 if (!ParseJsString(info[0], inputFilter)) {
448 LOGE("Parse inputFilter failed");
449 return;
450 }
451 if (info[1]->IsFunction()) {
452 auto jsFunc = AceType::MakeRefPtr<JsClipboardFunction>(JSRef<JSFunc>::Cast(info[1]));
453 auto resultId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
454 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
455 func->Execute(info);
456 };
457 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, resultId);
458 return;
459 }
460 TextFieldModel::GetInstance()->SetInputFilter(inputFilter, nullptr);
461 }
462
SetShowPasswordIcon(const JSCallbackInfo & info)463 void JSTextField::SetShowPasswordIcon(const JSCallbackInfo& info)
464 {
465 if (!info[0]->IsBoolean()) {
466 LOGE("The info is wrong, it is supposed to be an boolean");
467 return;
468 }
469
470 bool isShowPasswordIcon = info[0]->ToBoolean();
471 TextFieldModel::GetInstance()->SetShowPasswordIcon(isShowPasswordIcon);
472 }
473
SetBackgroundColor(const JSCallbackInfo & info)474 void JSTextField::SetBackgroundColor(const JSCallbackInfo& info)
475 {
476 if (Container::IsCurrentUseNewPipeline()) {
477 if (info.Length() < 1) {
478 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
479 return;
480 }
481 Color backgroundColor;
482 if (!ParseJsColor(info[0], backgroundColor)) {
483 auto pipeline = PipelineBase::GetCurrentContext();
484 CHECK_NULL_VOID_NOLOG(pipeline);
485 auto themeManager = pipeline->GetThemeManager();
486 CHECK_NULL_VOID_NOLOG(themeManager);
487 auto theme = themeManager->GetTheme<TextFieldTheme>();
488 CHECK_NULL_VOID_NOLOG(theme);
489 backgroundColor = theme->GetBgColor();
490 }
491 ViewAbstractModel::GetInstance()->SetBackgroundColor(backgroundColor);
492 return;
493 }
494 if (info.Length() < 1) {
495 LOGE("The arg(SetBackgroundColor) is wrong, it is supposed to have atleast 1 argument");
496 return;
497 }
498
499 Color backgroundColor;
500 if (!ParseJsColor(info[0], backgroundColor)) {
501 LOGE("the info[0] is null");
502 return;
503 }
504
505 auto* stack = ViewStackProcessor::GetInstance();
506 auto component = AceType::DynamicCast<OHOS::Ace::TextFieldComponent>(stack->GetMainComponent());
507 if (component) {
508 component->SetBgColor(backgroundColor);
509 } else {
510 LOGE("The component(SetPlaceholderColor) is null");
511 }
512 }
513
JsHeight(const JSCallbackInfo & info)514 void JSTextField::JsHeight(const JSCallbackInfo& info)
515 {
516 JSViewAbstract::JsHeight(info);
517 if (Container::IsCurrentUseNewPipeline()) {
518 return;
519 }
520 if (info.Length() < 1) {
521 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
522 return;
523 }
524 Dimension value;
525 if (!ParseJsDimensionVp(info[0], value)) {
526 LOGE("Parse to dimension VP failed!");
527 return;
528 }
529 if (LessNotEqual(value.Value(), 0.0)) {
530 LOGE("dimension value: %{public}f is invalid!", value.Value());
531 return;
532 }
533 auto* stack = ViewStackProcessor::GetInstance();
534 auto textInputComponent = AceType::DynamicCast<TextFieldComponent>(stack->GetMainComponent());
535 if (!textInputComponent) {
536 LOGE("JSTextInput set height failed, textInputComponent is null.");
537 return;
538 }
539 textInputComponent->SetHeight(value);
540 }
541
JsWidth(const JSCallbackInfo & info)542 void JSTextField::JsWidth(const JSCallbackInfo& info)
543 {
544 if (info.Length() < 1) {
545 LOGW("The arg is wrong, it is supposed to have atleast 1 arguments");
546 return;
547 }
548 if (info[0]->IsString() && info[0]->ToString() == "auto") {
549 ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
550 TextFieldModel::GetInstance()->SetWidthAuto(true);
551 return;
552 }
553
554 TextFieldModel::GetInstance()->SetWidthAuto(false);
555 Dimension value;
556 if (!ParseJsDimensionVp(info[0], value)) {
557 LOGW("Parse width fail");
558 return;
559 }
560 if (LessNotEqual(value.Value(), 0.0)) {
561 return;
562 }
563 ViewAbstractModel::GetInstance()->SetWidth(value);
564 }
565
JsPadding(const JSCallbackInfo & info)566 void JSTextField::JsPadding(const JSCallbackInfo& info)
567 {
568 if (Container::IsCurrentUseNewPipeline()) {
569 if (info[0]->IsUndefined()) {
570 auto pipeline = PipelineBase::GetCurrentContext();
571 CHECK_NULL_VOID(pipeline);
572 auto theme = pipeline->GetThemeManager()->GetTheme<TextFieldTheme>();
573 CHECK_NULL_VOID_NOLOG(theme);
574 auto textFieldPadding = theme->GetPadding();
575 ViewAbstractModel::GetInstance()->SetPaddings(
576 textFieldPadding.Top(), textFieldPadding.Bottom(), textFieldPadding.Left(), textFieldPadding.Right());
577 return;
578 }
579 JSViewAbstract::JsPadding(info);
580 return;
581 }
582 if (!info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject()) {
583 LOGE("arg is not a string, number or object.");
584 return;
585 }
586 Edge padding;
587 if (info[0]->IsNumber() || info[0]->IsString()) {
588 Dimension edgeValue;
589 if (ParseJsDimensionVp(info[0], edgeValue)) {
590 padding = Edge(edgeValue);
591 }
592 }
593 if (info[0]->IsObject()) {
594 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
595 Dimension left = Dimension(0.0, DimensionUnit::VP);
596 Dimension top = Dimension(0.0, DimensionUnit::VP);
597 Dimension right = Dimension(0.0, DimensionUnit::VP);
598 Dimension bottom = Dimension(0.0, DimensionUnit::VP);
599 ParseJsDimensionVp(object->GetProperty("left"), left);
600 ParseJsDimensionVp(object->GetProperty("top"), top);
601 ParseJsDimensionVp(object->GetProperty("right"), right);
602 ParseJsDimensionVp(object->GetProperty("bottom"), bottom);
603 padding = Edge(left, top, right, bottom);
604 }
605 auto* stack = ViewStackProcessor::GetInstance();
606 auto component = AceType::DynamicCast<TextFieldComponent>(stack->GetMainComponent());
607 if (component) {
608 auto decoration = component->GetDecoration();
609 decoration->SetPadding(padding);
610 }
611 }
612
JsBorder(const JSCallbackInfo & info)613 void JSTextField::JsBorder(const JSCallbackInfo& info)
614 {
615 if (Container::IsCurrentUseNewPipeline()) {
616 JSViewAbstract::JsBorder(info);
617 return;
618 }
619 if (!info[0]->IsObject()) {
620 LOGE("args is not a object. %s", info[0]->ToString().c_str());
621 return;
622 }
623 RefPtr<Decoration> decoration = nullptr;
624 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
625 if (component) {
626 decoration = component->GetDecoration();
627 }
628 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
629 auto valueWidth = object->GetProperty("width");
630 if (!valueWidth->IsUndefined()) {
631 ParseBorderWidth(valueWidth);
632 }
633 auto valueColor = object->GetProperty("color");
634 if (!valueColor->IsUndefined()) {
635 ParseBorderColor(valueColor);
636 }
637 auto valueRadius = object->GetProperty("radius");
638 if (!valueRadius->IsUndefined()) {
639 ParseBorderRadius(valueRadius);
640 }
641 auto valueStyle = object->GetProperty("style");
642 if (!valueStyle->IsUndefined()) {
643 ParseBorderStyle(valueStyle);
644 }
645 ViewAbstractModelImpl::SwapBackBorder(decoration);
646 if (component) {
647 component->SetOriginBorder(decoration->GetBorder());
648 }
649 info.ReturnSelf();
650 }
651
JsBorderWidth(const JSCallbackInfo & info)652 void JSTextField::JsBorderWidth(const JSCallbackInfo& info)
653 {
654 if (Container::IsCurrentUseNewPipeline()) {
655 JSViewAbstract::JsBorderWidth(info);
656 return;
657 }
658 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
659 LOGE("args need a string or number or object");
660 return;
661 }
662 RefPtr<Decoration> decoration = nullptr;
663 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
664 if (component) {
665 decoration = component->GetDecoration();
666 }
667 JSViewAbstract::ParseBorderWidth(info[0]);
668 ViewAbstractModelImpl::SwapBackBorder(decoration);
669 if (component) {
670 component->SetOriginBorder(decoration->GetBorder());
671 }
672 }
673
JsBorderColor(const JSCallbackInfo & info)674 void JSTextField::JsBorderColor(const JSCallbackInfo& info)
675 {
676 if (Container::IsCurrentUseNewPipeline()) {
677 JSViewAbstract::JsBorderColor(info);
678 return;
679 }
680 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
681 LOGE("args need a string or number or object");
682 return;
683 }
684 RefPtr<Decoration> decoration = nullptr;
685 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
686 if (component) {
687 decoration = component->GetDecoration();
688 }
689 JSViewAbstract::ParseBorderColor(info[0]);
690 ViewAbstractModelImpl::SwapBackBorder(decoration);
691 if (component) {
692 component->SetOriginBorder(decoration->GetBorder());
693 }
694 }
695
JsBorderStyle(const JSCallbackInfo & info)696 void JSTextField::JsBorderStyle(const JSCallbackInfo& info)
697 {
698 if (Container::IsCurrentUseNewPipeline()) {
699 JSViewAbstract::JsBorderStyle(info);
700 return;
701 }
702 if (!info[0]->IsObject() && !info[0]->IsNumber()) {
703 LOGE("args need a string or number or object");
704 return;
705 }
706 RefPtr<Decoration> decoration = nullptr;
707 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
708 if (component) {
709 decoration = component->GetDecoration();
710 }
711 JSViewAbstract::ParseBorderStyle(info[0]);
712 ViewAbstractModelImpl::SwapBackBorder(decoration);
713 if (component) {
714 component->SetOriginBorder(decoration->GetBorder());
715 }
716 }
717
JsBorderRadius(const JSCallbackInfo & info)718 void JSTextField::JsBorderRadius(const JSCallbackInfo& info)
719 {
720 if (Container::IsCurrentUseNewPipeline()) {
721 JSViewAbstract::JsBorderRadius(info);
722 return;
723 }
724 if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
725 LOGE("args need a string or number or object");
726 return;
727 }
728 RefPtr<Decoration> decoration = nullptr;
729 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
730 if (component) {
731 decoration = component->GetDecoration();
732 }
733 JSViewAbstract::ParseBorderRadius(info[0]);
734 ViewAbstractModelImpl::SwapBackBorder(decoration);
735 if (component) {
736 component->SetOriginBorder(decoration->GetBorder());
737 }
738 }
739
JsHoverEffect(const JSCallbackInfo & info)740 void JSTextField::JsHoverEffect(const JSCallbackInfo& info)
741 {
742 if (!info[0]->IsNumber()) {
743 LOGE("info[0] is not a number");
744 return;
745 }
746 if (Container::IsCurrentUseNewPipeline()) {
747 NG::ViewAbstract::SetHoverEffect(static_cast<HoverEffectType>(info[0]->ToNumber<int32_t>()));
748 return;
749 }
750 auto component = AceType::DynamicCast<TextFieldComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
751 if (component) {
752 component->SetHoverAnimationType(static_cast<HoverAnimationType>(info[0]->ToNumber<int32_t>()));
753 }
754 }
755
SetOnEditChanged(const JSCallbackInfo & info)756 void JSTextField::SetOnEditChanged(const JSCallbackInfo& info)
757 {
758 CHECK_NULL_VOID(info[0]->IsFunction());
759 JsEventCallback<void(bool)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
760 TextFieldModel::GetInstance()->SetOnEditChanged(std::move(callback));
761 }
762
SetOnSubmit(const JSCallbackInfo & info)763 void JSTextField::SetOnSubmit(const JSCallbackInfo& info)
764 {
765 CHECK_NULL_VOID(info[0]->IsFunction());
766 JsEventCallback<void(int32_t)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
767 TextFieldModel::GetInstance()->SetOnSubmit(std::move(callback));
768 }
769
SetOnChange(const JSCallbackInfo & info)770 void JSTextField::SetOnChange(const JSCallbackInfo& info)
771 {
772 CHECK_NULL_VOID(info[0]->IsFunction());
773 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
774 TextFieldModel::GetInstance()->SetOnChange(std::move(callback));
775 }
776
SetOnCopy(const JSCallbackInfo & info)777 void JSTextField::SetOnCopy(const JSCallbackInfo& info)
778 {
779 CHECK_NULL_VOID(info[0]->IsFunction());
780 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
781 TextFieldModel::GetInstance()->SetOnCopy(std::move(callback));
782 }
783
SetOnCut(const JSCallbackInfo & info)784 void JSTextField::SetOnCut(const JSCallbackInfo& info)
785 {
786 CHECK_NULL_VOID(info[0]->IsFunction());
787 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
788 TextFieldModel::GetInstance()->SetOnCut(std::move(callback));
789 }
790
SetOnPaste(const JSCallbackInfo & info)791 void JSTextField::SetOnPaste(const JSCallbackInfo& info)
792 {
793 CHECK_NULL_VOID(info[0]->IsFunction());
794 JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
795 TextFieldModel::GetInstance()->SetOnPaste(std::move(callback));
796 }
797
SetOnClick(const JSCallbackInfo & info)798 void JSTextField::SetOnClick(const JSCallbackInfo& info)
799 {
800 if (Container::IsCurrentUseNewPipeline()) {
801 JSInteractableView::JsOnClick(info);
802 return;
803 }
804 if (!JSViewBindEvent(&TextFieldComponent::SetOnClick, info)) {
805 LOGW("Failed(OnPaste) to bind event");
806 }
807 info.ReturnSelf();
808 }
809
SetCopyOption(const JSCallbackInfo & info)810 void JSTextField::SetCopyOption(const JSCallbackInfo& info)
811 {
812 if (info.Length() == 0) {
813 return;
814 }
815 auto copyOptions = CopyOptions::None;
816 if (info[0]->IsNumber()) {
817 auto emunNumber = info[0]->ToNumber<int>();
818 copyOptions = static_cast<CopyOptions>(emunNumber);
819 }
820 TextFieldModel::GetInstance()->SetCopyOption(copyOptions);
821 }
822
UpdateDecoration(const RefPtr<BoxComponent> & boxComponent,const RefPtr<TextFieldComponent> & component,const Border & boxBorder,const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme> & textFieldTheme)823 void JSTextField::UpdateDecoration(const RefPtr<BoxComponent>& boxComponent,
824 const RefPtr<TextFieldComponent>& component, const Border& boxBorder,
825 const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)
826 {
827 if (!textFieldTheme) {
828 LOGE("UpdateDecoration: textFieldTheme is null.");
829 return;
830 }
831
832 RefPtr<Decoration> decoration = component->GetDecoration();
833 RefPtr<Decoration> boxDecoration = boxComponent->GetBackDecoration();
834 if (!decoration) {
835 decoration = AceType::MakeRefPtr<Decoration>();
836 }
837 if (boxDecoration) {
838 Border border = decoration->GetBorder();
839 border.SetLeftEdge(boxBorder.Left());
840 border.SetRightEdge(boxBorder.Right());
841 border.SetTopEdge(boxBorder.Top());
842 border.SetBottomEdge(boxBorder.Bottom());
843 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
844 decoration->SetBorder(border);
845 component->SetOriginBorder(decoration->GetBorder());
846
847 if (boxDecoration->GetImage() || boxDecoration->GetGradient().IsValid()) {
848 // clear box properties except background image and radius.
849 boxDecoration->SetBackgroundColor(Color::TRANSPARENT);
850 Border border;
851 border.SetBorderRadius(textFieldTheme->GetBorderRadius());
852 boxDecoration->SetBorder(border);
853 }
854 } else {
855 boxDecoration = AceType::MakeRefPtr<Decoration>();
856 boxDecoration->SetBorderRadius(textFieldTheme->GetBorderRadius());
857 boxComponent->SetBackDecoration(boxDecoration);
858 }
859 }
860
861 } // namespace OHOS::Ace::Framework
862