• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_select.h"
17 
18 #include <cstdint>
19 #include <string>
20 #include <vector>
21 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
22 
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_function.h"
27 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
28 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
29 #include "bridge/declarative_frontend/jsview/js_symbol_modifier.h"
30 #include "bridge/declarative_frontend/jsview/models/select_model_impl.h"
31 #include "core/components_ng/base/view_abstract_model.h"
32 #include "core/components_ng/base/view_stack_processor.h"
33 #include "core/components_ng/pattern/select/select_model.h"
34 #include "core/components_ng/pattern/select/select_model_ng.h"
35 #include "core/components_ng/pattern/select/select_properties.h"
36 #include "core/components_v2/inspector/inspector_constants.h"
37 #include "core/pipeline/pipeline_base.h"
38 
39 namespace OHOS::Ace {
40 std::unique_ptr<SelectModel> SelectModel::instance_ = nullptr;
41 std::mutex SelectModel::mutex_;
42 
GetInstance()43 SelectModel* SelectModel::GetInstance()
44 {
45     if (!instance_) {
46         std::lock_guard<std::mutex> lock(mutex_);
47         if (!instance_) {
48 #ifdef NG_BUILD
49             instance_.reset(new NG::SelectModelNG());
50 #else
51             if (Container::IsCurrentUseNewPipeline()) {
52                 instance_.reset(new NG::SelectModelNG());
53             } else {
54                 instance_.reset(new Framework::SelectModelImpl());
55             }
56 #endif
57         }
58     }
59     return instance_.get();
60 }
61 } // namespace OHOS::Ace
62 
63 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)64 void JSSelect::Create(const JSCallbackInfo& info)
65 {
66     if (info.Length() < 0) {
67         return;
68     }
69     if (info[0]->IsArray()) {
70         auto paramArray = JSRef<JSArray>::Cast(info[0]);
71         size_t size = paramArray->Length();
72         std::vector<SelectParam> params(size);
73         for (size_t i = 0; i < size; i++) {
74             std::string value;
75             std::string icon;
76             JSRef<JSVal> indexVal = paramArray->GetValueAt(i);
77             if (!indexVal->IsObject()) {
78                 return;
79             }
80             auto indexObject = JSRef<JSObject>::Cast(indexVal);
81             auto selectValue = indexObject->GetProperty("value");
82             auto selectIcon = indexObject->GetProperty("icon");
83             auto selectSymbolIcon = indexObject->GetProperty("symbolIcon");
84             RefPtr<JSSymbolGlyphModifier> selectSymbol = AceType::MakeRefPtr<JSSymbolGlyphModifier>();
85             selectSymbol->symbol_ = selectSymbolIcon;
86             params[i].symbolModifier = selectSymbol;
87             ParseJsString(selectValue, value);
88             params[i].text = value;
89             if (selectSymbolIcon->IsObject()) {
90                 std::function<void(WeakPtr<NG::FrameNode>)> symbolApply = nullptr;
91                 JSViewAbstract::SetSymbolOptionApply(info, symbolApply, selectSymbolIcon);
92                 params[i].symbolIcon = symbolApply;
93             } else {
94                 ParseJsMedia(selectIcon, icon);
95                 params[i].icon = icon;
96             }
97         }
98         SelectModel::GetInstance()->Create(params);
99     }
100 }
101 
JSBind(BindingTarget globalObj)102 void JSSelect::JSBind(BindingTarget globalObj)
103 {
104     JSClass<JSSelect>::Declare("Select");
105     MethodOptions opt = MethodOptions::NONE;
106     JSClass<JSSelect>::StaticMethod("create", &JSSelect::Create, opt);
107 
108     JSClass<JSSelect>::StaticMethod("selected", &JSSelect::Selected, opt);
109     JSClass<JSSelect>::StaticMethod("value", &JSSelect::Value, opt);
110     JSClass<JSSelect>::StaticMethod("font", &JSSelect::Font, opt);
111     JSClass<JSSelect>::StaticMethod("fontColor", &JSSelect::FontColor, opt);
112     JSClass<JSSelect>::StaticMethod("backgroundColor", &JSSelect::BackgroundColor, opt);
113     JSClass<JSSelect>::StaticMethod("selectedOptionBgColor", &JSSelect::SelectedOptionBgColor, opt);
114     JSClass<JSSelect>::StaticMethod("selectedOptionFont", &JSSelect::SelectedOptionFont, opt);
115     JSClass<JSSelect>::StaticMethod("selectedOptionFontColor", &JSSelect::SelectedOptionFontColor, opt);
116     JSClass<JSSelect>::StaticMethod("optionBgColor", &JSSelect::OptionBgColor, opt);
117     JSClass<JSSelect>::StaticMethod("optionFont", &JSSelect::OptionFont, opt);
118     JSClass<JSSelect>::StaticMethod("optionFontColor", &JSSelect::OptionFontColor, opt);
119     JSClass<JSSelect>::StaticMethod("onSelect", &JSSelect::OnSelected, opt);
120     JSClass<JSSelect>::StaticMethod("space", &JSSelect::SetSpace, opt);
121     JSClass<JSSelect>::StaticMethod("arrowPosition", &JSSelect::SetArrowPosition, opt);
122     JSClass<JSSelect>::StaticMethod("menuAlign", &JSSelect::SetMenuAlign, opt);
123     JSClass<JSSelect>::StaticMethod("avoidance", &JSSelect::SetAvoidance, opt);
124 
125     // API7 onSelected deprecated
126     JSClass<JSSelect>::StaticMethod("onSelected", &JSSelect::OnSelected, opt);
127     JSClass<JSSelect>::StaticMethod("size", &JSSelect::JsSize);
128     JSClass<JSSelect>::StaticMethod("padding", &JSSelect::JsPadding);
129     JSClass<JSSelect>::StaticMethod("paddingTop", &JSSelect::SetPaddingTop, opt);
130     JSClass<JSSelect>::StaticMethod("paddingBottom", &JSSelect::SetPaddingBottom, opt);
131     JSClass<JSSelect>::StaticMethod("paddingLeft", &JSSelect::SetPaddingLeft, opt);
132     JSClass<JSSelect>::StaticMethod("paddingRight", &JSSelect::SetPaddingRight, opt);
133     JSClass<JSSelect>::StaticMethod("optionWidth", &JSSelect::SetOptionWidth, opt);
134     JSClass<JSSelect>::StaticMethod("optionHeight", &JSSelect::SetOptionHeight, opt);
135     JSClass<JSSelect>::StaticMethod("optionWidthFitTrigger", &JSSelect::SetOptionWidthFitTrigger, opt);
136     JSClass<JSSelect>::StaticMethod("menuBackgroundColor", &JSSelect::SetMenuBackgroundColor, opt);
137     JSClass<JSSelect>::StaticMethod("menuBackgroundBlurStyle", &JSSelect::SetMenuBackgroundBlurStyle, opt);
138     JSClass<JSSelect>::StaticMethod("divider", &JSSelect::SetDivider);
139     JSClass<JSSelect>::StaticMethod("controlSize", &JSSelect::SetControlSize);
140     JSClass<JSSelect>::StaticMethod("direction", &JSSelect::SetDirection, opt);
141     JSClass<JSSelect>::StaticMethod("dividerStyle", &JSSelect::SetDividerStyle);
142 
143     JSClass<JSSelect>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
144     JSClass<JSSelect>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
145     JSClass<JSSelect>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
146     JSClass<JSSelect>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
147     JSClass<JSSelect>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
148     JSClass<JSSelect>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
149     JSClass<JSSelect>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
150     JSClass<JSSelect>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
151     JSClass<JSSelect>::InheritAndBind<JSViewAbstract>(globalObj);
152 }
153 
ParseSelectedObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)154 void ParseSelectedObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
155 {
156     CHECK_NULL_VOID(changeEventVal->IsFunction());
157 
158     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
159     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
160     auto onSelect = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](int32_t index) {
161         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
162         ACE_SCORING_EVENT("Select.SelectChangeEvent");
163         PipelineContext::SetCallBackNode(node);
164         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(index));
165         func->ExecuteJS(1, &newJSVal);
166     };
167     SelectModel::GetInstance()->SetSelectChangeEvent(onSelect);
168 }
169 
Selected(const JSCallbackInfo & info)170 void JSSelect::Selected(const JSCallbackInfo& info)
171 {
172     if (info.Length() < 1 || info.Length() > 2) {
173         return;
174     }
175 
176     int32_t value = 0;
177 
178     bool result = ParseJsInteger<int32_t>(info[0], value);
179 
180     if (value < -1) {
181         value = -1;
182     }
183     JSRef<JSVal> changeEventVal;
184     auto selectedVal = info[0];
185     if (!result && selectedVal->IsObject()) {
186         JSRef<JSObject> obj = JSRef<JSObject>::Cast(selectedVal);
187         selectedVal = obj->GetProperty("value");
188         changeEventVal = obj->GetProperty("$value");
189         ParseJsInteger<int32_t>(selectedVal, value);
190     } else if (info.Length() > 1) {
191         changeEventVal = info[1];
192     }
193 
194     if (changeEventVal->IsFunction()) {
195         ParseSelectedObject(info, changeEventVal);
196     }
197     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set selected index %{public}d", value);
198     SelectModel::GetInstance()->SetSelected(value);
199 }
200 
ParseValueObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)201 void ParseValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
202 {
203     CHECK_NULL_VOID(changeEventVal->IsFunction());
204 
205     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
206     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
207     auto onSelect = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
208                         const std::string& value) {
209         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
210         ACE_SCORING_EVENT("Select.ValueChangeEvent");
211         PipelineContext::SetCallBackNode(node);
212         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
213         func->ExecuteJS(1, &newJSVal);
214     };
215     SelectModel::GetInstance()->SetValueChangeEvent(onSelect);
216 }
217 
Value(const JSCallbackInfo & info)218 void JSSelect::Value(const JSCallbackInfo& info)
219 {
220     if (info.Length() < 1 || info.Length() > 2) {
221         return;
222     }
223 
224     std::string value;
225 
226     bool result = ParseJsString(info[0], value);
227 
228     JSRef<JSVal> changeEventVal;
229     auto selectedVal = info[0];
230     if (!result && selectedVal->IsObject()) {
231         JSRef<JSObject> obj = JSRef<JSObject>::Cast(selectedVal);
232         selectedVal = obj->GetProperty("value");
233         changeEventVal = obj->GetProperty("$value");
234         ParseJsString(selectedVal, value);
235     } else if (info.Length() > 1) {
236         changeEventVal = info[1];
237     }
238 
239     if (changeEventVal->IsFunction()) {
240         ParseValueObject(info, changeEventVal);
241     }
242     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "value set by user");
243     SelectModel::GetInstance()->SetValue(value);
244 }
245 
Font(const JSCallbackInfo & info)246 void JSSelect::Font(const JSCallbackInfo& info)
247 {
248     if (info[0]->IsNull() || info[0]->IsUndefined()) {
249         ResetFont(SelectFontType::SELECT);
250         return;
251     }
252     if (!info[0]->IsObject()) {
253         return;
254     }
255     auto param = JSRef<JSObject>::Cast(info[0]);
256     ParseFontSize(param->GetProperty("size"), SelectFontType::SELECT);
257     ParseFontWeight(param->GetProperty("weight"), SelectFontType::SELECT);
258     ParseFontFamily(param->GetProperty("family"), SelectFontType::SELECT);
259     ParseFontStyle(param->GetProperty("style"), SelectFontType::SELECT);
260 }
261 
ParseFontSize(const JSRef<JSVal> & jsValue,SelectFontType type)262 void JSSelect::ParseFontSize(const JSRef<JSVal>& jsValue, SelectFontType type)
263 {
264     CalcDimension fontSize;
265     if (!ParseJsDimensionFp(jsValue, fontSize)) {
266         ResetFontSize(type);
267         return;
268     }
269     if (type == SelectFontType::SELECT) {
270         SelectModel::GetInstance()->SetFontSize(fontSize);
271     } else if (type == SelectFontType::OPTION) {
272         SelectModel::GetInstance()->SetOptionFontSize(fontSize);
273     } else if (type == SelectFontType::SELECTED_OPTION) {
274         SelectModel::GetInstance()->SetSelectedOptionFontSize(fontSize);
275     }
276 }
277 
ParseFontWeight(const JSRef<JSVal> & jsValue,SelectFontType type)278 void JSSelect::ParseFontWeight(const JSRef<JSVal>& jsValue, SelectFontType type)
279 {
280     std::string weight;
281     if (jsValue->IsNumber()) {
282         weight = std::to_string(jsValue->ToNumber<int32_t>());
283     } else {
284         ParseJsString(jsValue, weight);
285     }
286     if (type == SelectFontType::SELECT) {
287         SelectModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(weight, FontWeight::MEDIUM));
288     } else if (type == SelectFontType::OPTION) {
289         SelectModel::GetInstance()->SetOptionFontWeight(ConvertStrToFontWeight(weight, FontWeight::REGULAR));
290     } else if (type == SelectFontType::SELECTED_OPTION) {
291         SelectModel::GetInstance()->SetSelectedOptionFontWeight(ConvertStrToFontWeight(weight, FontWeight::REGULAR));
292     }
293 }
294 
ParseFontFamily(const JSRef<JSVal> & jsValue,SelectFontType type)295 void JSSelect::ParseFontFamily(const JSRef<JSVal>& jsValue, SelectFontType type)
296 {
297     if (!jsValue->IsString()) {
298         ResetFontFamily(type);
299         return;
300     }
301     auto family = ConvertStrToFontFamilies(jsValue->ToString());
302     if (type == SelectFontType::SELECT) {
303         SelectModel::GetInstance()->SetFontFamily(family);
304     } else if (type == SelectFontType::OPTION) {
305         SelectModel::GetInstance()->SetOptionFontFamily(family);
306     } else if (type == SelectFontType::SELECTED_OPTION) {
307         SelectModel::GetInstance()->SetSelectedOptionFontFamily(family);
308     }
309 }
310 
ParseFontStyle(const JSRef<JSVal> & jsValue,SelectFontType type)311 void JSSelect::ParseFontStyle(const JSRef<JSVal>& jsValue, SelectFontType type)
312 {
313     if (!jsValue->IsNumber()) {
314         ResetFontStyle(type);
315         return;
316     }
317     auto styleVal = static_cast<FontStyle>(jsValue->ToNumber<int32_t>());
318     if (type == SelectFontType::SELECT) {
319         SelectModel::GetInstance()->SetItalicFontStyle(styleVal);
320     } else if (type == SelectFontType::OPTION) {
321         SelectModel::GetInstance()->SetOptionItalicFontStyle(styleVal);
322     } else if (type == SelectFontType::SELECTED_OPTION) {
323         SelectModel::GetInstance()->SetSelectedOptionItalicFontStyle(styleVal);
324     }
325 }
326 
ResetFontSize(SelectFontType type)327 void JSSelect::ResetFontSize(SelectFontType type)
328 {
329     auto selectTheme = GetTheme<SelectTheme>();
330     CHECK_NULL_VOID(selectTheme);
331     if (type == SelectFontType::OPTION) {
332         SelectModel::GetInstance()->SetOptionFontSize(selectTheme->GetMenuFontSize());
333         return;
334     } else if (type == SelectFontType::SELECTED_OPTION) {
335         SelectModel::GetInstance()->SetSelectedOptionFontSize(selectTheme->GetMenuFontSize());
336         return;
337     }
338     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
339         SelectModel::GetInstance()->SetFontSize(selectTheme->GetFontSize());
340     } else {
341         auto controlSize = SelectModel::GetInstance()->GetControlSize();
342         SelectModel::GetInstance()->SetFontSize(selectTheme->GetFontSize(controlSize));
343     }
344 }
345 
ResetFontWeight(SelectFontType type)346 void JSSelect::ResetFontWeight(SelectFontType type)
347 {
348     if (type == SelectFontType::SELECT) {
349         SelectModel::GetInstance()->SetFontWeight(FontWeight::MEDIUM);
350     } else if (type == SelectFontType::OPTION) {
351         SelectModel::GetInstance()->SetOptionFontWeight(FontWeight::REGULAR);
352     } else if (type == SelectFontType::SELECTED_OPTION) {
353         SelectModel::GetInstance()->SetSelectedOptionFontWeight(FontWeight::REGULAR);
354     }
355 }
356 
ResetFontFamily(SelectFontType type)357 void JSSelect::ResetFontFamily(SelectFontType type)
358 {
359     auto textTheme = GetTheme<TextTheme>();
360     CHECK_NULL_VOID(textTheme);
361     if (type == SelectFontType::SELECT) {
362         SelectModel::GetInstance()->SetFontFamily(textTheme->GetTextStyle().GetFontFamilies());
363     } else if (type == SelectFontType::OPTION) {
364         SelectModel::GetInstance()->SetOptionFontFamily(textTheme->GetTextStyle().GetFontFamilies());
365     } else if (type == SelectFontType::SELECTED_OPTION) {
366         SelectModel::GetInstance()->SetSelectedOptionFontFamily(textTheme->GetTextStyle().GetFontFamilies());
367     }
368 }
369 
ResetFontStyle(SelectFontType type)370 void JSSelect::ResetFontStyle(SelectFontType type)
371 {
372     auto textTheme = GetTheme<TextTheme>();
373     CHECK_NULL_VOID(textTheme);
374     if (type == SelectFontType::SELECT) {
375         SelectModel::GetInstance()->SetItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
376     } else if (type == SelectFontType::OPTION) {
377         SelectModel::GetInstance()->SetOptionItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
378     } else if (type == SelectFontType::SELECTED_OPTION) {
379         SelectModel::GetInstance()->SetSelectedOptionItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
380     }
381 }
382 
ResetFont(SelectFontType type)383 void JSSelect::ResetFont(SelectFontType type)
384 {
385     ResetFontSize(type);
386     ResetFontWeight(type);
387     ResetFontFamily(type);
388     ResetFontStyle(type);
389 }
390 
FontColor(const JSCallbackInfo & info)391 void JSSelect::FontColor(const JSCallbackInfo& info)
392 {
393     if (info.Length() < 1) {
394         return;
395     }
396 
397     Color textColor;
398     if (!ParseJsColor(info[0], textColor)) {
399         SelectModel::GetInstance()->ResetFontColor();
400         return;
401     }
402 
403     SelectModel::GetInstance()->SetFontColor(textColor);
404 }
405 
BackgroundColor(const JSCallbackInfo & info)406 void JSSelect::BackgroundColor(const JSCallbackInfo& info)
407 {
408     if (info.Length() < 1) {
409         return;
410     }
411     Color backgroundColor;
412     if (!ParseJsColor(info[0], backgroundColor)) {
413         backgroundColor = Color::TRANSPARENT;
414     }
415 
416     SelectModel::GetInstance()->BackgroundColor(backgroundColor);
417 }
418 
SelectedOptionBgColor(const JSCallbackInfo & info)419 void JSSelect::SelectedOptionBgColor(const JSCallbackInfo& info)
420 {
421     if (info.Length() < 1) {
422         return;
423     }
424     Color bgColor;
425     if (!ParseJsColor(info[0], bgColor)) {
426         if (info[0]->IsUndefined() || info[0]->IsNull()) {
427             auto pipeline = PipelineBase::GetCurrentContext();
428             CHECK_NULL_VOID(pipeline);
429             auto theme = pipeline->GetTheme<SelectTheme>();
430             CHECK_NULL_VOID(theme);
431             bgColor = theme->GetSelectedColor();
432         } else {
433             return;
434         }
435     }
436     SelectModel::GetInstance()->SetSelectedOptionBgColor(bgColor);
437 }
438 
SelectedOptionFont(const JSCallbackInfo & info)439 void JSSelect::SelectedOptionFont(const JSCallbackInfo& info)
440 {
441     if (info[0]->IsNull() || info[0]->IsUndefined()) {
442         ResetFont(SelectFontType::SELECTED_OPTION);
443         return;
444     }
445     if (!info[0]->IsObject()) {
446         return;
447     }
448     auto param = JSRef<JSObject>::Cast(info[0]);
449     ParseFontSize(param->GetProperty("size"), SelectFontType::SELECTED_OPTION);
450     ParseFontWeight(param->GetProperty("weight"), SelectFontType::SELECTED_OPTION);
451     ParseFontFamily(param->GetProperty("family"), SelectFontType::SELECTED_OPTION);
452     ParseFontStyle(param->GetProperty("style"), SelectFontType::SELECTED_OPTION);
453 }
454 
SelectedOptionFontColor(const JSCallbackInfo & info)455 void JSSelect::SelectedOptionFontColor(const JSCallbackInfo& info)
456 {
457     if (info.Length() < 1) {
458         return;
459     }
460     Color textColor;
461     if (!ParseJsColor(info[0], textColor)) {
462         if (info[0]->IsNull() || info[0]->IsUndefined()) {
463             auto pipeline = PipelineBase::GetCurrentContext();
464             CHECK_NULL_VOID(pipeline);
465             auto theme = pipeline->GetTheme<SelectTheme>();
466             CHECK_NULL_VOID(theme);
467             textColor = theme->GetSelectedColorText();
468         } else {
469             return;
470         }
471     }
472     SelectModel::GetInstance()->SetSelectedOptionFontColor(textColor);
473 }
474 
OptionBgColor(const JSCallbackInfo & info)475 void JSSelect::OptionBgColor(const JSCallbackInfo& info)
476 {
477     if (info.Length() < 1) {
478         return;
479     }
480     Color bgColor;
481     if (!ParseJsColor(info[0], bgColor)) {
482         if (info[0]->IsUndefined() || info[0]->IsNull()) {
483             auto pipeline = PipelineBase::GetCurrentContext();
484             CHECK_NULL_VOID(pipeline);
485             auto theme = pipeline->GetTheme<SelectTheme>();
486             CHECK_NULL_VOID(theme);
487             bgColor = theme->GetBackgroundColor();
488         } else {
489             return;
490         }
491     }
492 
493     SelectModel::GetInstance()->SetOptionBgColor(bgColor);
494 }
495 
OptionFont(const JSCallbackInfo & info)496 void JSSelect::OptionFont(const JSCallbackInfo& info)
497 {
498     if (info[0]->IsNull() || info[0]->IsUndefined()) {
499         ResetFont(SelectFontType::OPTION);
500         return;
501     }
502     if (!info[0]->IsObject()) {
503         return;
504     }
505     auto param = JSRef<JSObject>::Cast(info[0]);
506     ParseFontSize(param->GetProperty("size"), SelectFontType::OPTION);
507     ParseFontWeight(param->GetProperty("weight"), SelectFontType::OPTION);
508     ParseFontFamily(param->GetProperty("family"), SelectFontType::OPTION);
509     ParseFontStyle(param->GetProperty("style"), SelectFontType::OPTION);
510 }
511 
OptionFontColor(const JSCallbackInfo & info)512 void JSSelect::OptionFontColor(const JSCallbackInfo& info)
513 {
514     if (info.Length() < 1) {
515         return;
516     }
517     Color textColor;
518     if (!ParseJsColor(info[0], textColor)) {
519         if (info[0]->IsUndefined() || info[0]->IsNull()) {
520             auto pipeline = PipelineBase::GetCurrentContext();
521             CHECK_NULL_VOID(pipeline);
522             auto theme = pipeline->GetTheme<SelectTheme>();
523             CHECK_NULL_VOID(theme);
524             textColor = theme->GetMenuFontColor();
525         } else {
526             return;
527         }
528     }
529     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set option font color %{public}s", textColor.ColorToString().c_str());
530     SelectModel::GetInstance()->SetOptionFontColor(textColor);
531 }
532 
OnSelected(const JSCallbackInfo & info)533 void JSSelect::OnSelected(const JSCallbackInfo& info)
534 {
535     if (!info[0]->IsFunction()) {
536         return;
537     }
538     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
539     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
540     auto onSelect = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
541                         int32_t index, const std::string& value) {
542         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
543         ACE_SCORING_EVENT("Select.onSelect");
544         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "fire change event %{public}d %{public}s", index, value.c_str());
545         PipelineContext::SetCallBackNode(node);
546         JSRef<JSVal> params[2];
547         params[0] = JSRef<JSVal>::Make(ToJSValue(index));
548         params[1] = JSRef<JSVal>::Make(ToJSValue(value));
549         func->ExecuteJS(2, params);
550         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "Select.onSelect");
551     };
552     SelectModel::GetInstance()->SetOnSelect(std::move(onSelect));
553     info.ReturnSelf();
554 }
555 
JsSize(const JSCallbackInfo & info)556 void JSSelect::JsSize(const JSCallbackInfo& info)
557 {
558     if (!info[0]->IsObject()) {
559         JSViewAbstract::JsWidth(JSVal::Undefined());
560         JSViewAbstract::JsHeight(JSVal::Undefined());
561         return;
562     }
563     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
564     JSViewAbstract::JsWidth(sizeObj->GetProperty("width"));
565     JSViewAbstract::JsHeight(sizeObj->GetProperty("height"));
566 }
567 
JsPadding(const JSCallbackInfo & info)568 void JSSelect::JsPadding(const JSCallbackInfo& info)
569 {
570     if (!info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject()) {
571         return;
572     }
573 
574     if (info[0]->IsObject()) {
575         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
576         CommonCalcDimension commonCalcDimension;
577         JSViewAbstract::ParseCommonMarginOrPaddingCorner(paddingObj, commonCalcDimension);
578         if (commonCalcDimension.left.has_value() || commonCalcDimension.right.has_value() ||
579             commonCalcDimension.top.has_value() || commonCalcDimension.bottom.has_value()) {
580             ViewAbstractModel::GetInstance()->SetPaddings(commonCalcDimension.top, commonCalcDimension.bottom,
581                 commonCalcDimension.left, commonCalcDimension.right);
582             return;
583         }
584     }
585 
586     CalcDimension value;
587     if (!ParseJsDimensionVp(info[0], value)) {
588         value.Reset();
589     }
590     SelectModel::GetInstance()->SetPadding(value);
591 }
592 
SetPaddingLeft(const JSCallbackInfo & info)593 void JSSelect::SetPaddingLeft(const JSCallbackInfo& info)
594 {
595     if (info.Length() < 1) {
596         return;
597     }
598     CalcDimension value;
599     if (!ParseJsDimensionVp(info[0], value)) {
600         return;
601     }
602     SelectModel::GetInstance()->SetPaddingLeft(value);
603 }
604 
SetPaddingTop(const JSCallbackInfo & info)605 void JSSelect::SetPaddingTop(const JSCallbackInfo& info)
606 {
607     if (info.Length() < 1) {
608         return;
609     }
610     CalcDimension value;
611     if (!ParseJsDimensionVp(info[0], value)) {
612         return;
613     }
614     SelectModel::GetInstance()->SetPaddingTop(value);
615 }
616 
SetPaddingRight(const JSCallbackInfo & info)617 void JSSelect::SetPaddingRight(const JSCallbackInfo& info)
618 {
619     if (info.Length() < 1) {
620         return;
621     }
622     CalcDimension value;
623     if (!ParseJsDimensionVp(info[0], value)) {
624         return;
625     }
626     SelectModel::GetInstance()->SetPaddingRight(value);
627 }
628 
SetPaddingBottom(const JSCallbackInfo & info)629 void JSSelect::SetPaddingBottom(const JSCallbackInfo& info)
630 {
631     if (info.Length() < 1) {
632         return;
633     }
634     CalcDimension value;
635     if (!ParseJsDimensionVp(info[0], value)) {
636         return;
637     }
638     SelectModel::GetInstance()->SetPaddingBottom(value);
639 }
640 
SetSpace(const JSCallbackInfo & info)641 void JSSelect::SetSpace(const JSCallbackInfo& info)
642 {
643     if (info.Length() < 1) {
644         return;
645     }
646 
647     auto selectTheme = GetTheme<SelectTheme>();
648 
649     CalcDimension value;
650     if (!ParseJsDimensionVp(info[0], value)) {
651         value = selectTheme->GetContentSpinnerPadding();
652     }
653     if (LessNotEqual(value.Value(), 0.0) || value.Unit() == DimensionUnit::PERCENT) {
654         value = selectTheme->GetContentSpinnerPadding();
655     }
656 
657     SelectModel::GetInstance()->SetSpace(value);
658 }
659 
SetArrowPosition(const JSCallbackInfo & info)660 void JSSelect::SetArrowPosition(const JSCallbackInfo& info)
661 {
662     if (info.Length() < 1) {
663         return;
664     }
665 
666     int32_t direction = 0;
667     if (!ParseJsInt32(info[0], direction)) {
668         direction = 0;
669     }
670 
671     if (static_cast<ArrowPosition>(direction) != ArrowPosition::START &&
672         static_cast<ArrowPosition>(direction) != ArrowPosition::END) {
673         direction = 0;
674     }
675 
676     SelectModel::GetInstance()->SetArrowPosition(static_cast<ArrowPosition>(direction));
677 }
678 
SetMenuAlign(const JSCallbackInfo & info)679 void JSSelect::SetMenuAlign(const JSCallbackInfo& info)
680 {
681     if (info.Length() < 1) {
682         return;
683     }
684 
685     MenuAlign menuAlignObj;
686 
687     if (!info[0]->IsNumber()) {
688         if (!(info[0]->IsUndefined() || info[0]->IsNull())) {
689             return;
690         }
691     } else {
692         menuAlignObj.alignType = static_cast<MenuAlignType>(info[0]->ToNumber<int32_t>());
693         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set alignType %{public}d", menuAlignObj.alignType);
694     }
695 
696     if (info.Length() > 1) {
697         if (info[1]->IsUndefined() || info[1]->IsNull()) {
698             SelectModel::GetInstance()->SetMenuAlign(menuAlignObj);
699             return;
700         }
701         if (!info[1]->IsObject()) {
702             return;
703         }
704         auto offsetObj = JSRef<JSObject>::Cast(info[1]);
705         CalcDimension dx;
706         auto dxValue = offsetObj->GetProperty("dx");
707         ParseJsDimensionVp(dxValue, dx);
708         CalcDimension dy;
709         auto dyValue = offsetObj->GetProperty("dy");
710         ParseJsDimensionVp(dyValue, dy);
711         TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set offset dx %{public}f dy %{public}f", dx.Value(), dy.Value());
712         menuAlignObj.offset = DimensionOffset(dx, dy);
713     }
714 
715     SelectModel::GetInstance()->SetMenuAlign(menuAlignObj);
716 }
717 
SetAvoidance(const JSCallbackInfo & info)718 void JSSelect::SetAvoidance(const JSCallbackInfo& info)
719 {
720     if (info.Length() < 1) {
721         return;
722     }
723     if (!info[0]->IsNumber()) {
724         return;
725     }
726     int32_t modeValue = info[0]->ToNumber<int32_t>();
727     Avoidance avoidance;
728     switch (modeValue) {
729         case static_cast<int32_t>(AvoidanceMode::COVER_TARGET):
730             avoidance.mode = AvoidanceMode::COVER_TARGET;
731             break;
732         case static_cast<int32_t>(AvoidanceMode::AVOID_AROUND_TARGET):
733             avoidance.mode = AvoidanceMode::AVOID_AROUND_TARGET;
734             break;
735         default:
736             avoidance.mode = AvoidanceMode::COVER_TARGET;
737     }
738 
739     SelectModel::GetInstance()->SetAvoidance(avoidance);
740 }
741 
IsPercentStr(std::string & percent)742 bool JSSelect::IsPercentStr(std::string& percent)
743 {
744     if (percent.find("%") != std::string::npos) {
745         size_t index = percent.find("%");
746         percent = percent.substr(0, index);
747         return true;
748     }
749     return false;
750 }
751 
SetOptionWidth(const JSCallbackInfo & info)752 void JSSelect::SetOptionWidth(const JSCallbackInfo& info)
753 {
754     CalcDimension value;
755     if (info[0]->IsUndefined() || info[0]->IsNull()) {
756         SelectModel::GetInstance()->SetHasOptionWidth(false);
757         SelectModel::GetInstance()->SetOptionWidth(value);
758         return;
759     } else if (info[0]->IsString()) {
760         SelectModel::GetInstance()->SetHasOptionWidth(true);
761         std::string modeFlag = info[0]->ToString();
762         if (modeFlag.compare("fit_content") == 0) {
763             SelectModel::GetInstance()->SetOptionWidthFitTrigger(false);
764         } else if (modeFlag.compare("fit_trigger") == 0) {
765             SelectModel::GetInstance()->SetOptionWidthFitTrigger(true);
766         } else if (IsPercentStr(modeFlag)) {
767             return;
768         } else {
769             ParseJsDimensionVpNG(info[0], value);
770             if (value.IsNegative()) {
771                 value.Reset();
772             }
773             SelectModel::GetInstance()->SetOptionWidth(value);
774         }
775     } else {
776         SelectModel::GetInstance()->SetHasOptionWidth(true);
777         ParseJsDimensionVpNG(info[0], value);
778         if (value.IsNegative()) {
779             value.Reset();
780         }
781         SelectModel::GetInstance()->SetOptionWidth(value);
782     }
783 }
784 
SetOptionHeight(const JSCallbackInfo & info)785 void JSSelect::SetOptionHeight(const JSCallbackInfo& info)
786 {
787     CalcDimension value;
788     if (info[0]->IsUndefined() || info[0]->IsNull()) {
789         return;
790     } else if (info[0]->IsString()) {
791         std::string modeFlag = info[0]->ToString();
792         if (IsPercentStr(modeFlag)) {
793             return;
794         } else {
795             ParseJsDimensionVpNG(info[0], value);
796             if (value.IsNonPositive()) {
797                 return;
798             }
799             SelectModel::GetInstance()->SetOptionHeight(value);
800         }
801     } else {
802         ParseJsDimensionVpNG(info[0], value);
803         if (value.IsNonPositive()) {
804             return;
805         }
806         SelectModel::GetInstance()->SetOptionHeight(value);
807     }
808 }
809 
SetOptionWidthFitTrigger(const JSCallbackInfo & info)810 void JSSelect::SetOptionWidthFitTrigger(const JSCallbackInfo& info)
811 {
812     bool isFitTrigger = false;
813     if (info[0]->IsBoolean()) {
814         isFitTrigger = info[0]->ToBoolean();
815     }
816 
817     SelectModel::GetInstance()->SetOptionWidthFitTrigger(isFitTrigger);
818 }
819 
SetMenuBackgroundColor(const JSCallbackInfo & info)820 void JSSelect::SetMenuBackgroundColor(const JSCallbackInfo& info)
821 {
822     if (info.Length() < 1) {
823         return;
824     }
825     Color menuBackgroundColor;
826     if (!ParseJsColor(info[0], menuBackgroundColor)) {
827         if (info[0]->IsNull() || info[0]->IsUndefined()) {
828             menuBackgroundColor = Color::TRANSPARENT;
829         } else {
830             return;
831         }
832     }
833     TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set menu background color %{public}s",
834         menuBackgroundColor.ColorToString().c_str());
835     SelectModel::GetInstance()->SetMenuBackgroundColor(menuBackgroundColor);
836 }
837 
SetMenuBackgroundBlurStyle(const JSCallbackInfo & info)838 void JSSelect::SetMenuBackgroundBlurStyle(const JSCallbackInfo& info)
839 {
840     if (info.Length() < 1) {
841         return;
842     }
843 
844     BlurStyleOption styleOption;
845     if (info[0]->IsNumber()) {
846         auto blurStyle = info[0]->ToNumber<int32_t>();
847         if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
848             blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
849             styleOption.blurStyle = static_cast<BlurStyle>(blurStyle);
850             TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set menu blurStyle %{public}d", blurStyle);
851             SelectModel::GetInstance()->SetMenuBackgroundBlurStyle(styleOption);
852         }
853     }
854 }
855 
SetControlSize(const JSCallbackInfo & info)856 void JSSelect::SetControlSize(const JSCallbackInfo& info)
857 {
858     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
859         return;
860     }
861     if (info.Length() < 1) {
862         return;
863     }
864     if (info[0]->IsNumber()) {
865         auto controlSize = static_cast<ControlSize>(info[0]->ToNumber<int32_t>());
866         SelectModel::GetInstance()->SetControlSize(controlSize);
867     } else {
868         LOGE("JSSelect::SetControlSize Is not Number.");
869     }
870 }
871 
SetDivider(const JSCallbackInfo & info)872 void JSSelect::SetDivider(const JSCallbackInfo& info)
873 {
874     NG::SelectDivider divider;
875     auto selectTheme = GetTheme<SelectTheme>();
876     Dimension defaultStrokeWidth = 0.0_vp;
877     Dimension defaultMargin = -1.0_vp;
878     Color defaultColor = Color::TRANSPARENT;
879     // Set default strokeWidth and color
880     if (selectTheme) {
881         defaultStrokeWidth = selectTheme->GetDefaultDividerWidth();
882         defaultColor = selectTheme->GetLineColor();
883         divider.strokeWidth = defaultStrokeWidth;
884         divider.color = defaultColor;
885         divider.startMargin = defaultMargin;
886         divider.endMargin = defaultMargin;
887     }
888 
889     if (info.Length() >= 1 && info[0]->IsObject()) {
890         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
891 
892         Dimension strokeWidth = defaultStrokeWidth;
893         if (ConvertFromJSValueNG(obj->GetProperty("strokeWidth"), strokeWidth) && CheckDividerValue(strokeWidth)) {
894             divider.strokeWidth = strokeWidth;
895         }
896 
897         Color color = defaultColor;
898         if (ConvertFromJSValue(obj->GetProperty("color"), color)) {
899             divider.color = color;
900         }
901 
902         Dimension startMargin = defaultMargin;
903         if (ConvertFromJSValueNG(obj->GetProperty("startMargin"), startMargin) && CheckDividerValue(startMargin)) {
904             divider.startMargin = startMargin;
905         }
906 
907         Dimension endMargin = defaultMargin;
908         if (ConvertFromJSValueNG(obj->GetProperty("endMargin"), endMargin) &&  CheckDividerValue(endMargin)) {
909             divider.endMargin = endMargin;
910         }
911     } else if (info.Length() >= 1 && info[0]->IsNull()) {
912         divider.strokeWidth = 0.0_vp;
913     }
914     SelectModel::GetInstance()->SetDivider(divider);
915 }
916 
SetDividerStyle(const JSCallbackInfo & info)917 void JSSelect::SetDividerStyle(const JSCallbackInfo& info)
918 {
919     NG::SelectDivider divider;
920     Dimension defaultStrokeWidth = 0.0_vp;
921     Dimension defaultMargin = -1.0_vp;
922     Color defaultColor = Color::TRANSPARENT;
923     auto selectTheme = GetTheme<SelectTheme>();
924     if (selectTheme) {
925         defaultStrokeWidth = selectTheme->GetDefaultDividerWidth();
926         defaultColor = selectTheme->GetLineColor();
927         divider.strokeWidth = defaultStrokeWidth;
928         divider.color = defaultColor;
929         divider.startMargin = defaultMargin;
930         divider.endMargin = defaultMargin;
931     }
932     if (info.Length() >= 1 && info[0]->IsObject()) {
933         auto mode = DividerMode::FLOATING_ABOVE_MENU;
934         divider.isDividerStyle = true;
935         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
936         CalcDimension value;
937         if (ParseLengthMetricsToPositiveDimension(obj->GetProperty("strokeWidth"), value) && value.IsNonNegative()) {
938             divider.strokeWidth = value;
939         }
940         if (ParseLengthMetricsToPositiveDimension(obj->GetProperty("startMargin"), value) && value.IsNonNegative()) {
941             divider.startMargin = value;
942         }
943         if (ParseLengthMetricsToPositiveDimension(obj->GetProperty("endMargin"), value) && value.IsNonNegative()) {
944             divider.endMargin = value;
945         }
946         if (!ConvertFromJSValue(obj->GetProperty("color"), divider.color)) {
947             divider.color = defaultColor;
948         }
949         auto modeVal = obj->GetProperty("mode");
950         if (modeVal->IsNumber() && modeVal->ToNumber<int32_t>() == 1) {
951             mode = DividerMode::EMBEDDED_IN_MENU;
952         }
953         SelectModel::GetInstance()->SetDividerStyle(divider, mode);
954     } else {
955         divider.isDividerStyle = false;
956         SelectModel::GetInstance()->SetDivider(divider);
957     }
958 }
959 
CheckDividerValue(const Dimension & dimension)960 bool JSSelect::CheckDividerValue(const Dimension &dimension)
961 {
962     if (dimension.Value() >= 0.0f && dimension.Unit() != DimensionUnit::PERCENT) {
963         return true;
964     }
965     return false;
966 }
967 
SetDirection(const std::string & dir)968 void JSSelect::SetDirection(const std::string& dir)
969 {
970     TextDirection direction = TextDirection::AUTO;
971     if (dir == "Ltr") {
972         direction = TextDirection::LTR;
973     } else if (dir == "Rtl") {
974         direction = TextDirection::RTL;
975     } else if (dir == "Auto") {
976         direction = TextDirection::AUTO;
977     } else if (dir == "undefined" && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
978         direction = TextDirection::AUTO;
979     }
980     SelectModel::GetInstance()->SetLayoutDirection(direction);
981 }
982 } // namespace OHOS::Ace::Framework
983