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