• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_search.h"
17 
18 #include <optional>
19 #include <string>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_textfield.h"
23 #include "bridge/declarative_frontend/jsview/js_textinput.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/search_model_impl.h"
26 #include "bridge/declarative_frontend/jsview/models/view_abstract_model_impl.h"
27 #include "bridge/declarative_frontend/view_stack_processor.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components/search/search_component.h"
30 #include "core/components/search/search_theme.h"
31 #include "core/components/text_field/text_field_component.h"
32 #include "core/components_ng/base/view_abstract.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/pattern/search/search_model_ng.h"
35 
36 namespace OHOS::Ace {
37 
38 std::unique_ptr<SearchModel> SearchModel::instance_ = nullptr;
39 
GetInstance()40 SearchModel* SearchModel::GetInstance()
41 {
42     if (!instance_) {
43 #ifdef NG_BUILD
44         instance_.reset(new NG::SearchModelNG());
45 #else
46         if (Container::IsCurrentUseNewPipeline()) {
47             instance_.reset(new NG::SearchModelNG());
48         } else {
49             instance_.reset(new Framework::SearchModelImpl());
50         }
51 #endif
52     }
53     return instance_.get();
54 }
55 
56 } // namespace OHOS::Ace
57 
58 namespace OHOS::Ace::Framework {
59 
60 namespace {
61 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END };
62 } // namespace
63 
JSBind(BindingTarget globalObj)64 void JSSearch::JSBind(BindingTarget globalObj)
65 {
66     JSClass<JSSearch>::Declare("Search");
67     MethodOptions opt = MethodOptions::NONE;
68 
69     JSClass<JSSearch>::StaticMethod("create", &JSSearch::Create, opt);
70     JSClass<JSSearch>::StaticMethod("searchButton", &JSSearch::SetSearchButton, opt);
71     JSClass<JSSearch>::StaticMethod("placeholderColor", &JSSearch::SetPlaceholderColor, opt);
72     JSClass<JSSearch>::StaticMethod("placeholderFont", &JSSearch::SetPlaceholderFont, opt);
73     JSClass<JSSearch>::StaticMethod("textFont", &JSSearch::SetTextFont, opt);
74     JSClass<JSSearch>::StaticMethod("textAlign", &JSSearch::SetTextAlign, opt);
75     JSClass<JSSearch>::StaticMethod("onSubmit", &JSSearch::OnSubmit, opt);
76     JSClass<JSSearch>::StaticMethod("onChange", &JSSearch::OnChange, opt);
77     JSClass<JSSearch>::StaticMethod("border", &JSSearch::JsBorder);
78     JSClass<JSSearch>::StaticMethod("borderWidth", &JSSearch::JsBorderWidth);
79     JSClass<JSSearch>::StaticMethod("borderColor", &JSSearch::JsBorderColor);
80     JSClass<JSSearch>::StaticMethod("borderStyle", &JSSearch::JsBorderStyle);
81     JSClass<JSSearch>::StaticMethod("borderRadius", &JSSearch::JsBorderRadius);
82     JSClass<JSSearch>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
83     JSClass<JSSearch>::StaticMethod("height", &JSSearch::SetHeight);
84     JSClass<JSSearch>::StaticMethod("width", &JSViewAbstract::JsWidth);
85     JSClass<JSSearch>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
86     JSClass<JSSearch>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
87     JSClass<JSSearch>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
88     JSClass<JSSearch>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
89     JSClass<JSSearch>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
90     JSClass<JSSearch>::StaticMethod("onCopy", &JSSearch::SetOnCopy);
91     JSClass<JSSearch>::StaticMethod("onCut", &JSSearch::SetOnCut);
92     JSClass<JSSearch>::StaticMethod("onPaste", &JSSearch::SetOnPaste);
93     JSClass<JSSearch>::StaticMethod("copyOption", &JSSearch::SetCopyOption);
94     JSClass<JSSearch>::Inherit<JSViewAbstract>();
95     JSClass<JSSearch>::Bind(globalObj);
96 }
97 
Create(const JSCallbackInfo & info)98 void JSSearch::Create(const JSCallbackInfo& info)
99 {
100     std::optional<std::string> key;
101     std::optional<std::string> tip;
102     std::optional<std::string> src;
103     JSSearchController* jsController = nullptr;
104     if (info[0]->IsObject()) {
105         auto param = JSRef<JSObject>::Cast(info[0]);
106         std::string placeholder;
107         if (param->GetProperty("placeholder")->IsUndefined()) {
108             tip = "";
109         }
110         if (ParseJsString(param->GetProperty("placeholder"), placeholder)) {
111             tip = placeholder;
112         }
113         std::string text;
114         if (param->GetProperty("value")->IsUndefined()) {
115             key = "";
116         }
117         if (ParseJsString(param->GetProperty("value"), text)) {
118             key = text;
119         }
120         std::string icon;
121         if (ParseJsString(param->GetProperty("icon"), icon)) {
122             src = icon;
123         }
124         auto controllerObj = param->GetProperty("controller");
125         if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
126             jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSSearchController>();
127         }
128     }
129     auto controller = SearchModel::GetInstance()->Create(key, tip, src);
130     if (jsController) {
131         jsController->SetController(controller);
132     }
133     if (!Container::IsCurrentUseNewPipeline()) {
134         JSInteractableView::SetFocusable(true);
135         JSInteractableView::SetFocusNode(true);
136     }
137 }
138 
SetSearchButton(const std::string & text)139 void JSSearch::SetSearchButton(const std::string& text)
140 {
141     SearchModel::GetInstance()->SetSearchButton(text);
142 }
143 
SetPlaceholderColor(const JSCallbackInfo & info)144 void JSSearch::SetPlaceholderColor(const JSCallbackInfo& info)
145 {
146     auto value = JSRef<JSVal>::Cast(info[0]);
147     Color colorVal;
148     if (ParseJsColor(value, colorVal)) {
149         SearchModel::GetInstance()->SetPlaceholderColor(colorVal);
150     }
151 }
152 
SetPlaceholderFont(const JSCallbackInfo & info)153 void JSSearch::SetPlaceholderFont(const JSCallbackInfo& info)
154 {
155     auto param = JSRef<JSObject>::Cast(info[0]);
156     Font font;
157     auto fontSize = param->GetProperty("size");
158     if (fontSize->IsNull() || fontSize->IsUndefined()) {
159         font.fontSize = Dimension(-1);
160     } else {
161         Dimension size;
162         if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
163             font.fontSize = Dimension(-1);
164             LOGW("Parse to dimension FP failed.");
165         } else {
166             font.fontSize = size;
167         }
168     }
169 
170     auto weight = param->GetProperty("weight");
171     if (!weight->IsNull()) {
172         std::string weightVal;
173         if (weight->IsNumber()) {
174             weightVal = std::to_string(weight->ToNumber<int32_t>());
175         } else {
176             ParseJsString(weight, weightVal);
177         }
178         font.fontWeight = ConvertStrToFontWeight(weightVal);
179     }
180 
181     auto family = param->GetProperty("family");
182     if (!family->IsNull() && family->IsString()) {
183         auto familyVal = family->ToString();
184         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
185     }
186 
187     auto style = param->GetProperty("style");
188     if (!style->IsNull() && style->IsNumber()) {
189         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
190         font.fontStyle = styleVal;
191     }
192     SearchModel::GetInstance()->SetPlaceholderFont(font);
193 }
194 
SetTextFont(const JSCallbackInfo & info)195 void JSSearch::SetTextFont(const JSCallbackInfo& info)
196 {
197     auto param = JSRef<JSObject>::Cast(info[0]);
198     Font font;
199     auto fontSize = param->GetProperty("size");
200     if (fontSize->IsNull() || fontSize->IsUndefined()) {
201         font.fontSize = Dimension(-1);
202     } else {
203         Dimension size;
204         if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
205             font.fontSize = Dimension(-1);
206             LOGW("Parse to dimension FP failed.");
207         } else {
208             font.fontSize = size;
209         }
210     }
211 
212     auto weight = param->GetProperty("weight");
213     if (!weight->IsNull()) {
214         std::string weightVal;
215         if (weight->IsNumber()) {
216             weightVal = std::to_string(weight->ToNumber<int32_t>());
217         } else {
218             ParseJsString(weight, weightVal);
219         }
220         font.fontWeight = ConvertStrToFontWeight(weightVal);
221     }
222 
223     auto family = param->GetProperty("family");
224     if (!family->IsNull() && family->IsString()) {
225         auto familyVal = family->ToString();
226         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
227     }
228 
229     auto style = param->GetProperty("style");
230     if (!style->IsNull() && style->IsNumber()) {
231         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
232         font.fontStyle = styleVal;
233     }
234     SearchModel::GetInstance()->SetTextFont(font);
235 }
236 
SetTextAlign(int32_t value)237 void JSSearch::SetTextAlign(int32_t value)
238 {
239     if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
240         SearchModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
241     } else {
242         LOGE("the value is error");
243     }
244 }
245 
JsBorder(const JSCallbackInfo & info)246 void JSSearch::JsBorder(const JSCallbackInfo& info)
247 {
248     if (Container::IsCurrentUseNewPipeline()) {
249         JSViewAbstract::JsBorder(info);
250         return;
251     }
252     if (!info[0]->IsObject()) {
253         LOGE("args is not a object. %s", info[0]->ToString().c_str());
254         return;
255     }
256     RefPtr<Decoration> decoration = nullptr;
257     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
258     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
259     if (!searchComponent) {
260         LOGE("search component error");
261         return;
262     }
263     auto childComponent = searchComponent->GetChild();
264     if (!childComponent) {
265         LOGE("component error");
266         return;
267     }
268     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
269     if (!textFieldComponent) {
270         LOGE("text component error");
271         return;
272     }
273     decoration = textFieldComponent->GetDecoration();
274     JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
275     auto valueWidth = object->GetProperty("width");
276     if (!valueWidth->IsUndefined()) {
277         ParseBorderWidth(valueWidth);
278     }
279     auto valueColor = object->GetProperty("color");
280     if (!valueColor->IsUndefined()) {
281         ParseBorderColor(valueColor);
282     }
283     auto valueRadius = object->GetProperty("radius");
284     if (!valueRadius->IsUndefined()) {
285         ParseBorderRadius(valueRadius);
286     }
287     auto valueStyle = object->GetProperty("style");
288     if (!valueStyle->IsUndefined()) {
289         ParseBorderStyle(valueStyle);
290     }
291     ViewAbstractModelImpl::SwapBackBorder(decoration);
292     textFieldComponent->SetOriginBorder(decoration->GetBorder());
293     info.ReturnSelf();
294 }
295 
JsBorderWidth(const JSCallbackInfo & info)296 void JSSearch::JsBorderWidth(const JSCallbackInfo& info)
297 {
298     if (Container::IsCurrentUseNewPipeline()) {
299         JSViewAbstract::JsBorderWidth(info);
300         return;
301     }
302     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
303         LOGE("args need a string or number or object");
304         return;
305     }
306     RefPtr<Decoration> decoration = nullptr;
307     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
308     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
309     if (!searchComponent) {
310         LOGE("search component error");
311         return;
312     }
313     auto childComponent = searchComponent->GetChild();
314     if (!childComponent) {
315         LOGE("component error");
316         return;
317     }
318     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
319     if (!textFieldComponent) {
320         LOGE("text component error");
321         return;
322     }
323     decoration = textFieldComponent->GetDecoration();
324     JSViewAbstract::ParseBorderWidth(info[0]);
325     ViewAbstractModelImpl::SwapBackBorder(decoration);
326     textFieldComponent->SetOriginBorder(decoration->GetBorder());
327 }
328 
JsBorderColor(const JSCallbackInfo & info)329 void JSSearch::JsBorderColor(const JSCallbackInfo& info)
330 {
331     if (Container::IsCurrentUseNewPipeline()) {
332         JSViewAbstract::JsBorderColor(info);
333         return;
334     }
335     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
336         LOGE("args need a string or number or object");
337         return;
338     }
339     RefPtr<Decoration> decoration = nullptr;
340     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
341     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
342     if (!searchComponent) {
343         LOGE("search component error");
344         return;
345     }
346     auto childComponent = searchComponent->GetChild();
347     if (!childComponent) {
348         LOGE("component error");
349         return;
350     }
351     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
352     if (!textFieldComponent) {
353         LOGE("text component error");
354         return;
355     }
356     decoration = textFieldComponent->GetDecoration();
357     JSViewAbstract::ParseBorderColor(info[0]);
358     ViewAbstractModelImpl::SwapBackBorder(decoration);
359     textFieldComponent->SetOriginBorder(decoration->GetBorder());
360 }
361 
JsBorderStyle(const JSCallbackInfo & info)362 void JSSearch::JsBorderStyle(const JSCallbackInfo& info)
363 {
364     if (Container::IsCurrentUseNewPipeline()) {
365         JSViewAbstract::JsBorderStyle(info);
366         return;
367     }
368     if (!info[0]->IsObject() && !info[0]->IsNumber()) {
369         LOGE("args need a string or number or object");
370         return;
371     }
372     RefPtr<Decoration> decoration = nullptr;
373     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
374     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
375     if (!searchComponent) {
376         LOGE("search component error");
377         return;
378     }
379     auto childComponent = searchComponent->GetChild();
380     if (!childComponent) {
381         LOGE("component error");
382         return;
383     }
384     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
385     if (!textFieldComponent) {
386         LOGE("text component error");
387         return;
388     }
389     decoration = textFieldComponent->GetDecoration();
390     JSViewAbstract::ParseBorderStyle(info[0]);
391     ViewAbstractModelImpl::SwapBackBorder(decoration);
392     textFieldComponent->SetOriginBorder(decoration->GetBorder());
393 }
394 
JsBorderRadius(const JSCallbackInfo & info)395 void JSSearch::JsBorderRadius(const JSCallbackInfo& info)
396 {
397     if (Container::IsCurrentUseNewPipeline()) {
398         JSViewAbstract::JsBorderRadius(info);
399         return;
400     }
401     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
402         LOGE("args need a string or number or object");
403         return;
404     }
405     RefPtr<Decoration> decoration = nullptr;
406     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
407     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
408     if (!searchComponent) {
409         LOGE("search component error");
410         return;
411     }
412     auto childComponent = searchComponent->GetChild();
413     if (!childComponent) {
414         LOGE("component error");
415         return;
416     }
417     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
418     if (!textFieldComponent) {
419         LOGE("text component error");
420         return;
421     }
422     decoration = textFieldComponent->GetDecoration();
423     JSViewAbstract::ParseBorderRadius(info[0]);
424     ViewAbstractModelImpl::SwapBackBorder(decoration);
425     textFieldComponent->SetOriginBorder(decoration->GetBorder());
426 }
427 
OnSubmit(const JSCallbackInfo & info)428 void JSSearch::OnSubmit(const JSCallbackInfo& info)
429 {
430     CHECK_NULL_VOID(info[0]->IsFunction());
431     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
432     SearchModel::GetInstance()->SetOnSubmit(std::move(callback));
433 }
434 
OnChange(const JSCallbackInfo & info)435 void JSSearch::OnChange(const JSCallbackInfo& info)
436 {
437     CHECK_NULL_VOID(info[0]->IsFunction());
438     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
439     SearchModel::GetInstance()->SetOnChange(std::move(callback));
440 }
441 
SetHeight(const JSCallbackInfo & info)442 void JSSearch::SetHeight(const JSCallbackInfo& info)
443 {
444     JSViewAbstract::JsHeight(info);
445     if (info.Length() < 1) {
446         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
447         return;
448     }
449     Dimension value;
450     if (!ParseJsDimensionVp(info[0], value)) {
451         LOGE("The arg is wrong, it is supposed to be a number arguments");
452         return;
453     }
454     if (LessNotEqual(value.Value(), 0.0)) {
455         value.SetValue(0.0);
456     }
457 
458     if (Container::IsCurrentUseNewPipeline()) {
459         NG::ViewAbstract::SetHeight(NG::CalcLength(value));
460         return;
461     }
462 
463     auto stack = ViewStackProcessor::GetInstance();
464     auto searchComponent = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
465     if (!searchComponent) {
466         LOGE("SearchComponent set height failed, SearchComponent is null.");
467         return;
468     }
469     auto childComponent = searchComponent->GetChild();
470     if (!childComponent) {
471         LOGE("component error");
472         return;
473     }
474     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
475     if (!textFieldComponent) {
476         LOGE("text component error");
477         return;
478     }
479     textFieldComponent->SetHeight(value);
480 }
481 
SetOnCopy(const JSCallbackInfo & info)482 void JSSearch::SetOnCopy(const JSCallbackInfo& info)
483 {
484     CHECK_NULL_VOID(info[0]->IsFunction());
485     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
486     SearchModel::GetInstance()->SetOnCopy(std::move(callback));
487 }
488 
SetOnCut(const JSCallbackInfo & info)489 void JSSearch::SetOnCut(const JSCallbackInfo& info)
490 {
491     CHECK_NULL_VOID(info[0]->IsFunction());
492     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
493     SearchModel::GetInstance()->SetOnCut(std::move(callback));
494 }
495 
SetOnPaste(const JSCallbackInfo & info)496 void JSSearch::SetOnPaste(const JSCallbackInfo& info)
497 {
498     CHECK_NULL_VOID(info[0]->IsFunction());
499     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
500     SearchModel::GetInstance()->SetOnPaste(std::move(callback));
501 }
502 
SetCopyOption(const JSCallbackInfo & info)503 void JSSearch::SetCopyOption(const JSCallbackInfo& info)
504 {
505     if (info.Length() == 0) {
506         return;
507     }
508     auto copyOptions = CopyOptions::None;
509     if (info[0]->IsNumber()) {
510         auto emunNumber = info[0]->ToNumber<int>();
511         copyOptions = static_cast<CopyOptions>(emunNumber);
512     }
513     SearchModel::GetInstance()->SetCopyOption(copyOptions);
514 }
515 
JSBind(BindingTarget globalObj)516 void JSSearchController::JSBind(BindingTarget globalObj)
517 {
518     JSClass<JSSearchController>::Declare("SearchController");
519     JSClass<JSSearchController>::Method("caretPosition", &JSSearchController::CaretPosition);
520     JSClass<JSSearchController>::Bind(globalObj, JSSearchController::Constructor, JSSearchController::Destructor);
521 }
522 
Constructor(const JSCallbackInfo & args)523 void JSSearchController::Constructor(const JSCallbackInfo& args)
524 {
525     auto scroller = Referenced::MakeRefPtr<JSSearchController>();
526     scroller->IncRefCount();
527     args.SetReturnValue(Referenced::RawPtr(scroller));
528 }
529 
Destructor(JSSearchController * scroller)530 void JSSearchController::Destructor(JSSearchController* scroller)
531 {
532     if (scroller != nullptr) {
533         scroller->DecRefCount();
534     }
535 }
536 
CaretPosition(int32_t caretPosition)537 void JSSearchController::CaretPosition(int32_t caretPosition)
538 {
539     auto controller = controller_.Upgrade();
540     if (controller) {
541         controller->CaretPosition(caretPosition);
542     }
543 }
544 
545 } // namespace OHOS::Ace::Framework
546