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
ResetFont(void)227 void ResetFont(void)
228 {
229 auto pipeline = PipelineBase::GetCurrentContext();
230 CHECK_NULL_VOID(pipeline);
231 auto selectTheme = pipeline->GetTheme<SelectTheme>();
232 CHECK_NULL_VOID(selectTheme);
233 auto textTheme = pipeline->GetTheme<TextTheme>();
234 CHECK_NULL_VOID(textTheme);
235 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
236 SelectModel::GetInstance()->SetFontSize(selectTheme->GetFontSize());
237 } else {
238 auto controlSize = SelectModel::GetInstance()->GetControlSize();
239 SelectModel::GetInstance()->SetFontSize(selectTheme->GetFontSize(controlSize));
240 }
241 SelectModel::GetInstance()->SetFontWeight(FontWeight::MEDIUM);
242 SelectModel::GetInstance()->SetFontFamily(textTheme->GetTextStyle().GetFontFamilies());
243 SelectModel::GetInstance()->SetItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
244 return;
245 }
246
Font(const JSCallbackInfo & info)247 void JSSelect::Font(const JSCallbackInfo& info)
248 {
249 if (info[0]->IsNull() || info[0]->IsUndefined()) {
250 ResetFont(SelectFontType::SELECT);
251 return;
252 }
253 if (!info[0]->IsObject()) {
254 return;
255 }
256 auto param = JSRef<JSObject>::Cast(info[0]);
257 ParseFontSize(param->GetProperty("size"), SelectFontType::SELECT);
258 ParseFontWeight(param->GetProperty("weight"), SelectFontType::SELECT);
259 ParseFontFamily(param->GetProperty("family"), SelectFontType::SELECT);
260 ParseFontStyle(param->GetProperty("style"), SelectFontType::SELECT);
261 }
262
ParseFontSize(const JSRef<JSVal> & jsValue,SelectFontType type)263 void JSSelect::ParseFontSize(const JSRef<JSVal>& jsValue, SelectFontType type)
264 {
265 CalcDimension fontSize;
266 if (!ParseJsDimensionFp(jsValue, fontSize)) {
267 ResetFontSize(type);
268 return;
269 }
270 if (type == SelectFontType::SELECT) {
271 SelectModel::GetInstance()->SetFontSize(fontSize);
272 } else if (type == SelectFontType::OPTION) {
273 SelectModel::GetInstance()->SetOptionFontSize(fontSize);
274 } else if (type == SelectFontType::SELECTED_OPTION) {
275 SelectModel::GetInstance()->SetSelectedOptionFontSize(fontSize);
276 }
277 }
278
ParseFontWeight(const JSRef<JSVal> & jsValue,SelectFontType type)279 void JSSelect::ParseFontWeight(const JSRef<JSVal>& jsValue, SelectFontType type)
280 {
281 std::string weight;
282 if (jsValue->IsNumber()) {
283 weight = std::to_string(jsValue->ToNumber<int32_t>());
284 } else {
285 ParseJsString(jsValue, weight);
286 }
287 if (type == SelectFontType::SELECT) {
288 SelectModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(weight, FontWeight::MEDIUM));
289 } else if (type == SelectFontType::OPTION) {
290 SelectModel::GetInstance()->SetOptionFontWeight(ConvertStrToFontWeight(weight, FontWeight::REGULAR));
291 } else if (type == SelectFontType::SELECTED_OPTION) {
292 SelectModel::GetInstance()->SetSelectedOptionFontWeight(ConvertStrToFontWeight(weight, FontWeight::REGULAR));
293 }
294 }
295
ParseFontFamily(const JSRef<JSVal> & jsValue,SelectFontType type)296 void JSSelect::ParseFontFamily(const JSRef<JSVal>& jsValue, SelectFontType type)
297 {
298 if (!jsValue->IsString()) {
299 ResetFontFamily(type);
300 return;
301 }
302 auto family = ConvertStrToFontFamilies(jsValue->ToString());
303 if (type == SelectFontType::SELECT) {
304 SelectModel::GetInstance()->SetFontFamily(family);
305 } else if (type == SelectFontType::OPTION) {
306 SelectModel::GetInstance()->SetOptionFontFamily(family);
307 } else if (type == SelectFontType::SELECTED_OPTION) {
308 SelectModel::GetInstance()->SetSelectedOptionFontFamily(family);
309 }
310 }
311
ParseFontStyle(const JSRef<JSVal> & jsValue,SelectFontType type)312 void JSSelect::ParseFontStyle(const JSRef<JSVal>& jsValue, SelectFontType type)
313 {
314 if (!jsValue->IsNumber()) {
315 ResetFontStyle(type);
316 return;
317 }
318 auto styleVal = static_cast<FontStyle>(jsValue->ToNumber<int32_t>());
319 if (type == SelectFontType::SELECT) {
320 SelectModel::GetInstance()->SetItalicFontStyle(styleVal);
321 } else if (type == SelectFontType::OPTION) {
322 SelectModel::GetInstance()->SetOptionItalicFontStyle(styleVal);
323 } else if (type == SelectFontType::SELECTED_OPTION) {
324 SelectModel::GetInstance()->SetSelectedOptionItalicFontStyle(styleVal);
325 }
326 }
327
ResetFontSize(SelectFontType type)328 void JSSelect::ResetFontSize(SelectFontType type)
329 {
330 auto pipeline = PipelineBase::GetCurrentContext();
331 CHECK_NULL_VOID(pipeline);
332 auto selectTheme = pipeline->GetTheme<SelectTheme>();
333 CHECK_NULL_VOID(selectTheme);
334 if (type == SelectFontType::OPTION) {
335 SelectModel::GetInstance()->SetOptionFontSize(selectTheme->GetMenuFontSize());
336 return;
337 } else if (type == SelectFontType::SELECTED_OPTION) {
338 SelectModel::GetInstance()->SetSelectedOptionFontSize(selectTheme->GetMenuFontSize());
339 return;
340 }
341 SelectModel::GetInstance()->SetFontSize(selectTheme->GetFontSize());
342 }
343
ResetFontWeight(SelectFontType type)344 void JSSelect::ResetFontWeight(SelectFontType type)
345 {
346 if (type == SelectFontType::SELECT) {
347 SelectModel::GetInstance()->SetFontWeight(FontWeight::MEDIUM);
348 } else if (type == SelectFontType::OPTION) {
349 SelectModel::GetInstance()->SetOptionFontWeight(FontWeight::REGULAR);
350 } else if (type == SelectFontType::SELECTED_OPTION) {
351 SelectModel::GetInstance()->SetSelectedOptionFontWeight(FontWeight::REGULAR);
352 }
353 }
354
ResetFontFamily(SelectFontType type)355 void JSSelect::ResetFontFamily(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()->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 pipeline = PipelineBase::GetCurrentContext();
373 CHECK_NULL_VOID(pipeline);
374 auto textTheme = pipeline->GetTheme<TextTheme>();
375 CHECK_NULL_VOID(textTheme);
376 if (type == SelectFontType::SELECT) {
377 SelectModel::GetInstance()->SetItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
378 } else if (type == SelectFontType::OPTION) {
379 SelectModel::GetInstance()->SetOptionItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
380 } else if (type == SelectFontType::SELECTED_OPTION) {
381 SelectModel::GetInstance()->SetSelectedOptionItalicFontStyle(textTheme->GetTextStyle().GetFontStyle());
382 }
383 }
384
ResetFont(SelectFontType type)385 void JSSelect::ResetFont(SelectFontType type)
386 {
387 ResetFontSize(type);
388 ResetFontWeight(type);
389 ResetFontFamily(type);
390 ResetFontStyle(type);
391 }
392
FontColor(const JSCallbackInfo & info)393 void JSSelect::FontColor(const JSCallbackInfo& info)
394 {
395 if (info.Length() < 1) {
396 return;
397 }
398
399 Color textColor;
400 if (!ParseJsColor(info[0], textColor)) {
401 if (info[0]->IsNull() || info[0]->IsUndefined()) {
402 auto pipeline = PipelineBase::GetCurrentContext();
403 CHECK_NULL_VOID(pipeline);
404 auto theme = pipeline->GetTheme<SelectTheme>();
405 CHECK_NULL_VOID(theme);
406 textColor = theme->GetFontColor();
407 } else {
408 return;
409 }
410 }
411
412 SelectModel::GetInstance()->SetFontColor(textColor);
413 }
414
SelectedOptionBgColor(const JSCallbackInfo & info)415 void JSSelect::SelectedOptionBgColor(const JSCallbackInfo& info)
416 {
417 if (info.Length() < 1) {
418 return;
419 }
420 Color bgColor;
421 if (!ParseJsColor(info[0], bgColor)) {
422 if (info[0]->IsUndefined() || info[0]->IsNull()) {
423 auto pipeline = PipelineBase::GetCurrentContext();
424 CHECK_NULL_VOID(pipeline);
425 auto theme = pipeline->GetTheme<SelectTheme>();
426 CHECK_NULL_VOID(theme);
427 bgColor = theme->GetSelectedColor();
428 } else {
429 return;
430 }
431 }
432 SelectModel::GetInstance()->SetSelectedOptionBgColor(bgColor);
433 }
434
SelectedOptionFont(const JSCallbackInfo & info)435 void JSSelect::SelectedOptionFont(const JSCallbackInfo& info)
436 {
437 if (info[0]->IsNull() || info[0]->IsUndefined()) {
438 ResetFont(SelectFontType::SELECTED_OPTION);
439 return;
440 }
441 if (!info[0]->IsObject()) {
442 return;
443 }
444 auto param = JSRef<JSObject>::Cast(info[0]);
445 ParseFontSize(param->GetProperty("size"), SelectFontType::SELECTED_OPTION);
446 ParseFontWeight(param->GetProperty("weight"), SelectFontType::SELECTED_OPTION);
447 ParseFontFamily(param->GetProperty("family"), SelectFontType::SELECTED_OPTION);
448 ParseFontStyle(param->GetProperty("style"), SelectFontType::SELECTED_OPTION);
449 }
450
SelectedOptionFontColor(const JSCallbackInfo & info)451 void JSSelect::SelectedOptionFontColor(const JSCallbackInfo& info)
452 {
453 if (info.Length() < 1) {
454 return;
455 }
456 Color textColor;
457 if (!ParseJsColor(info[0], textColor)) {
458 if (info[0]->IsNull() || info[0]->IsUndefined()) {
459 auto pipeline = PipelineBase::GetCurrentContext();
460 CHECK_NULL_VOID(pipeline);
461 auto theme = pipeline->GetTheme<SelectTheme>();
462 CHECK_NULL_VOID(theme);
463 textColor = theme->GetSelectedColorText();
464 } else {
465 return;
466 }
467 }
468 SelectModel::GetInstance()->SetSelectedOptionFontColor(textColor);
469 }
470
OptionBgColor(const JSCallbackInfo & info)471 void JSSelect::OptionBgColor(const JSCallbackInfo& info)
472 {
473 if (info.Length() < 1) {
474 return;
475 }
476 Color bgColor;
477 if (!ParseJsColor(info[0], bgColor)) {
478 if (info[0]->IsUndefined() || info[0]->IsNull()) {
479 auto pipeline = PipelineBase::GetCurrentContext();
480 CHECK_NULL_VOID(pipeline);
481 auto theme = pipeline->GetTheme<SelectTheme>();
482 CHECK_NULL_VOID(theme);
483 bgColor = theme->GetBackgroundColor();
484 } else {
485 return;
486 }
487 }
488
489 SelectModel::GetInstance()->SetOptionBgColor(bgColor);
490 }
491
OptionFont(const JSCallbackInfo & info)492 void JSSelect::OptionFont(const JSCallbackInfo& info)
493 {
494 if (info[0]->IsNull() || info[0]->IsUndefined()) {
495 ResetFont(SelectFontType::OPTION);
496 return;
497 }
498 if (!info[0]->IsObject()) {
499 return;
500 }
501 auto param = JSRef<JSObject>::Cast(info[0]);
502 ParseFontSize(param->GetProperty("size"), SelectFontType::OPTION);
503 ParseFontWeight(param->GetProperty("weight"), SelectFontType::OPTION);
504 ParseFontFamily(param->GetProperty("family"), SelectFontType::OPTION);
505 ParseFontStyle(param->GetProperty("style"), SelectFontType::OPTION);
506 }
507
OptionFontColor(const JSCallbackInfo & info)508 void JSSelect::OptionFontColor(const JSCallbackInfo& info)
509 {
510 if (info.Length() < 1) {
511 return;
512 }
513 Color textColor;
514 if (!ParseJsColor(info[0], textColor)) {
515 if (info[0]->IsUndefined() || info[0]->IsNull()) {
516 auto pipeline = PipelineBase::GetCurrentContext();
517 CHECK_NULL_VOID(pipeline);
518 auto theme = pipeline->GetTheme<SelectTheme>();
519 CHECK_NULL_VOID(theme);
520 textColor = theme->GetMenuFontColor();
521 } else {
522 return;
523 }
524 }
525 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set option font color %{public}s", textColor.ColorToString().c_str());
526 SelectModel::GetInstance()->SetOptionFontColor(textColor);
527 }
528
OnSelected(const JSCallbackInfo & info)529 void JSSelect::OnSelected(const JSCallbackInfo& info)
530 {
531 if (!info[0]->IsFunction()) {
532 return;
533 }
534 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
535 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
536 auto onSelect = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
537 int32_t index, const std::string& value) {
538 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
539 ACE_SCORING_EVENT("Select.onSelect");
540 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "fire change event %{public}d %{public}s", index, value.c_str());
541 PipelineContext::SetCallBackNode(node);
542 JSRef<JSVal> params[2];
543 params[0] = JSRef<JSVal>::Make(ToJSValue(index));
544 params[1] = JSRef<JSVal>::Make(ToJSValue(value));
545 func->ExecuteJS(2, params);
546 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
547 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Select.onSelect");
548 #endif
549 };
550 SelectModel::GetInstance()->SetOnSelect(std::move(onSelect));
551 info.ReturnSelf();
552 }
553
JsSize(const JSCallbackInfo & info)554 void JSSelect::JsSize(const JSCallbackInfo& info)
555 {
556 if (!info[0]->IsObject()) {
557 JSViewAbstract::JsWidth(JSVal::Undefined());
558 JSViewAbstract::JsHeight(JSVal::Undefined());
559 return;
560 }
561 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
562 JSViewAbstract::JsWidth(sizeObj->GetProperty("width"));
563 JSViewAbstract::JsHeight(sizeObj->GetProperty("height"));
564 }
565
JsPadding(const JSCallbackInfo & info)566 void JSSelect::JsPadding(const JSCallbackInfo& info)
567 {
568 if (!info[0]->IsString() && !info[0]->IsNumber() && !info[0]->IsObject()) {
569 return;
570 }
571
572 if (info[0]->IsObject()) {
573 std::optional<CalcDimension> left;
574 std::optional<CalcDimension> right;
575 std::optional<CalcDimension> top;
576 std::optional<CalcDimension> bottom;
577 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
578
579 CalcDimension leftDimen;
580 if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
581 left = leftDimen;
582 }
583 CalcDimension rightDimen;
584 if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
585 right = rightDimen;
586 }
587 CalcDimension topDimen;
588 if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
589 top = topDimen;
590 }
591 CalcDimension bottomDimen;
592 if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
593 bottom = bottomDimen;
594 }
595 if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
596 ViewAbstractModel::GetInstance()->SetPaddings(top, bottom, left, right);
597 return;
598 }
599 }
600
601 CalcDimension value;
602 if (!ParseJsDimensionVp(info[0], value)) {
603 value.Reset();
604 }
605 SelectModel::GetInstance()->SetPadding(value);
606 }
607
SetPaddingLeft(const JSCallbackInfo & info)608 void JSSelect::SetPaddingLeft(const JSCallbackInfo& info)
609 {
610 if (info.Length() < 1) {
611 return;
612 }
613 CalcDimension value;
614 if (!ParseJsDimensionVp(info[0], value)) {
615 return;
616 }
617 SelectModel::GetInstance()->SetPaddingLeft(value);
618 }
619
SetPaddingTop(const JSCallbackInfo & info)620 void JSSelect::SetPaddingTop(const JSCallbackInfo& info)
621 {
622 if (info.Length() < 1) {
623 return;
624 }
625 CalcDimension value;
626 if (!ParseJsDimensionVp(info[0], value)) {
627 return;
628 }
629 SelectModel::GetInstance()->SetPaddingTop(value);
630 }
631
SetPaddingRight(const JSCallbackInfo & info)632 void JSSelect::SetPaddingRight(const JSCallbackInfo& info)
633 {
634 if (info.Length() < 1) {
635 return;
636 }
637 CalcDimension value;
638 if (!ParseJsDimensionVp(info[0], value)) {
639 return;
640 }
641 SelectModel::GetInstance()->SetPaddingRight(value);
642 }
643
SetPaddingBottom(const JSCallbackInfo & info)644 void JSSelect::SetPaddingBottom(const JSCallbackInfo& info)
645 {
646 if (info.Length() < 1) {
647 return;
648 }
649 CalcDimension value;
650 if (!ParseJsDimensionVp(info[0], value)) {
651 return;
652 }
653 SelectModel::GetInstance()->SetPaddingBottom(value);
654 }
655
SetSpace(const JSCallbackInfo & info)656 void JSSelect::SetSpace(const JSCallbackInfo& info)
657 {
658 if (info.Length() < 1) {
659 return;
660 }
661
662 auto selectTheme = GetTheme<SelectTheme>();
663
664 CalcDimension value;
665 if (!ParseJsDimensionVp(info[0], value)) {
666 value = selectTheme->GetContentSpinnerPadding();
667 }
668 if (LessNotEqual(value.Value(), 0.0) || value.Unit() == DimensionUnit::PERCENT) {
669 value = selectTheme->GetContentSpinnerPadding();
670 }
671
672 SelectModel::GetInstance()->SetSpace(value);
673 }
674
SetArrowPosition(const JSCallbackInfo & info)675 void JSSelect::SetArrowPosition(const JSCallbackInfo& info)
676 {
677 if (info.Length() < 1) {
678 return;
679 }
680
681 int32_t direction = 0;
682 if (!ParseJsInt32(info[0], direction)) {
683 direction = 0;
684 }
685
686 if (static_cast<ArrowPosition>(direction) != ArrowPosition::START &&
687 static_cast<ArrowPosition>(direction) != ArrowPosition::END) {
688 direction = 0;
689 }
690
691 SelectModel::GetInstance()->SetArrowPosition(static_cast<ArrowPosition>(direction));
692 }
693
SetMenuAlign(const JSCallbackInfo & info)694 void JSSelect::SetMenuAlign(const JSCallbackInfo& info)
695 {
696 if (info.Length() < 1) {
697 return;
698 }
699
700 MenuAlign menuAlignObj;
701
702 if (!info[0]->IsNumber()) {
703 if (!(info[0]->IsUndefined() || info[0]->IsNull())) {
704 return;
705 }
706 } else {
707 menuAlignObj.alignType = static_cast<MenuAlignType>(info[0]->ToNumber<int32_t>());
708 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set alignType %{public}d", menuAlignObj.alignType);
709 }
710
711 if (info.Length() > 1) {
712 if (info[1]->IsUndefined() || info[1]->IsNull()) {
713 SelectModel::GetInstance()->SetMenuAlign(menuAlignObj);
714 return;
715 }
716 if (!info[1]->IsObject()) {
717 return;
718 }
719 auto offsetObj = JSRef<JSObject>::Cast(info[1]);
720 CalcDimension dx;
721 auto dxValue = offsetObj->GetProperty("dx");
722 ParseJsDimensionVp(dxValue, dx);
723 CalcDimension dy;
724 auto dyValue = offsetObj->GetProperty("dy");
725 ParseJsDimensionVp(dyValue, dy);
726 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set offset dx %{public}f dy %{public}f", dx.Value(), dy.Value());
727 menuAlignObj.offset = DimensionOffset(dx, dy);
728 }
729
730 SelectModel::GetInstance()->SetMenuAlign(menuAlignObj);
731 }
732
IsPercentStr(std::string & percent)733 bool JSSelect::IsPercentStr(std::string& percent)
734 {
735 if (percent.find("%") != std::string::npos) {
736 size_t index = percent.find("%");
737 percent = percent.substr(0, index);
738 return true;
739 }
740 return false;
741 }
742
SetOptionWidth(const JSCallbackInfo & info)743 void JSSelect::SetOptionWidth(const JSCallbackInfo& info)
744 {
745 CalcDimension value;
746 if (info[0]->IsUndefined() || info[0]->IsNull()) {
747 SelectModel::GetInstance()->SetHasOptionWidth(false);
748 SelectModel::GetInstance()->SetOptionWidth(value);
749 return;
750 } else if (info[0]->IsString()) {
751 SelectModel::GetInstance()->SetHasOptionWidth(true);
752 std::string modeFlag = info[0]->ToString();
753 if (modeFlag.compare("fit_content") == 0) {
754 SelectModel::GetInstance()->SetOptionWidthFitTrigger(false);
755 } else if (modeFlag.compare("fit_trigger") == 0) {
756 SelectModel::GetInstance()->SetOptionWidthFitTrigger(true);
757 } else if (IsPercentStr(modeFlag)) {
758 return;
759 } else {
760 ParseJsDimensionVpNG(info[0], value);
761 if (value.IsNegative()) {
762 value.Reset();
763 }
764 SelectModel::GetInstance()->SetOptionWidth(value);
765 }
766 } else {
767 SelectModel::GetInstance()->SetHasOptionWidth(true);
768 ParseJsDimensionVpNG(info[0], value);
769 if (value.IsNegative()) {
770 value.Reset();
771 }
772 SelectModel::GetInstance()->SetOptionWidth(value);
773 }
774 }
775
SetOptionHeight(const JSCallbackInfo & info)776 void JSSelect::SetOptionHeight(const JSCallbackInfo& info)
777 {
778 CalcDimension value;
779 if (info[0]->IsUndefined() || info[0]->IsNull()) {
780 return;
781 } else if (info[0]->IsString()) {
782 std::string modeFlag = info[0]->ToString();
783 if (IsPercentStr(modeFlag)) {
784 return;
785 } else {
786 ParseJsDimensionVpNG(info[0], value);
787 if (value.IsNonPositive()) {
788 return;
789 }
790 SelectModel::GetInstance()->SetOptionHeight(value);
791 }
792 } else {
793 ParseJsDimensionVpNG(info[0], value);
794 if (value.IsNonPositive()) {
795 return;
796 }
797 SelectModel::GetInstance()->SetOptionHeight(value);
798 }
799 }
800
SetOptionWidthFitTrigger(const JSCallbackInfo & info)801 void JSSelect::SetOptionWidthFitTrigger(const JSCallbackInfo& info)
802 {
803 bool isFitTrigger = false;
804 if (info[0]->IsBoolean()) {
805 isFitTrigger = info[0]->ToBoolean();
806 }
807
808 SelectModel::GetInstance()->SetOptionWidthFitTrigger(isFitTrigger);
809 }
810
SetMenuBackgroundColor(const JSCallbackInfo & info)811 void JSSelect::SetMenuBackgroundColor(const JSCallbackInfo& info)
812 {
813 if (info.Length() < 1) {
814 return;
815 }
816 Color menuBackgroundColor;
817 if (!ParseJsColor(info[0], menuBackgroundColor)) {
818 if (info[0]->IsNull() || info[0]->IsUndefined()) {
819 menuBackgroundColor = Color::TRANSPARENT;
820 } else {
821 return;
822 }
823 }
824 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set menu background color %{public}s",
825 menuBackgroundColor.ColorToString().c_str());
826 SelectModel::GetInstance()->SetMenuBackgroundColor(menuBackgroundColor);
827 }
828
SetMenuBackgroundBlurStyle(const JSCallbackInfo & info)829 void JSSelect::SetMenuBackgroundBlurStyle(const JSCallbackInfo& info)
830 {
831 if (info.Length() < 1) {
832 return;
833 }
834
835 BlurStyleOption styleOption;
836 if (info[0]->IsNumber()) {
837 auto blurStyle = info[0]->ToNumber<int32_t>();
838 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
839 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
840 styleOption.blurStyle = static_cast<BlurStyle>(blurStyle);
841 TAG_LOGD(AceLogTag::ACE_SELECT_COMPONENT, "set menu blurStyle %{public}d", blurStyle);
842 SelectModel::GetInstance()->SetMenuBackgroundBlurStyle(styleOption);
843 }
844 }
845 }
846
SetControlSize(const JSCallbackInfo & info)847 void JSSelect::SetControlSize(const JSCallbackInfo& info)
848 {
849 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
850 return;
851 }
852 if (info.Length() < 1) {
853 return;
854 }
855 if (info[0]->IsNumber()) {
856 auto controlSize = static_cast<ControlSize>(info[0]->ToNumber<int32_t>());
857 SelectModel::GetInstance()->SetControlSize(controlSize);
858 } else {
859 LOGE("JSSelect::SetControlSize Is not Number.");
860 }
861 }
862
SetDivider(const JSCallbackInfo & info)863 void JSSelect::SetDivider(const JSCallbackInfo& info)
864 {
865 NG::SelectDivider divider;
866 auto selectTheme = GetTheme<SelectTheme>();
867 Dimension defaultStrokeWidth = 0.0_vp;
868 Dimension defaultMargin = -1.0_vp;
869 Color defaultColor = Color::TRANSPARENT;
870 // Set default strokeWidth and color
871 if (selectTheme) {
872 defaultStrokeWidth = selectTheme->GetDefaultDividerWidth();
873 defaultColor = selectTheme->GetLineColor();
874 divider.strokeWidth = defaultStrokeWidth;
875 divider.color = defaultColor;
876 divider.startMargin = defaultMargin;
877 divider.endMargin = defaultMargin;
878 }
879
880 if (info.Length() >= 1 && info[0]->IsObject()) {
881 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
882
883 Dimension strokeWidth = defaultStrokeWidth;
884 if (ConvertFromJSValueNG(obj->GetProperty("strokeWidth"), strokeWidth) && CheckDividerValue(strokeWidth)) {
885 divider.strokeWidth = strokeWidth;
886 }
887
888 Color color = defaultColor;
889 if (ConvertFromJSValue(obj->GetProperty("color"), color)) {
890 divider.color = color;
891 }
892
893 Dimension startMargin = defaultMargin;
894 if (ConvertFromJSValueNG(obj->GetProperty("startMargin"), startMargin) && CheckDividerValue(startMargin)) {
895 divider.startMargin = startMargin;
896 }
897
898 Dimension endMargin = defaultMargin;
899 if (ConvertFromJSValueNG(obj->GetProperty("endMargin"), endMargin) && CheckDividerValue(endMargin)) {
900 divider.endMargin = endMargin;
901 }
902 } else if (info.Length() >= 1 && info[0]->IsNull()) {
903 divider.strokeWidth = 0.0_vp;
904 }
905 SelectModel::GetInstance()->SetDivider(divider);
906 }
907
CheckDividerValue(const Dimension & dimension)908 bool JSSelect::CheckDividerValue(const Dimension &dimension)
909 {
910 if (dimension.Value() >= 0.0f && dimension.Unit() != DimensionUnit::PERCENT) {
911 return true;
912 }
913 return false;
914 }
915
SetDirection(const std::string & dir)916 void JSSelect::SetDirection(const std::string& dir)
917 {
918 TextDirection direction = TextDirection::AUTO;
919 if (dir == "Ltr") {
920 direction = TextDirection::LTR;
921 } else if (dir == "Rtl") {
922 direction = TextDirection::RTL;
923 } else if (dir == "Auto") {
924 direction = TextDirection::AUTO;
925 } else if (dir == "undefined" && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
926 direction = TextDirection::AUTO;
927 }
928 SelectModel::GetInstance()->SetLayoutDirection(direction);
929 }
930 } // namespace OHOS::Ace::Framework
931