• 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     if (info.Length() < 1 || !info[0]->IsObject()) {
156         return;
157     }
158     auto param = JSRef<JSObject>::Cast(info[0]);
159     Font font;
160     auto fontSize = param->GetProperty("size");
161     if (fontSize->IsNull() || fontSize->IsUndefined()) {
162         font.fontSize = Dimension(-1);
163     } else {
164         Dimension size;
165         if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
166             font.fontSize = Dimension(-1);
167             LOGW("Parse to dimension FP failed.");
168         } else {
169             font.fontSize = size;
170         }
171     }
172 
173     auto weight = param->GetProperty("weight");
174     if (!weight->IsNull()) {
175         std::string weightVal;
176         if (weight->IsNumber()) {
177             weightVal = std::to_string(weight->ToNumber<int32_t>());
178         } else {
179             ParseJsString(weight, weightVal);
180         }
181         font.fontWeight = ConvertStrToFontWeight(weightVal);
182     }
183 
184     auto family = param->GetProperty("family");
185     if (!family->IsNull() && family->IsString()) {
186         auto familyVal = family->ToString();
187         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
188     }
189 
190     auto style = param->GetProperty("style");
191     if (!style->IsNull() && style->IsNumber()) {
192         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
193         font.fontStyle = styleVal;
194     }
195     SearchModel::GetInstance()->SetPlaceholderFont(font);
196 }
197 
SetTextFont(const JSCallbackInfo & info)198 void JSSearch::SetTextFont(const JSCallbackInfo& info)
199 {
200     if (info.Length() < 1 || !info[0]->IsObject()) {
201         return;
202     }
203     auto param = JSRef<JSObject>::Cast(info[0]);
204     Font font;
205     auto fontSize = param->GetProperty("size");
206     if (fontSize->IsNull() || fontSize->IsUndefined()) {
207         font.fontSize = Dimension(-1);
208     } else {
209         Dimension size;
210         if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
211             font.fontSize = Dimension(-1);
212             LOGW("Parse to dimension FP failed.");
213         } else {
214             font.fontSize = size;
215         }
216     }
217 
218     auto weight = param->GetProperty("weight");
219     if (!weight->IsNull()) {
220         std::string weightVal;
221         if (weight->IsNumber()) {
222             weightVal = std::to_string(weight->ToNumber<int32_t>());
223         } else {
224             ParseJsString(weight, weightVal);
225         }
226         font.fontWeight = ConvertStrToFontWeight(weightVal);
227     }
228 
229     auto family = param->GetProperty("family");
230     if (!family->IsNull() && family->IsString()) {
231         auto familyVal = family->ToString();
232         font.fontFamilies = ConvertStrToFontFamilies(familyVal);
233     }
234 
235     auto style = param->GetProperty("style");
236     if (!style->IsNull() && style->IsNumber()) {
237         FontStyle styleVal = static_cast<FontStyle>(style->ToNumber<int32_t>());
238         font.fontStyle = styleVal;
239     }
240     SearchModel::GetInstance()->SetTextFont(font);
241 }
242 
SetTextAlign(int32_t value)243 void JSSearch::SetTextAlign(int32_t value)
244 {
245     if (value >= 0 && value < static_cast<int32_t>(TEXT_ALIGNS.size())) {
246         SearchModel::GetInstance()->SetTextAlign(TEXT_ALIGNS[value]);
247     } else {
248         LOGE("the value is error");
249     }
250 }
251 
JsBorder(const JSCallbackInfo & info)252 void JSSearch::JsBorder(const JSCallbackInfo& info)
253 {
254     if (Container::IsCurrentUseNewPipeline()) {
255         JSViewAbstract::JsBorder(info);
256         return;
257     }
258     if (!info[0]->IsObject()) {
259         LOGE("args is not a object. %s", info[0]->ToString().c_str());
260         return;
261     }
262     RefPtr<Decoration> decoration = nullptr;
263     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
264     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
265     if (!searchComponent) {
266         LOGE("search component error");
267         return;
268     }
269     auto childComponent = searchComponent->GetChild();
270     if (!childComponent) {
271         LOGE("component error");
272         return;
273     }
274     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
275     if (!textFieldComponent) {
276         LOGE("text component error");
277         return;
278     }
279     decoration = textFieldComponent->GetDecoration();
280     JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
281     auto valueWidth = object->GetProperty("width");
282     if (!valueWidth->IsUndefined()) {
283         ParseBorderWidth(valueWidth);
284     }
285     auto valueColor = object->GetProperty("color");
286     if (!valueColor->IsUndefined()) {
287         ParseBorderColor(valueColor);
288     }
289     auto valueRadius = object->GetProperty("radius");
290     if (!valueRadius->IsUndefined()) {
291         ParseBorderRadius(valueRadius);
292     }
293     auto valueStyle = object->GetProperty("style");
294     if (!valueStyle->IsUndefined()) {
295         ParseBorderStyle(valueStyle);
296     }
297     ViewAbstractModelImpl::SwapBackBorder(decoration);
298     textFieldComponent->SetOriginBorder(decoration->GetBorder());
299     info.ReturnSelf();
300 }
301 
JsBorderWidth(const JSCallbackInfo & info)302 void JSSearch::JsBorderWidth(const JSCallbackInfo& info)
303 {
304     if (Container::IsCurrentUseNewPipeline()) {
305         JSViewAbstract::JsBorderWidth(info);
306         return;
307     }
308     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
309         LOGE("args need a string or number or object");
310         return;
311     }
312     RefPtr<Decoration> decoration = nullptr;
313     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
314     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
315     if (!searchComponent) {
316         LOGE("search component error");
317         return;
318     }
319     auto childComponent = searchComponent->GetChild();
320     if (!childComponent) {
321         LOGE("component error");
322         return;
323     }
324     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
325     if (!textFieldComponent) {
326         LOGE("text component error");
327         return;
328     }
329     decoration = textFieldComponent->GetDecoration();
330     JSViewAbstract::ParseBorderWidth(info[0]);
331     ViewAbstractModelImpl::SwapBackBorder(decoration);
332     textFieldComponent->SetOriginBorder(decoration->GetBorder());
333 }
334 
JsBorderColor(const JSCallbackInfo & info)335 void JSSearch::JsBorderColor(const JSCallbackInfo& info)
336 {
337     if (Container::IsCurrentUseNewPipeline()) {
338         JSViewAbstract::JsBorderColor(info);
339         return;
340     }
341     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
342         LOGE("args need a string or number or object");
343         return;
344     }
345     RefPtr<Decoration> decoration = nullptr;
346     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
347     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
348     if (!searchComponent) {
349         LOGE("search component error");
350         return;
351     }
352     auto childComponent = searchComponent->GetChild();
353     if (!childComponent) {
354         LOGE("component error");
355         return;
356     }
357     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
358     if (!textFieldComponent) {
359         LOGE("text component error");
360         return;
361     }
362     decoration = textFieldComponent->GetDecoration();
363     JSViewAbstract::ParseBorderColor(info[0]);
364     ViewAbstractModelImpl::SwapBackBorder(decoration);
365     textFieldComponent->SetOriginBorder(decoration->GetBorder());
366 }
367 
JsBorderStyle(const JSCallbackInfo & info)368 void JSSearch::JsBorderStyle(const JSCallbackInfo& info)
369 {
370     if (Container::IsCurrentUseNewPipeline()) {
371         JSViewAbstract::JsBorderStyle(info);
372         return;
373     }
374     if (!info[0]->IsObject() && !info[0]->IsNumber()) {
375         LOGE("args need a string or number or object");
376         return;
377     }
378     RefPtr<Decoration> decoration = nullptr;
379     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
380     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
381     if (!searchComponent) {
382         LOGE("search component error");
383         return;
384     }
385     auto childComponent = searchComponent->GetChild();
386     if (!childComponent) {
387         LOGE("component error");
388         return;
389     }
390     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
391     if (!textFieldComponent) {
392         LOGE("text component error");
393         return;
394     }
395     decoration = textFieldComponent->GetDecoration();
396     JSViewAbstract::ParseBorderStyle(info[0]);
397     ViewAbstractModelImpl::SwapBackBorder(decoration);
398     textFieldComponent->SetOriginBorder(decoration->GetBorder());
399 }
400 
JsBorderRadius(const JSCallbackInfo & info)401 void JSSearch::JsBorderRadius(const JSCallbackInfo& info)
402 {
403     if (Container::IsCurrentUseNewPipeline()) {
404         JSViewAbstract::JsBorderRadius(info);
405         return;
406     }
407     if (!info[0]->IsObject() && !info[0]->IsString() && !info[0]->IsNumber()) {
408         LOGE("args need a string or number or object");
409         return;
410     }
411     RefPtr<Decoration> decoration = nullptr;
412     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
413     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
414     if (!searchComponent) {
415         LOGE("search component error");
416         return;
417     }
418     auto childComponent = searchComponent->GetChild();
419     if (!childComponent) {
420         LOGE("component error");
421         return;
422     }
423     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
424     if (!textFieldComponent) {
425         LOGE("text component error");
426         return;
427     }
428     decoration = textFieldComponent->GetDecoration();
429     JSViewAbstract::ParseBorderRadius(info[0]);
430     ViewAbstractModelImpl::SwapBackBorder(decoration);
431     textFieldComponent->SetOriginBorder(decoration->GetBorder());
432 }
433 
OnSubmit(const JSCallbackInfo & info)434 void JSSearch::OnSubmit(const JSCallbackInfo& info)
435 {
436     CHECK_NULL_VOID(info[0]->IsFunction());
437     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
438     SearchModel::GetInstance()->SetOnSubmit(std::move(callback));
439 }
440 
OnChange(const JSCallbackInfo & info)441 void JSSearch::OnChange(const JSCallbackInfo& info)
442 {
443     CHECK_NULL_VOID(info[0]->IsFunction());
444     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
445     SearchModel::GetInstance()->SetOnChange(std::move(callback));
446 }
447 
SetHeight(const JSCallbackInfo & info)448 void JSSearch::SetHeight(const JSCallbackInfo& info)
449 {
450     JSViewAbstract::JsHeight(info);
451     if (info.Length() < 1) {
452         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
453         return;
454     }
455     Dimension value;
456     if (!ParseJsDimensionVp(info[0], value)) {
457         LOGE("The arg is wrong, it is supposed to be a number arguments");
458         return;
459     }
460     if (LessNotEqual(value.Value(), 0.0)) {
461         value.SetValue(0.0);
462     }
463 
464     if (Container::IsCurrentUseNewPipeline()) {
465         NG::ViewAbstract::SetHeight(NG::CalcLength(value));
466         return;
467     }
468 
469     auto stack = ViewStackProcessor::GetInstance();
470     auto searchComponent = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
471     if (!searchComponent) {
472         LOGE("SearchComponent set height failed, SearchComponent is null.");
473         return;
474     }
475     auto childComponent = searchComponent->GetChild();
476     if (!childComponent) {
477         LOGE("component error");
478         return;
479     }
480     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
481     if (!textFieldComponent) {
482         LOGE("text component error");
483         return;
484     }
485     textFieldComponent->SetHeight(value);
486 }
487 
SetOnCopy(const JSCallbackInfo & info)488 void JSSearch::SetOnCopy(const JSCallbackInfo& info)
489 {
490     CHECK_NULL_VOID(info[0]->IsFunction());
491     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
492     SearchModel::GetInstance()->SetOnCopy(std::move(callback));
493 }
494 
SetOnCut(const JSCallbackInfo & info)495 void JSSearch::SetOnCut(const JSCallbackInfo& info)
496 {
497     CHECK_NULL_VOID(info[0]->IsFunction());
498     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
499     SearchModel::GetInstance()->SetOnCut(std::move(callback));
500 }
501 
SetOnPaste(const JSCallbackInfo & info)502 void JSSearch::SetOnPaste(const JSCallbackInfo& info)
503 {
504     CHECK_NULL_VOID(info[0]->IsFunction());
505     JsEventCallback<void(const std::string&)> callback(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0]));
506     SearchModel::GetInstance()->SetOnPaste(std::move(callback));
507 }
508 
SetCopyOption(const JSCallbackInfo & info)509 void JSSearch::SetCopyOption(const JSCallbackInfo& info)
510 {
511     if (info.Length() == 0) {
512         return;
513     }
514     auto copyOptions = CopyOptions::None;
515     if (info[0]->IsNumber()) {
516         auto emunNumber = info[0]->ToNumber<int>();
517         copyOptions = static_cast<CopyOptions>(emunNumber);
518     }
519     SearchModel::GetInstance()->SetCopyOption(copyOptions);
520 }
521 
JSBind(BindingTarget globalObj)522 void JSSearchController::JSBind(BindingTarget globalObj)
523 {
524     JSClass<JSSearchController>::Declare("SearchController");
525     JSClass<JSSearchController>::Method("caretPosition", &JSSearchController::CaretPosition);
526     JSClass<JSSearchController>::Bind(globalObj, JSSearchController::Constructor, JSSearchController::Destructor);
527 }
528 
Constructor(const JSCallbackInfo & args)529 void JSSearchController::Constructor(const JSCallbackInfo& args)
530 {
531     auto scroller = Referenced::MakeRefPtr<JSSearchController>();
532     scroller->IncRefCount();
533     args.SetReturnValue(Referenced::RawPtr(scroller));
534 }
535 
Destructor(JSSearchController * scroller)536 void JSSearchController::Destructor(JSSearchController* scroller)
537 {
538     if (scroller != nullptr) {
539         scroller->DecRefCount();
540     }
541 }
542 
CaretPosition(int32_t caretPosition)543 void JSSearchController::CaretPosition(int32_t caretPosition)
544 {
545     auto controller = controller_.Upgrade();
546     if (controller) {
547         controller->CaretPosition(caretPosition);
548     }
549 }
550 
551 } // namespace OHOS::Ace::Framework
552