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