1 /*
2  * Copyright (c) 2021 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 "core/components/declaration/input/input_declaration.h"
17 
18 #include "core/components/declaration/common/declaration_constants.h"
19 #include "frameworks/core/components/text_field/textfield_theme.h"
20 
21 namespace OHOS::Ace {
22 namespace {
23 
24 // input type
25 constexpr char INPUT_TYPE_BUTTON[] = "button";
26 constexpr char INPUT_TYPE_CHECKBOX[] = "checkbox";
27 constexpr char INPUT_TYPE_RADIO[] = "radio";
28 constexpr char INPUT_TYPE_TEXT[] = "text";
29 constexpr char INPUT_TYPE_EMAIL[] = "email";
30 constexpr char INPUT_TYPE_DATE[] = "date";
31 constexpr char INPUT_TYPE_TIME[] = "time";
32 constexpr char INPUT_TYPE_NUMBER[] = "number";
33 constexpr char INPUT_TYPE_PASSWORD[] = "password";
34 
35 std::set<std::string> g_textCategory;
36 
37 // If type is changed between g_textCategory, there is no need to recreate components.
ShouldCreateNewComponent(const std::string & oldType,const std::string & newType)38 bool ShouldCreateNewComponent(const std::string& oldType, const std::string& newType)
39 {
40     if (g_textCategory.empty()) {
41         g_textCategory = std::set<std::string>({
42             INPUT_TYPE_TEXT, INPUT_TYPE_EMAIL, INPUT_TYPE_DATE, INPUT_TYPE_TIME,
43             INPUT_TYPE_NUMBER, INPUT_TYPE_PASSWORD });
44     }
45     return g_textCategory.find(oldType) == g_textCategory.end() || g_textCategory.find(newType) == g_textCategory.end();
46 }
47 
48 } // namespace
49 
50 using namespace Framework;
51 
InitSpecialized()52 void InputDeclaration::InitSpecialized()
53 {
54     AddSpecializedAttribute(DeclarationConstants::DEFAULT_INPUT_ATTR);
55 }
56 
InitializeStyle()57 void InputDeclaration::InitializeStyle()
58 {
59     if (specializedDeclaration_) {
60         specializedDeclaration_->InitializeStyle();
61     }
62 }
63 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)64 bool InputDeclaration::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
65 {
66     static const std::set<std::string> inputCategory { INPUT_TYPE_BUTTON, INPUT_TYPE_CHECKBOX, INPUT_TYPE_RADIO,
67         INPUT_TYPE_TEXT, INPUT_TYPE_EMAIL, INPUT_TYPE_DATE, INPUT_TYPE_TIME, INPUT_TYPE_NUMBER, INPUT_TYPE_PASSWORD };
68     if (attr.first == DOM_INPUT_TYPE) {
69         auto& specializedAttr = MaybeResetAttribute<InputAttribute>(AttributeTag::SPECIALIZED_ATTR);
70         if (specializedAttr.IsValid()) {
71             std::string typeName = attr.second;
72             if (typeName.empty() || inputCategory.find(typeName) == inputCategory.end()) {
73                 typeName = INPUT_TYPE_TEXT;
74             }
75             specializedAttr.type.second = ShouldCreateNewComponent(specializedAttr.type.first, typeName);
76             specializedAttr.type.first = typeName;
77         }
78         return true;
79     }
80     inputAttrs_[attr.first] = attr.second;
81     return false;
82 }
83 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)84 bool InputDeclaration::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
85 {
86     inputStyles_[style.first] = style.second;
87     return false;
88 }
89 
SetSpecializedEvent(int32_t pageId,const std::string & eventId,const std::string & event)90 bool InputDeclaration::SetSpecializedEvent(int32_t pageId, const std::string& eventId, const std::string& event)
91 {
92     inputEvents_[event] = eventId;
93     pageId_ = pageId;
94     return false;
95 }
96 
CallSpecializedMethod(const std::string & method,const std::string & args)97 void InputDeclaration::CallSpecializedMethod(const std::string& method, const std::string& args)
98 {
99     if (g_textCategory.find(GetType()) != g_textCategory.end()) {
100         auto declaration = AceType::DynamicCast<TextFieldDeclaration>(specializedDeclaration_);
101         if (declaration) {
102             declaration->CallSpecializedMethod(method, args);
103         }
104     }
105 }
106 
OnRequestFocus(bool shouldFocus)107 void InputDeclaration::OnRequestFocus(bool shouldFocus)
108 {
109     if (g_textCategory.find(GetType()) != g_textCategory.end()) {
110         auto declaration = AceType::DynamicCast<TextFieldDeclaration>(specializedDeclaration_);
111         if (declaration) {
112             declaration->OnRequestFocus(shouldFocus);
113         }
114     }
115 }
116 
PrepareSpecializedDeclaration()117 void InputDeclaration::PrepareSpecializedDeclaration()
118 {
119     CreateSpecializedDeclaration();
120     auto declaration = AceType::DynamicCast<TextFieldDeclaration>(specializedDeclaration_);
121     if (declaration) {
122         for (const auto& attr : inputAttrs_) {
123             declaration->SetSpecializedAttr(attr);
124         }
125         for (const auto& style : inputStyles_) {
126             declaration->SetSpecializedStyle(style);
127         }
128         for (const auto& event : inputEvents_) {
129             declaration->SetSpecializedEvent(pageId_, event.second, event.first);
130         }
131     }
132 
133     PrepareTextField();
134 }
135 
CreateSpecializedDeclaration()136 void InputDeclaration::CreateSpecializedDeclaration()
137 {
138     std::pair<std::string, bool> type = { INPUT_TYPE_TEXT, true };
139     auto& specializedAttr = static_cast<InputAttribute&>(GetAttribute(AttributeTag::SPECIALIZED_ATTR));
140     if (specializedAttr.IsValid()) {
141         type = specializedAttr.type;
142         if (!type.second) {
143             return;
144         }
145         specializedAttr.type.second = true;
146     }
147 
148     if (specializedAttr.type.first == INPUT_TYPE_BUTTON) {
149     } else if (specializedAttr.type.first == INPUT_TYPE_CHECKBOX) {
150     } else if (specializedAttr.type.first == INPUT_TYPE_RADIO) {
151     } else {
152         specializedDeclaration_ = AceType::MakeRefPtr<TextFieldDeclaration>();
153     }
154     if (specializedDeclaration_) {
155         specializedDeclaration_->BindPipelineContext(pipelineContext_);
156         specializedDeclaration_->Init();
157         specializedDeclaration_->InitializeStyle();
158     }
159 }
160 
PrepareTextField()161 void InputDeclaration::PrepareTextField()
162 {
163     auto textFieldDeclaration = AceType::DynamicCast<TextFieldDeclaration>(specializedDeclaration_);
164     if (!textFieldDeclaration) {
165         return;
166     }
167 
168     // Init disable style.
169     if (!textFieldDeclaration->IsEnabled()) {
170         auto theme = GetTheme<TextFieldTheme>();
171         textFieldDeclaration->SetTextColor(theme->GetDisableTextColor());
172         textFieldDeclaration->SetPlaceholderColor(theme->GetDisableTextColor());
173     }
174 
175     // Set height with height of box.
176     auto& sizeStyle = static_cast<CommonSizeStyle&>(GetStyle(StyleTag::COMMON_SIZE_STYLE));
177     if (sizeStyle.IsValid() && GreatOrEqual(sizeStyle.height.Value(), 0.0)) {
178         textFieldDeclaration->SetHeight(sizeStyle.height);
179     }
180 }
181 
182 } // namespace OHOS::Ace
183