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