1 /*
2 * Copyright (c) 2021-2024 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_textpicker.h"
17
18 #include <cstdint>
19 #include <securec.h>
20
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/common/utils/engine_helper.h"
23 #include "bridge/declarative_frontend/engine/functions/js_function.h"
24 #include "bridge/declarative_frontend/jsview/js_datepicker.h"
25 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
26 #include "bridge/declarative_frontend/jsview/js_utils.h"
27 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
28 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
29 #include "bridge/declarative_frontend/jsview/models/textpicker_model_impl.h"
30 #include "bridge/declarative_frontend/view_stack_processor.h"
31 #include "core/components/picker/picker_base_component.h"
32 #include "core/components/picker/picker_theme.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/pattern/text_picker/textpicker_model.h"
35 #include "core/components_ng/pattern/text_picker/textpicker_model_ng.h"
36 #include "core/components_ng/pattern/text_picker/textpicker_properties.h"
37 #include "core/pipeline_ng/pipeline_context.h"
38 #include "core/common/resource/resource_object.h"
39
40 namespace OHOS::Ace {
41 namespace {
42 const DimensionOffset TEXT_PICKER_OFFSET_DEFAULT_TOP = DimensionOffset(0.0_vp, 40.0_vp);
43 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
44 DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
45 DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
46 DialogAlignment::BOTTOM_END };
47 const std::vector<HoverModeAreaType> HOVER_MODE_AREA_TYPE = { HoverModeAreaType::TOP_SCREEN,
48 HoverModeAreaType::BOTTOM_SCREEN };
49 const std::regex DIMENSION_REGEX(R"(^[-+]?\d+(?:\.\d+)?(?:px|vp|fp|lpx)?$)", std::regex::icase);
50 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
51 TextOverflow::MARQUEE };
52 constexpr bool DEFAULT_ENABLE_HAPTIC_FEEDBACK = true;
53 }
54
55 std::unique_ptr<TextPickerModel> TextPickerModel::textPickerInstance_ = nullptr;
56 std::unique_ptr<TextPickerDialogModel> TextPickerDialogModel::textPickerDialogInstance_ = nullptr;
57 std::once_flag TextPickerModel::onceFlag_;
58 std::once_flag TextPickerDialogModel::onceFlag_;
59
GetInstance()60 TextPickerModel* TextPickerModel::GetInstance()
61 {
62 std::call_once(onceFlag_, []() {
63 #ifdef NG_BUILD
64 textPickerInstance_.reset(new NG::TextPickerModelNG());
65 #else
66 if (Container::IsCurrentUseNewPipeline()) {
67 textPickerInstance_.reset(new NG::TextPickerModelNG());
68 } else {
69 textPickerInstance_.reset(new Framework::TextPickerModelImpl());
70 }
71 #endif
72 });
73
74 return textPickerInstance_.get();
75 }
76
GetInstance()77 TextPickerDialogModel* TextPickerDialogModel::GetInstance()
78 {
79 std::call_once(onceFlag_, []() {
80 #ifdef NG_BUILD
81 textPickerDialogInstance_.reset(new NG::TextPickerDialogModelNG());
82 #else
83 if (Container::IsCurrentUseNewPipeline()) {
84 textPickerDialogInstance_.reset(new NG::TextPickerDialogModelNG());
85 } else {
86 textPickerDialogInstance_.reset(new Framework::TextPickerDialogModelImpl());
87 }
88 #endif
89 });
90
91 return textPickerDialogInstance_.get();
92 }
93 } // namespace OHOS::Ace
94
95 namespace OHOS::Ace::Framework {
96 namespace {
ParseFontOfButtonStyle(const JSRef<JSObject> & pickerButtonParamObject,ButtonInfo & buttonInfo)97 void ParseFontOfButtonStyle(const JSRef<JSObject>& pickerButtonParamObject, ButtonInfo& buttonInfo)
98 {
99 CalcDimension fontSize;
100 JSRef<JSVal> sizeProperty = pickerButtonParamObject->GetProperty("fontSize");
101 if (JSViewAbstract::ParseJsDimensionVpNG(sizeProperty, fontSize) && fontSize.Unit() != DimensionUnit::PERCENT &&
102 GreatOrEqual(fontSize.Value(), 0.0)) {
103 if (JSViewAbstract::ParseJsDimensionFp(sizeProperty, fontSize)) {
104 buttonInfo.fontSize = fontSize;
105 }
106 }
107 Color fontColor;
108 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("fontColor"), fontColor)) {
109 buttonInfo.fontColor = fontColor;
110 }
111 auto fontWeight = pickerButtonParamObject->GetProperty("fontWeight");
112 if (fontWeight->IsString() || fontWeight->IsNumber()) {
113 buttonInfo.fontWeight = ConvertStrToFontWeight(fontWeight->ToString(), FontWeight::MEDIUM);
114 }
115 JSRef<JSVal> style = pickerButtonParamObject->GetProperty("fontStyle");
116 if (style->IsNumber()) {
117 auto value = style->ToNumber<int32_t>();
118 if (value >= 0 && value < static_cast<int32_t>(FontStyle::NONE)) {
119 buttonInfo.fontStyle = static_cast<FontStyle>(value);
120 }
121 }
122 JSRef<JSVal> family = pickerButtonParamObject->GetProperty("fontFamily");
123 std::vector<std::string> fontFamilies;
124 if (JSViewAbstract::ParseJsFontFamilies(family, fontFamilies)) {
125 buttonInfo.fontFamily = fontFamilies;
126 }
127 }
128
ParseButtonStyle(const JSRef<JSObject> & pickerButtonParamObject)129 ButtonInfo ParseButtonStyle(const JSRef<JSObject>& pickerButtonParamObject)
130 {
131 ButtonInfo buttonInfo;
132 if (pickerButtonParamObject->GetProperty("type")->IsNumber()) {
133 auto buttonTypeIntValue = pickerButtonParamObject->GetProperty("type")->ToNumber<int32_t>();
134 if (buttonTypeIntValue == static_cast<int32_t>(ButtonType::CAPSULE) ||
135 buttonTypeIntValue == static_cast<int32_t>(ButtonType::CIRCLE) ||
136 buttonTypeIntValue == static_cast<int32_t>(ButtonType::ARC) ||
137 buttonTypeIntValue == static_cast<int32_t>(ButtonType::NORMAL) ||
138 buttonTypeIntValue == static_cast<int32_t>(ButtonType::ROUNDED_RECTANGLE)) {
139 buttonInfo.type = static_cast<ButtonType>(buttonTypeIntValue);
140 }
141 }
142 if (pickerButtonParamObject->GetProperty("style")->IsNumber()) {
143 auto styleModeIntValue = pickerButtonParamObject->GetProperty("style")->ToNumber<int32_t>();
144 if (styleModeIntValue >= static_cast<int32_t>(ButtonStyleMode::NORMAL) &&
145 styleModeIntValue <= static_cast<int32_t>(ButtonStyleMode::TEXT)) {
146 buttonInfo.buttonStyle = static_cast<ButtonStyleMode>(styleModeIntValue);
147 }
148 }
149 if (pickerButtonParamObject->GetProperty("role")->IsNumber()) {
150 auto buttonRoleIntValue = pickerButtonParamObject->GetProperty("role")->ToNumber<int32_t>();
151 if (buttonRoleIntValue >= static_cast<int32_t>(ButtonRole::NORMAL) &&
152 buttonRoleIntValue <= static_cast<int32_t>(ButtonRole::ERROR)) {
153 buttonInfo.role = static_cast<ButtonRole>(buttonRoleIntValue);
154 }
155 }
156 ParseFontOfButtonStyle(pickerButtonParamObject, buttonInfo);
157 Color backgroundColor;
158 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("backgroundColor"), backgroundColor)) {
159 buttonInfo.backgroundColor = backgroundColor;
160 }
161 auto radius = ParseBorderRadiusAttr(pickerButtonParamObject->GetProperty("borderRadius"));
162 if (radius.has_value()) {
163 buttonInfo.borderRadius = radius.value();
164 }
165
166 auto primaryValue = pickerButtonParamObject->GetProperty("primary");
167 if (primaryValue->IsBoolean()) {
168 buttonInfo.isPrimary = primaryValue->ToBoolean();
169 }
170
171 return buttonInfo;
172 }
173
ParseButtonStyles(const JSRef<JSObject> & paramObject)174 std::vector<ButtonInfo> ParseButtonStyles(const JSRef<JSObject>& paramObject)
175 {
176 std::vector<ButtonInfo> buttonInfos;
177 auto acceptButtonStyle = paramObject->GetProperty("acceptButtonStyle");
178 if (acceptButtonStyle->IsObject()) {
179 auto acceptButtonStyleParamObject = JSRef<JSObject>::Cast(acceptButtonStyle);
180 buttonInfos.emplace_back(ParseButtonStyle(acceptButtonStyleParamObject));
181 buttonInfos[0].isAcceptButton = true;
182 } else {
183 ButtonInfo buttonInfo;
184 buttonInfos.emplace_back(buttonInfo);
185 }
186 auto cancelButtonStyle = paramObject->GetProperty("cancelButtonStyle");
187 if (cancelButtonStyle->IsObject()) {
188 auto cancelButtonStyleParamObject = JSRef<JSObject>::Cast(cancelButtonStyle);
189 buttonInfos.emplace_back(ParseButtonStyle(cancelButtonStyleParamObject));
190 }
191
192 return buttonInfos;
193 }
194
CheckDividerValue(const Dimension & dimension)195 bool CheckDividerValue(const Dimension &dimension)
196 {
197 if (dimension.Value() >= 0.0f && dimension.Unit() != DimensionUnit::PERCENT) {
198 return true;
199 }
200 return false;
201 }
202
ParseDivider(JSRef<JSObject> & obj,NG::ItemDivider & divider)203 void ParseDivider(JSRef<JSObject>& obj, NG::ItemDivider& divider)
204 {
205 Dimension defaultStrokeWidth = 0.0_vp;
206 Dimension defaultMargin = 0.0_vp;
207 Color defaultColor = Color::TRANSPARENT;
208
209 Dimension strokeWidth = defaultStrokeWidth;
210 RefPtr<ResourceObject> strokeWidthResObj;
211 if (ConvertFromJSValueNG(obj->GetProperty("strokeWidth"), strokeWidth, strokeWidthResObj) &&
212 CheckDividerValue(strokeWidth)) {
213 divider.strokeWidth = strokeWidth;
214 divider.strokeWidthResObj = strokeWidthResObj;
215 }
216
217 Color color = defaultColor;
218 RefPtr<ResourceObject> colorResObj;
219 if (ConvertFromJSValue(obj->GetProperty("color"), color, colorResObj)) {
220 divider.color = color;
221 divider.colorResObj = colorResObj;
222 divider.isDefaultColor = false;
223 }
224
225 Dimension startMargin = defaultMargin;
226 RefPtr<ResourceObject> startMarginResObj;
227 if (ConvertFromJSValueNG(obj->GetProperty("startMargin"), startMargin, startMarginResObj) &&
228 CheckDividerValue(startMargin)) {
229 divider.startMargin = startMargin;
230 divider.startMarginResObj = startMarginResObj;
231 }
232
233 Dimension endMargin = defaultMargin;
234 RefPtr<ResourceObject> endMarginResObj;
235 if (ConvertFromJSValueNG(obj->GetProperty("endMargin"), endMargin, endMarginResObj) &&
236 CheckDividerValue(endMargin)) {
237 divider.endMargin = endMargin;
238 divider.endMarginResObj = endMarginResObj;
239 }
240 }
241 } // namespace
242
JSBind(BindingTarget globalObj)243 void JSTextPicker::JSBind(BindingTarget globalObj)
244 {
245 JSClass<JSTextPicker>::Declare("TextPicker");
246 MethodOptions opt = MethodOptions::NONE;
247 JSClass<JSTextPicker>::StaticMethod("create", &JSTextPicker::Create, opt);
248 JSClass<JSTextPicker>::StaticMethod("defaultPickerItemHeight", &JSTextPicker::SetDefaultPickerItemHeight);
249 JSClass<JSTextPicker>::StaticMethod("canLoop", &JSTextPicker::SetCanLoop);
250 JSClass<JSTextPicker>::StaticMethod("digitalCrownSensitivity", &JSTextPicker::SetDigitalCrownSensitivity);
251 JSClass<JSTextPicker>::StaticMethod("disappearTextStyle", &JSTextPicker::SetDisappearTextStyle);
252 JSClass<JSTextPicker>::StaticMethod("textStyle", &JSTextPicker::SetTextStyle);
253 JSClass<JSTextPicker>::StaticMethod("selectedTextStyle", &JSTextPicker::SetSelectedTextStyle);
254 JSClass<JSTextPicker>::StaticMethod("selectedIndex", &JSTextPicker::SetSelectedIndex);
255 JSClass<JSTextPicker>::StaticMethod("divider", &JSTextPicker::SetDivider);
256 JSClass<JSTextPicker>::StaticMethod("opacity", &JSTextPicker::JsOpacity);
257 JSClass<JSTextPicker>::StaticMethod("disableTextStyleAnimation", &JSTextPicker::SetDisableTextStyleAnimation);
258 JSClass<JSTextPicker>::StaticMethod("defaultTextStyle", &JSTextPicker::SetDefaultTextStyle);
259
260 JSClass<JSTextPicker>::StaticMethod("onAccept", &JSTextPicker::OnAccept);
261 JSClass<JSTextPicker>::StaticMethod("onCancel", &JSTextPicker::OnCancel);
262 JSClass<JSTextPicker>::StaticMethod("onChange", &JSTextPicker::OnChange);
263 JSClass<JSTextPicker>::StaticMethod("onScrollStop", &JSTextPicker::OnScrollStop);
264 JSClass<JSTextPicker>::StaticMethod("onEnterSelectedArea", &JSTextPicker::OnEnterSelectedArea);
265 JSClass<JSTextPicker>::StaticMethod("backgroundColor", &JSTextPicker::PickerBackgroundColor);
266 JSClass<JSTextPicker>::StaticMethod("gradientHeight", &JSTextPicker::SetGradientHeight);
267 JSClass<JSTextPicker>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
268 JSClass<JSTextPicker>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
269 JSClass<JSTextPicker>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
270 JSClass<JSTextPicker>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
271 JSClass<JSTextPicker>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
272 JSClass<JSTextPicker>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
273 JSClass<JSTextPicker>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
274 JSClass<JSTextPicker>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
275 JSClass<JSTextPicker>::StaticMethod("enableHapticFeedback", &JSTextPicker::SetEnableHapticFeedback);
276 JSClass<JSTextPicker>::StaticMethod("selectedBackgroundStyle", &JSTextPicker::SetSelectedBackgroundStyle);
277 JSClass<JSTextPicker>::InheritAndBind<JSViewAbstract>(globalObj);
278 }
279
SetDisableTextStyleAnimation(const JSCallbackInfo & info)280 void JSTextPicker::SetDisableTextStyleAnimation(const JSCallbackInfo& info)
281 {
282 bool value = false;
283 if (info.Length() >= 1 && info[0]->IsBoolean()) {
284 value = info[0]->ToBoolean();
285 }
286 TextPickerModel::GetInstance()->SetDisableTextStyleAnimation(value);
287 }
288
SetDefaultTextStyle(const JSCallbackInfo & info)289 void JSTextPicker::SetDefaultTextStyle(const JSCallbackInfo& info)
290 {
291 auto theme = GetTheme<TextTheme>();
292 CHECK_NULL_VOID(theme);
293 NG::PickerTextStyle textStyle;
294 if (info.Length() >= 1 && info[0]->IsObject()) {
295 JSTextPickerParser::ParseTextStyle(info[0], textStyle, "defaultTextStyle");
296 }
297 TextPickerModel::GetInstance()->SetDefaultTextStyle(theme, textStyle);
298 }
299
PickerBackgroundColor(const JSCallbackInfo & info)300 void JSTextPicker::PickerBackgroundColor(const JSCallbackInfo& info)
301 {
302 JSViewAbstract::JsBackgroundColor(info);
303
304 if (info.Length() < 1) {
305 return;
306 }
307 Color backgroundColor;
308 if (!ParseJsColor(info[0], backgroundColor)) {
309 return;
310 }
311 TextPickerModel::GetInstance()->SetBackgroundColor(backgroundColor);
312 }
313
JsOpacity(const JSCallbackInfo & info)314 void JSTextPicker::JsOpacity(const JSCallbackInfo& info)
315 {
316 JSViewAbstract::JsOpacity(info);
317 TextPickerModel::GetInstance()->HasUserDefinedOpacity();
318 }
319
ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions & option)320 size_t JSTextPicker::ProcessCascadeOptionDepth(const NG::TextCascadePickerOptions& option)
321 {
322 size_t depth = 1;
323 if (option.children.size() == 0) {
324 return depth;
325 }
326
327 for (auto&& pos : option.children) {
328 size_t tmpDep = 1;
329 tmpDep += ProcessCascadeOptionDepth(pos);
330 if (tmpDep > depth) {
331 depth = tmpDep;
332 }
333 }
334 return depth;
335 }
336
CreateSingle(const RefPtr<PickerTheme> & theme,ParseTextArrayParam & param)337 void JSTextPicker::CreateSingle(const RefPtr<PickerTheme>& theme, ParseTextArrayParam& param)
338 {
339 TextPickerModel::GetInstance()->Create(theme, param.kind);
340 TextPickerModel::GetInstance()->SetRange(param.result);
341 TextPickerModel::GetInstance()->SetSelected(param.selected);
342 TextPickerModel::GetInstance()->SetValue(param.value);
343 TextPickerModel::GetInstance()->SetColumnWidths(param.columnWidths);
344
345 if (SystemProperties::ConfigChangePerform()) {
346 if (param.kind == NG::TEXT) {
347 TextPickerModel::GetInstance()->ParseSingleRangeResourceObj(param.resultResObj, param.valueResObj);
348 } else if (param.kind == NG::ICON || param.kind == (NG::ICON | NG::TEXT)) {
349 TextPickerModel::GetInstance()->ParseSingleIconTextResourceObj(param.result);
350 }
351
352 TextPickerModel::GetInstance()->ParseColumnWidthsResourceObj(param.columnWidthResObjs);
353 }
354 }
355
CreateMulti(const RefPtr<PickerTheme> & theme,const NG::TextCascadePickerOptionsAttr & attr,ParseTextArrayParam & param)356 void JSTextPicker::CreateMulti(const RefPtr<PickerTheme>& theme,
357 const NG::TextCascadePickerOptionsAttr& attr, ParseTextArrayParam& param)
358 {
359 TextPickerModel::GetInstance()->MultiInit(theme);
360 TextPickerModel::GetInstance()->SetValues(param.values);
361 TextPickerModel::GetInstance()->SetSelecteds(param.selecteds);
362 TextPickerModel::GetInstance()->SetIsCascade(attr.isCascade);
363 TextPickerModel::GetInstance()->SetHasSelectAttr(attr.isHasSelectAttr);
364 TextPickerModel::GetInstance()->SetColumns(param.options);
365 TextPickerModel::GetInstance()->SetColumnWidths(param.columnWidths);
366
367 if (SystemProperties::ConfigChangePerform()) {
368 TextPickerModel::GetInstance()->ParseCascadeResourceObj(param.options, param.valueArrResObj);
369 TextPickerModel::GetInstance()->ParseColumnWidthsResourceObj(param.columnWidthResObjs);
370 }
371 }
372
ParseTextPickerValueObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)373 void ParseTextPickerValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
374 {
375 CHECK_NULL_VOID(changeEventVal->IsFunction());
376
377 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
378 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
379 auto onValueChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
380 const std::vector<std::string>& value) {
381 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
382 ACE_SCORING_EVENT("TextPicker.onValueChange");
383 if (value.size() == 1) {
384 JSRef<JSVal> newJSVal = JSRef<JSVal>::Make(ToJSValue(value[0]));
385 PipelineContext::SetCallBackNode(node);
386 func->ExecuteJS(1, &newJSVal);
387 } else {
388 JSRef<JSArray> valueArray = JSRef<JSArray>::New();
389 for (uint32_t i = 0; i < value.size(); i++) {
390 valueArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(value[i])));
391 }
392 JSRef<JSVal> newJSVal = JSRef<JSVal>::Cast(valueArray);
393 PipelineContext::SetCallBackNode(node);
394 func->ExecuteJS(1, &newJSVal);
395 }
396 };
397 TextPickerModel::GetInstance()->SetOnValueChangeEvent(std::move(onValueChange));
398 }
399
ParseTextPickerSelectedObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)400 void ParseTextPickerSelectedObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
401 {
402 CHECK_NULL_VOID(changeEventVal->IsFunction());
403
404 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
405 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
406 auto onSelectedChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
407 const std::vector<double>& index) {
408 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
409 ACE_SCORING_EVENT("TextPicker.onSelectedChange");
410 if (index.size() == 1) {
411 PipelineContext::SetCallBackNode(node);
412 JSRef<JSVal> newJSVal = JSRef<JSVal>::Make(ToJSValue(index[0]));
413 func->ExecuteJS(1, &newJSVal);
414 } else {
415 JSRef<JSArray> indexArray = JSRef<JSArray>::New();
416 for (uint32_t i = 0; i < index.size(); i++) {
417 indexArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(index[i])));
418 }
419 PipelineContext::SetCallBackNode(node);
420 JSRef<JSVal> newJSVal = JSRef<JSVal>::Cast(indexArray);
421 func->ExecuteJS(1, &newJSVal);
422 }
423 };
424 TextPickerModel::GetInstance()->SetOnSelectedChangeEvent(std::move(onSelectedChange));
425 }
426
Create(const JSCallbackInfo & info)427 void JSTextPicker::Create(const JSCallbackInfo& info)
428 {
429 ParseTextArrayParam param;
430 NG::TextCascadePickerOptionsAttr optionsAttr;
431 if (info.Length() >= 1 && info[0]->IsObject()) {
432 auto paramObject = JSRef<JSObject>::Cast(info[0]);
433 bool optionsMultiContentCheckErr = false;
434 bool optionsCascadeContentCheckErr = false;
435 auto isSingleRange = ProcessSingleRangeValue(paramObject, param);
436 TextPickerModel::GetInstance()->SetSingleRange(isSingleRange);
437 if (!isSingleRange) {
438 if (!JSTextPickerParser::ParseMultiTextArray(paramObject, param)) {
439 param.options.clear();
440 optionsMultiContentCheckErr = true;
441 }
442 if (optionsMultiContentCheckErr) {
443 optionsCascadeContentCheckErr =
444 !ProcessCascadeOptions(paramObject, param, optionsAttr);
445 }
446 }
447 if (!isSingleRange && optionsMultiContentCheckErr && optionsCascadeContentCheckErr) {
448 param.result.clear();
449 param.options.clear();
450 auto targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
451 bool firstBuild = targetNode && targetNode->IsFirstBuilding();
452 if (!firstBuild) {
453 return;
454 }
455 }
456 }
457 auto theme = GetTheme<PickerTheme>();
458 CHECK_NULL_VOID(theme);
459 if (!param.result.empty()) {
460 CreateSingle(theme, param);
461 } else {
462 CreateMulti(theme, optionsAttr, param);
463 }
464 TextPickerModel::GetInstance()->SetDefaultAttributes(theme);
465 JSInteractableView::SetFocusable(true);
466 JSInteractableView::SetFocusNode(true);
467 if (param.valueChangeEventVal->IsFunction()) {
468 ParseTextPickerValueObject(info, param.valueChangeEventVal);
469 }
470 if (param.selectedChangeEventVal->IsFunction()) {
471 ParseTextPickerSelectedObject(info, param.selectedChangeEventVal);
472 }
473 }
474
ProcessSingleRangeValue(const JSRef<JSObject> & paramObjec,ParseTextArrayParam & param)475 bool JSTextPicker::ProcessSingleRangeValue(const JSRef<JSObject>& paramObjec, ParseTextArrayParam& param)
476 {
477 bool ret = true;
478 auto getRange = paramObjec->GetProperty("range");
479 if (getRange->IsNull() || getRange->IsUndefined()) {
480 if (TextPickerModel::GetInstance()->GetSingleRange()) {
481 return ret;
482 }
483 return false;
484 }
485 if (!JSTextPickerParser::ParseTextArray(paramObjec, param)) {
486 if (!JSTextPickerParser::ParseIconTextArray(paramObjec, param)) {
487 param.result.clear();
488 ret = false;
489 }
490 }
491 return ret;
492 }
493
ProcessCascadeOptions(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param,NG::TextCascadePickerOptionsAttr & attr)494 bool JSTextPicker::ProcessCascadeOptions(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param,
495 NG::TextCascadePickerOptionsAttr& attr)
496 {
497 auto getRange = paramObject->GetProperty("range");
498 if (getRange->IsNull() || getRange->IsUndefined()) {
499 param.options.clear();
500 return false;
501 }
502 if (!JSTextPickerParser::ParseCascadeTextArray(paramObject, param, attr)) {
503 param.options.clear();
504 return false;
505 } else {
506 JSTextPickerParser::GenerateCascadeOptions(getRange, param.options);
507 uint32_t maxCount = param.options.empty() ? 0 : 1;
508 for (size_t i = 0; i < param.options.size(); i++) {
509 size_t tmp = ProcessCascadeOptionDepth(param.options[i]);
510 if (tmp > maxCount) {
511 maxCount = tmp;
512 }
513 }
514 if (param.selecteds.size() < maxCount) {
515 auto differ = maxCount - param.selecteds.size();
516 for (uint32_t i = 0; i < differ; i++) {
517 param.selecteds.emplace_back(0);
518 }
519 }
520 if (param.values.size() < maxCount) {
521 auto differ = maxCount - param.values.size();
522 for (uint32_t i = 0; i < differ; i++) {
523 param.values.emplace_back("");
524 }
525 }
526 attr.isCascade = true;
527 TextPickerModel::GetInstance()->SetMaxCount(maxCount);
528 if (!JSTextPickerParser::ParseColumnWidths(paramObject, param)) {
529 return false;
530 }
531 }
532 return true;
533 }
534
GenerateCascadeOptionsInternal(const JSRef<JSObject> & jsObj,std::vector<NG::TextCascadePickerOptions> & options)535 bool JSTextPickerParser::GenerateCascadeOptionsInternal(
536 const JSRef<JSObject>& jsObj, std::vector<NG::TextCascadePickerOptions>& options)
537 {
538 NG::TextCascadePickerOptions option;
539 auto text = jsObj->GetProperty("text");
540 std::string textStr = "";
541 if (ParseJsString(text, textStr, option.rangeResultResObj)) {
542 option.rangeResult.emplace_back(textStr);
543 } else {
544 return false;
545 }
546
547 auto children = jsObj->GetProperty("children");
548 if (children->IsArray()) {
549 JSRef<JSArray> arrayChildren = JSRef<JSArray>::Cast(children);
550 if (arrayChildren->Length() > 0) {
551 if (!GenerateCascadeOptions(arrayChildren, option.children)) {
552 return false;
553 }
554 }
555 }
556 options.emplace_back(option);
557 return true;
558 }
559
GenerateCascadeOptions(const JSRef<JSArray> & array,std::vector<NG::TextCascadePickerOptions> & options)560 bool JSTextPickerParser::GenerateCascadeOptions(
561 const JSRef<JSArray>& array, std::vector<NG::TextCascadePickerOptions>& options)
562 {
563 for (size_t i = 0; i < array->Length(); i++) {
564 if (array->GetValueAt(i)->IsObject()) {
565 auto jsObj = JSRef<JSObject>::Cast(array->GetValueAt(i));
566 if (!GenerateCascadeOptionsInternal(jsObj, options)) {
567 return false;
568 }
569 } else {
570 options.clear();
571 return false;
572 }
573 }
574 return true;
575 }
576
ParseMultiTextArrayRangeInternal(const JSRef<JSVal> & value,std::vector<NG::TextCascadePickerOptions> & options)577 bool JSTextPickerParser::ParseMultiTextArrayRangeInternal(
578 const JSRef<JSVal>& value, std::vector<NG::TextCascadePickerOptions>& options)
579 {
580 if (value->IsArray()) {
581 NG::TextCascadePickerOptions option;
582 std::vector<RefPtr<ResourceObject>> resObjVector;
583 if (!ParseJsStrArray(value, option.rangeResult, option.rangeResultResObj, resObjVector)) {
584 return false;
585 } else {
586 options.emplace_back(option);
587 }
588 } else {
589 return false;
590 }
591 return true;
592 }
593
ParseMultiTextArrayRange(const JSRef<JSArray> & jsRangeValue,std::vector<NG::TextCascadePickerOptions> & options)594 bool JSTextPickerParser::ParseMultiTextArrayRange(
595 const JSRef<JSArray>& jsRangeValue, std::vector<NG::TextCascadePickerOptions>& options)
596 {
597 options.clear();
598 if (jsRangeValue->Length() > 0) {
599 for (size_t i = 0; i < jsRangeValue->Length(); i++) {
600 JSRef<JSVal> value = jsRangeValue->GetValueAt(i);
601 if (!ParseMultiTextArrayRangeInternal(value, options)) {
602 return false;
603 }
604 }
605 } else {
606 return false;
607 }
608 return true;
609 }
610
ParseMultiTextArraySelectInternal(const std::vector<NG::TextCascadePickerOptions> & options,const std::vector<std::string> & values,std::vector<uint32_t> & selectedValues)611 void JSTextPickerParser::ParseMultiTextArraySelectInternal(const std::vector<NG::TextCascadePickerOptions>& options,
612 const std::vector<std::string>& values, std::vector<uint32_t>& selectedValues)
613 {
614 uint32_t selectedValue = 0;
615 auto sizeOfValues = values.size();
616 for (uint32_t i = 0; i < options.size(); i++) {
617 if ((sizeOfValues >= 0 && sizeOfValues < i + 1) || values[i].empty()) {
618 selectedValues.emplace_back(0);
619 continue;
620 }
621
622 auto valueIterator = std::find(options[i].rangeResult.begin(), options[i].rangeResult.end(), values[i]);
623 if (valueIterator != options[i].rangeResult.end()) {
624 selectedValue = static_cast<uint32_t>(std::distance(options[i].rangeResult.begin(), valueIterator));
625 selectedValues.emplace_back(selectedValue);
626 } else {
627 selectedValues.emplace_back(0);
628 }
629 }
630 }
631
ParseMultiTextArraySelectArrayInternal(const std::vector<NG::TextCascadePickerOptions> & options,std::vector<uint32_t> & selectedValues)632 void JSTextPickerParser::ParseMultiTextArraySelectArrayInternal(
633 const std::vector<NG::TextCascadePickerOptions>& options, std::vector<uint32_t>& selectedValues)
634 {
635 for (uint32_t i = 0; i < options.size(); i++) {
636 if (selectedValues.size() > 0 && selectedValues.size() < i + 1) {
637 selectedValues.emplace_back(0);
638 } else {
639 if (selectedValues[i] >= options[i].rangeResult.size()) {
640 selectedValues[i] = 0;
641 }
642 }
643 }
644 }
645
ParseMultiTextArraySelect(const JsiRef<JsiValue> & jsSelectedValue,ParseTextArrayParam & param)646 bool JSTextPickerParser::ParseMultiTextArraySelect(const JsiRef<JsiValue>& jsSelectedValue, ParseTextArrayParam& param)
647 {
648 if (jsSelectedValue->IsArray()) {
649 if (!ParseJsIntegerArray(jsSelectedValue, param.selecteds)) {
650 return false;
651 }
652 ParseMultiTextArraySelectArrayInternal(param.options, param.selecteds);
653 } else {
654 uint32_t selectedValue = 0;
655 if (ParseJsInteger(jsSelectedValue, selectedValue)) {
656 if (param.options.size() < 1 || selectedValue >= param.options[0].rangeResult.size()) {
657 selectedValue = 0;
658 }
659 param.selecteds.emplace_back(selectedValue);
660 for (uint32_t i = 1; i < param.options.size(); i++) {
661 param.selecteds.emplace_back(0);
662 }
663 } else {
664 ParseMultiTextArraySelectInternal(param.options, param.values, param.selecteds);
665 }
666 }
667 return true;
668 }
669
ParseMultiColumnWidths(const JsiRef<JsiValue> & jsColumnWidthsValue,ParseTextArrayParam & param)670 bool JSTextPickerParser::ParseMultiColumnWidths(const JsiRef<JsiValue>& jsColumnWidthsValue,
671 ParseTextArrayParam& param)
672 {
673 if (jsColumnWidthsValue->IsArray() &&
674 ParseJsLengthMetricsArray(jsColumnWidthsValue, param.columnWidths, param.columnWidthResObjs)) {
675 return true;
676 }
677 return false;
678 }
679
ParseMultiTextArrayValueInternal(const std::vector<NG::TextCascadePickerOptions> & options,std::vector<std::string> & values)680 void JSTextPickerParser::ParseMultiTextArrayValueInternal(
681 const std::vector<NG::TextCascadePickerOptions>& options, std::vector<std::string>& values)
682 {
683 for (uint32_t i = 0; i < options.size(); i++) {
684 if (values.size() > 0 && values.size() < i + 1) {
685 if (options[i].rangeResult.size() > 0) {
686 values.emplace_back(options[i].rangeResult[0]);
687 } else {
688 values.emplace_back("");
689 }
690 } else if (i < values.size() && !options[i].rangeResult.empty()) {
691 auto valueIterator = std::find(options[i].rangeResult.begin(), options[i].rangeResult.end(), values[i]);
692 if (valueIterator == options[i].rangeResult.end()) {
693 values[i] = options[i].rangeResult.front();
694 }
695 } else if (!options[i].rangeResult.empty()) {
696 values.emplace_back(options[i].rangeResult[0]);
697 } else {
698 values.emplace_back("");
699 }
700 }
701 }
702
ParseMultiTextArrayValueSingleInternal(const std::vector<NG::TextCascadePickerOptions> & options,const std::string & value,std::vector<std::string> & values)703 void JSTextPickerParser::ParseMultiTextArrayValueSingleInternal(
704 const std::vector<NG::TextCascadePickerOptions>& options, const std::string& value,
705 std::vector<std::string>& values)
706 {
707 if (options.size() > 0) {
708 auto valueIterator = std::find(options[0].rangeResult.begin(), options[0].rangeResult.end(), value);
709 if (valueIterator != options[0].rangeResult.end()) {
710 values.emplace_back(value);
711 } else {
712 values.emplace_back(options[0].rangeResult.front());
713 }
714 for (uint32_t i = 1; i < options.size(); i++) {
715 values.emplace_back(options[i].rangeResult.front());
716 }
717 } else {
718 for (uint32_t i = 0; i < options.size(); i++) {
719 values.emplace_back(options[i].rangeResult.front());
720 }
721 }
722 }
723
ParseMultiTextArrayValue(const JsiRef<JsiValue> & jsValue,ParseTextArrayParam & param)724 bool JSTextPickerParser::ParseMultiTextArrayValue(const JsiRef<JsiValue>& jsValue, ParseTextArrayParam& param)
725 {
726 if (jsValue->IsArray()) {
727 if (!ParseJsStrArray(jsValue, param.values)) {
728 return false;
729 }
730 ParseMultiTextArrayValueInternal(param.options, param.values);
731 } else {
732 std::string value;
733 if (ParseJsString(jsValue, value)) {
734 ParseMultiTextArrayValueSingleInternal(param.options, value, param.values);
735 } else {
736 for (uint32_t i = 0; i < param.options.size(); i++) {
737 if (param.options[i].rangeResult.size() > 0) {
738 param.values.emplace_back(param.options[i].rangeResult.front());
739 }
740 }
741 }
742 }
743 return true;
744 }
745
ParseMultiTextArray(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param)746 bool JSTextPickerParser::ParseMultiTextArray(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param)
747 {
748 auto getSelected = paramObject->GetProperty("selected");
749 auto getValue = paramObject->GetProperty("value");
750 auto getRange = paramObject->GetProperty("range");
751 auto getColumnWidths = paramObject->GetProperty("columnWidths");
752 if (getRange->IsNull() || getRange->IsUndefined()) {
753 return false;
754 }
755 if (!getRange->IsArray()) {
756 return false;
757 }
758 JSRef<JSArray> array = JSRef<JSArray>::Cast(getRange);
759 if (!ParseMultiTextArrayRange(array, param.options)) {
760 return false;
761 }
762 if (getValue->IsObject()) {
763 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(getValue);
764 param.valueChangeEventVal = valueObj->GetProperty("changeEvent");
765 if (param.valueChangeEventVal->IsFunction()) {
766 getValue = valueObj->GetProperty("value");
767 }
768 }
769 if (!ParseMultiTextArrayValue(getValue, param)) {
770 return false;
771 }
772 if (getSelected->IsObject()) {
773 JSRef<JSObject> selectedObj = JSRef<JSObject>::Cast(getSelected);
774 param.selectedChangeEventVal = selectedObj->GetProperty("changeEvent");
775 if (param.selectedChangeEventVal->IsFunction()) {
776 getSelected = selectedObj->GetProperty("value");
777 }
778 }
779 if (!ParseMultiTextArraySelect(getSelected, param)) {
780 return false;
781 }
782 if (!getColumnWidths->IsNull() && !getColumnWidths->IsUndefined()) {
783 if (!ParseMultiColumnWidths(getColumnWidths, param)) {
784 return false;
785 }
786 }
787 return true;
788 }
789
ParseInternalArray(const JSRef<JSArray> & jsRangeValue,std::vector<uint32_t> & selectedValues,std::vector<std::string> & values,uint32_t index,bool isHasSelectAttr)790 bool JSTextPickerParser::ParseInternalArray(const JSRef<JSArray>& jsRangeValue, std::vector<uint32_t>& selectedValues,
791 std::vector<std::string>& values, uint32_t index, bool isHasSelectAttr)
792 {
793 std::vector<std::string> resultStr;
794 for (size_t i = 0; i < jsRangeValue->Length(); i++) {
795 if (jsRangeValue->GetValueAt(i)->IsObject()) {
796 auto jsObj = JSRef<JSObject>::Cast(jsRangeValue->GetValueAt(i));
797 auto getText = jsObj->GetProperty("text");
798 std::string textStr = "";
799 if (ParseJsString(getText, textStr)) {
800 resultStr.emplace_back(textStr);
801 } else {
802 return false;
803 }
804 }
805 }
806 if (index + 1 > values.size()) {
807 if (resultStr.size() > 0) {
808 values.emplace_back(resultStr.front());
809 } else {
810 values.emplace_back("");
811 }
812 } else {
813 if (resultStr.size() > 0) {
814 auto valueIterator = std::find(resultStr.begin(), resultStr.end(), values[index]);
815 if (valueIterator == resultStr.end()) {
816 values[index] = resultStr.front();
817 }
818 } else {
819 values[index] = "";
820 }
821 }
822
823 SetSelectedValues(selectedValues, values, index, isHasSelectAttr, resultStr);
824
825 if (!jsRangeValue->GetValueAt(selectedValues[index])->IsObject()) {
826 return true;
827 }
828 auto jsObj = JSRef<JSObject>::Cast(jsRangeValue->GetValueAt(selectedValues[index]));
829 auto getChildren = jsObj->GetProperty("children");
830 if (getChildren->IsArray()) {
831 ParseInternalArray(getChildren, selectedValues, values, index + 1, isHasSelectAttr);
832 }
833 return true;
834 }
835
SetSelectedValues(std::vector<uint32_t> & selectedValues,std::vector<std::string> & values,uint32_t index,bool isHasSelectAttr,std::vector<std::string> & resultStr)836 void JSTextPickerParser::SetSelectedValues(std::vector<uint32_t>& selectedValues, std::vector<std::string>& values,
837 uint32_t index, bool isHasSelectAttr, std::vector<std::string>& resultStr)
838 {
839 if (index + 1 > selectedValues.size()) {
840 selectedValues.emplace_back(0);
841 } else {
842 if (selectedValues[index] >= resultStr.size()) {
843 selectedValues[index] = 0;
844 }
845 }
846
847 if (!isHasSelectAttr && selectedValues[index] == 0 && !values[index].empty()) {
848 auto valueIterator = std::find(resultStr.begin(), resultStr.end(), values[index]);
849 if (valueIterator != resultStr.end()) {
850 auto localDistance = std::distance(resultStr.begin(), valueIterator);
851 selectedValues[index] = localDistance > 0 ? static_cast<uint32_t>(localDistance) : 0;
852 }
853 }
854 }
855
ParseCascadeTextArray(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param,NG::TextCascadePickerOptionsAttr & attr)856 bool JSTextPickerParser::ParseCascadeTextArray(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param,
857 NG::TextCascadePickerOptionsAttr& attr)
858 {
859 std::vector<uint32_t>& selectedValues = param.selecteds;
860 std::vector<std::string>& values = param.values;
861
862 JSRef<JSArray> getRange = paramObject->GetProperty("range");
863 auto getSelected = paramObject->GetProperty("selected");
864 auto getValue = paramObject->GetProperty("value");
865 if (getValue->IsArray()) {
866 RefPtr<ResourceObject> resObj;
867 std::vector<RefPtr<ResourceObject>> resObjVector;
868 if (!ParseJsStrArray(getValue, values, resObj, resObjVector)) {
869 return false;
870 }
871
872 if (resObjVector.size() > 0) {
873 param.valueArrResObj = resObjVector;
874 }
875 } else {
876 std::string value = "";
877 if (!ParseJsString(getValue, value)) {
878 value = "";
879 }
880 values.emplace_back(value);
881 }
882 if (getSelected->IsArray()) {
883 if (!ParseJsIntegerArray(getSelected, selectedValues)) {
884 attr.isHasSelectAttr = false;
885 return false;
886 } else {
887 attr.isHasSelectAttr = true;
888 }
889 } else {
890 uint32_t selectValue = 0;
891 if (!ParseJsInteger(getSelected, selectValue)) {
892 selectValue = 0;
893 attr.isHasSelectAttr = false;
894 } else {
895 attr.isHasSelectAttr = true;
896 }
897 selectedValues.emplace_back(selectValue);
898 }
899 return ParseInternalArray(getRange, selectedValues, values, 0, attr.isHasSelectAttr);
900 }
901
ParseColumnWidths(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param)902 bool JSTextPickerParser::ParseColumnWidths(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param)
903 {
904 auto getColumnWidths = paramObject->GetProperty("columnWidths");
905 if (!getColumnWidths->IsNull() && !getColumnWidths->IsUndefined()) {
906 if (!ParseMultiColumnWidths(getColumnWidths, param)) {
907 return false;
908 }
909 }
910 return true;
911 }
912
ParseTextArray(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param)913 bool JSTextPickerParser::ParseTextArray(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param)
914 {
915 auto getSelected = paramObject->GetProperty("selected");
916 auto getValue = paramObject->GetProperty("value");
917 JSRef<JSArray> getRange = paramObject->GetProperty("range");
918 std::vector<std::string> getRangeVector;
919 if (getRange->Length() > 0) {
920 if (!ParseJsStrArray(getRange, getRangeVector)) {
921 return false;
922 }
923 param.result.clear();
924 for (const auto& text : getRangeVector) {
925 NG::RangeContent content;
926 content.icon_ = "";
927 content.text_ = text;
928 param.result.emplace_back(content);
929 }
930 param.kind = NG::TEXT;
931 if (getValue->IsObject()) {
932 JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(getValue);
933 param.valueChangeEventVal = valueObj->GetProperty("changeEvent");
934 if (param.valueChangeEventVal->IsFunction()) {
935 getValue = valueObj->GetProperty("value");
936 }
937 }
938 if (!ParseJsString(getValue, param.value, param.valueResObj)) {
939 param.value = getRangeVector.front();
940 }
941 if (getSelected->IsObject()) {
942 JSRef<JSObject> selectedObj = JSRef<JSObject>::Cast(getSelected);
943 param.selectedChangeEventVal = selectedObj->GetProperty("changeEvent");
944 if (param.selectedChangeEventVal->IsFunction()) {
945 getSelected = selectedObj->GetProperty("value");
946 }
947 }
948 if (!ParseJsInteger(getSelected, param.selected) && !param.value.empty()) {
949 auto valueIterator = std::find(getRangeVector.begin(), getRangeVector.end(), param.value);
950 if (valueIterator != getRangeVector.end()) {
951 param.selected = static_cast<uint32_t>(std::distance(getRangeVector.begin(), valueIterator));
952 }
953 }
954 if (param.selected >= getRangeVector.size()) {
955 param.selected = 0;
956 }
957 if (!ParseColumnWidths(paramObject, param)) {
958 return false;
959 }
960 }
961 return true;
962 }
963
ParseIconTextArray(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param)964 bool JSTextPickerParser::ParseIconTextArray(const JSRef<JSObject>& paramObject, ParseTextArrayParam& param)
965 {
966 auto getSelected = paramObject->GetProperty("selected");
967 auto getRange = paramObject->GetProperty("range");
968 if (!getRange->IsArray()) {
969 return false;
970 }
971 JSRef<JSArray> array = JSRef<JSArray>::Cast(getRange);
972 param.result.clear();
973 param.kind = 0;
974 for (size_t i = 0; i < array->Length(); i++) {
975 if (!array->GetValueAt(i)->IsObject()) {
976 continue;
977 }
978 auto jsObj = JSRef<JSObject>::Cast(array->GetValueAt(i));
979 auto rangeIcon = jsObj->GetProperty("icon");
980 auto rangeText = jsObj->GetProperty("text");
981 NG::RangeContent content;
982 std::string icon;
983 std::string text;
984 RefPtr<ResourceObject> iconResObj;
985 RefPtr<ResourceObject> textResObj;
986 if (ParseJsMedia(rangeIcon, icon, iconResObj)) {
987 content.icon_ = icon;
988 param.kind |= NG::ICON;
989 content.iconResObj_ = iconResObj;
990 }
991
992 if (ParseJsString(rangeText, text, textResObj)) {
993 content.text_ = text;
994 param.kind |= NG::TEXT;
995 content.textResObj_ = textResObj;
996 }
997 param.result.emplace_back(content);
998 }
999
1000 if (param.kind != NG::ICON && param.kind != (NG::ICON | NG::TEXT)) {
1001 return false;
1002 }
1003
1004 if (!ParseJsInteger(getSelected, param.selected)) {
1005 param.selected = 0;
1006 }
1007
1008 if (!ParseColumnWidths(paramObject, param)) {
1009 return false;
1010 }
1011 return true;
1012 }
1013
IsUserDefinedFontFamily(const std::string & pos)1014 void JSTextPickerParser::IsUserDefinedFontFamily(const std::string& pos)
1015 {
1016 if (pos == "disappearTextStyle") {
1017 TextPickerModel::GetInstance()->HasUserDefinedDisappearFontFamily(true);
1018 } else if (pos == "textStyle") {
1019 TextPickerModel::GetInstance()->HasUserDefinedNormalFontFamily(true);
1020 } else if (pos == "selectedTextStyle") {
1021 TextPickerModel::GetInstance()->HasUserDefinedSelectedFontFamily(true);
1022 }
1023 }
1024
ParseDefaultTextStyle(const JSRef<JSObject> & paramObj,NG::PickerTextStyle & textStyle)1025 void JSTextPickerParser::ParseDefaultTextStyle(const JSRef<JSObject>& paramObj, NG::PickerTextStyle& textStyle)
1026 {
1027 auto minFontSize = paramObj->GetProperty("minFontSize");
1028 auto maxFontSize = paramObj->GetProperty("maxFontSize");
1029
1030 if (!minFontSize->IsNull() && !minFontSize->IsUndefined()) {
1031 CalcDimension minSize;
1032 if (ParseJsDimensionFp(minFontSize, minSize, textStyle.minFontSizeResObj) &&
1033 minSize.Unit() != DimensionUnit::PERCENT) {
1034 textStyle.minFontSize = minSize;
1035 }
1036 }
1037 if (!maxFontSize->IsNull() && !maxFontSize->IsUndefined()) {
1038 CalcDimension maxSize;
1039 if (ParseJsDimensionFp(maxFontSize, maxSize, textStyle.maxFontSizeResObj) &&
1040 maxSize.Unit() != DimensionUnit::PERCENT) {
1041 textStyle.maxFontSize = maxSize;
1042 }
1043 }
1044
1045 auto overflow = paramObj->GetProperty("overflow");
1046 if (!overflow->IsNull() && !overflow->IsUndefined()) {
1047 if (overflow->IsNumber()) {
1048 auto overflowValue = overflow->ToNumber<int32_t>();
1049 if (overflowValue >= 0 && overflowValue < static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
1050 textStyle.textOverflow = TEXT_OVERFLOWS[overflowValue];
1051 }
1052 }
1053 }
1054 }
1055
ParseTextStyleFontSize(const JSRef<JSVal> & fontSize,NG::PickerTextStyle & textStyle)1056 void JSTextPickerParser::ParseTextStyleFontSize(const JSRef<JSVal>& fontSize, NG::PickerTextStyle& textStyle)
1057 {
1058 if (fontSize->IsNull() || fontSize->IsUndefined()) {
1059 textStyle.fontSize = Dimension(-1);
1060 } else {
1061 CalcDimension size;
1062 if (!ParseJsDimensionFp(fontSize, size, textStyle.fontSizeResObj) || size.Unit() == DimensionUnit::PERCENT) {
1063 textStyle.fontSize = Dimension(-1);
1064 } else {
1065 textStyle.fontSize = size;
1066 }
1067 }
1068 }
1069
ParseTextStyle(const JSRef<JSObject> & paramObj,NG::PickerTextStyle & textStyle,const std::string & pos)1070 void JSTextPickerParser::ParseTextStyle(
1071 const JSRef<JSObject>& paramObj, NG::PickerTextStyle& textStyle, const std::string& pos)
1072 {
1073 auto fontColor = paramObj->GetProperty("color");
1074 auto fontOptions = paramObj->GetProperty("font");
1075
1076 Color textColor;
1077 if (ParseJsColor(fontColor, textColor, textStyle.textColorResObj)) {
1078 textStyle.textColor = textColor;
1079 textStyle.textColorSetByUser = true;
1080 }
1081
1082 ParseDefaultTextStyle(paramObj, textStyle);
1083
1084 if (!fontOptions->IsObject()) {
1085 return;
1086 }
1087 JSRef<JSObject> fontObj = JSRef<JSObject>::Cast(fontOptions);
1088 auto fontSize = fontObj->GetProperty("size");
1089 auto fontWeight = fontObj->GetProperty("weight");
1090 auto fontFamily = fontObj->GetProperty("family");
1091 auto fontStyle = fontObj->GetProperty("style");
1092
1093 ParseTextStyleFontSize(fontSize, textStyle);
1094
1095 if (!fontWeight->IsNull() && !fontWeight->IsUndefined()) {
1096 std::string weight;
1097 if (fontWeight->IsNumber()) {
1098 weight = std::to_string(fontWeight->ToNumber<int32_t>());
1099 } else {
1100 ParseJsString(fontWeight, weight);
1101 }
1102 textStyle.fontWeight = ConvertStrToFontWeight(weight);
1103 }
1104
1105 if (!fontFamily->IsNull() && !fontFamily->IsUndefined()) {
1106 std::vector<std::string> families;
1107 if (ParseJsFontFamilies(fontFamily, families, textStyle.fontFamilyResObj)) {
1108 textStyle.fontFamily = families;
1109 IsUserDefinedFontFamily(pos);
1110 }
1111 }
1112
1113 if (fontStyle->IsNumber()) {
1114 auto style = fontStyle->ToNumber<int32_t>();
1115 if (style < 0 || style > 1) {
1116 return;
1117 }
1118 textStyle.fontStyle = static_cast<FontStyle>(style);
1119 }
1120 }
1121
ParsePickerBackgroundStyle(const JSRef<JSObject> & paramObj,NG::PickerBackgroundStyle & bgStyle)1122 void JSTextPickerParser::ParsePickerBackgroundStyle(const JSRef<JSObject>& paramObj, NG::PickerBackgroundStyle& bgStyle)
1123 {
1124 auto color = paramObj->GetProperty("color");
1125 auto borderRadius = paramObj->GetProperty("borderRadius");
1126 if (!color->IsUndefined() && !color->IsNull()) {
1127 Color buttonBgColor;
1128 if (ParseJsColor(color, buttonBgColor, bgStyle.colorResObj)) {
1129 bgStyle.color = buttonBgColor;
1130 bgStyle.textColorSetByUser = true;
1131 }
1132 }
1133 if (!borderRadius->IsUndefined() && !borderRadius->IsNull()) {
1134 CalcDimension calcDimension;
1135 NG::BorderRadiusProperty borderRadiusProperty;
1136 if (ParseLengthMetricsToDimension(borderRadius, calcDimension, bgStyle.borderRadiusResObj)) {
1137 if (GreatOrEqual(calcDimension.Value(), 0.0f)) {
1138 bgStyle.borderRadius = NG::BorderRadiusProperty(calcDimension);
1139 } else {
1140 bgStyle.borderRadiusResObj = nullptr;
1141 }
1142 } else if (ParseBindSheetBorderRadiusProps(borderRadius, borderRadiusProperty)) {
1143 SetBorderRadiusWithCheck(bgStyle.borderRadius, borderRadiusProperty);
1144 }
1145 }
1146 }
1147
SetDefaultPickerItemHeight(const JSCallbackInfo & info)1148 void JSTextPicker::SetDefaultPickerItemHeight(const JSCallbackInfo& info)
1149 {
1150 if (info.Length() < 1) {
1151 return;
1152 }
1153 CalcDimension height;
1154 if (info[0]->IsNumber() || info[0]->IsString()) {
1155 if (!ParseJsDimensionFp(info[0], height)) {
1156 return;
1157 }
1158 }
1159 TextPickerModel::GetInstance()->SetDefaultPickerItemHeight(height);
1160 }
1161
SetGradientHeight(const JSCallbackInfo & info)1162 void JSTextPicker::SetGradientHeight(const JSCallbackInfo& info)
1163 {
1164 CalcDimension height;
1165 RefPtr<ResourceObject> heightResObj;
1166 auto pickerTheme = GetTheme<PickerTheme>();
1167 if (info[0]->IsNull() || info[0]->IsUndefined()) {
1168 if (pickerTheme) {
1169 height = pickerTheme->GetGradientHeight();
1170 } else {
1171 height = 0.0_vp;
1172 }
1173 }
1174 if (info.Length() >= 1) {
1175 if (!ConvertFromJSValueNG(info[0], height, heightResObj)) {
1176 if (pickerTheme) {
1177 height = pickerTheme->GetGradientHeight();
1178 }
1179 }
1180 if ((height.Unit() == DimensionUnit::PERCENT) &&
1181 ((height.Value() > 1.0f) || (height.Value() < 0.0f))) {
1182 if (pickerTheme) {
1183 height = pickerTheme->GetGradientHeight();
1184 } else {
1185 height = 0.0_vp;
1186 }
1187 }
1188 }
1189
1190 if (SystemProperties::ConfigChangePerform()) {
1191 TextPickerModel::GetInstance()->ParseGradientHeight(heightResObj);
1192 }
1193 TextPickerModel::GetInstance()->SetGradientHeight(height);
1194 }
1195
SetCanLoop(const JSCallbackInfo & info)1196 void JSTextPicker::SetCanLoop(const JSCallbackInfo& info)
1197 {
1198 bool value = true;
1199 if (info.Length() >= 1 && info[0]->IsBoolean()) {
1200 value = info[0]->ToBoolean();
1201 }
1202 TextPickerModel::GetInstance()->SetCanLoop(value);
1203 }
1204
SetDigitalCrownSensitivity(const JSCallbackInfo & info)1205 void JSTextPicker::SetDigitalCrownSensitivity(const JSCallbackInfo& info)
1206 {
1207 int32_t value = OHOS::Ace::NG::DEFAULT_CROWNSENSITIVITY;
1208 if (info.Length() >= 1 && info[0]->IsNumber()) {
1209 value = info[0]->ToNumber<int32_t>();
1210 }
1211 TextPickerModel::GetInstance()->SetDigitalCrownSensitivity(value);
1212 }
1213
SetDisappearTextStyle(const JSCallbackInfo & info)1214 void JSTextPicker::SetDisappearTextStyle(const JSCallbackInfo& info)
1215 {
1216 auto theme = GetTheme<PickerTheme>();
1217 CHECK_NULL_VOID(theme);
1218 NG::PickerTextStyle textStyle;
1219 if (info.Length() >= 1 && info[0]->IsObject()) {
1220 JSTextPickerParser::ParseTextStyle(info[0], textStyle, "disappearTextStyle");
1221 }
1222 TextPickerModel::GetInstance()->SetDisappearTextStyle(theme, textStyle);
1223 }
1224
SetTextStyle(const JSCallbackInfo & info)1225 void JSTextPicker::SetTextStyle(const JSCallbackInfo& info)
1226 {
1227 auto theme = GetTheme<PickerTheme>();
1228 CHECK_NULL_VOID(theme);
1229 NG::PickerTextStyle textStyle;
1230 if (info.Length() >= 1 && info[0]->IsObject()) {
1231 JSTextPickerParser::ParseTextStyle(info[0], textStyle, "textStyle");
1232 }
1233 TextPickerModel::GetInstance()->SetNormalTextStyle(theme, textStyle);
1234 }
1235
SetSelectedTextStyle(const JSCallbackInfo & info)1236 void JSTextPicker::SetSelectedTextStyle(const JSCallbackInfo& info)
1237 {
1238 auto theme = GetTheme<PickerTheme>();
1239 CHECK_NULL_VOID(theme);
1240 NG::PickerTextStyle textStyle;
1241 if (info.Length() >= 1 && info[0]->IsObject()) {
1242 JSTextPickerParser::ParseTextStyle(info[0], textStyle, "selectedTextStyle");
1243 }
1244 TextPickerModel::GetInstance()->SetSelectedTextStyle(theme, textStyle);
1245 if (textStyle.textColor.has_value() && theme->IsCircleDial()) {
1246 TextPickerModel::GetInstance()->UpdateUserSetSelectColor();
1247 }
1248 }
1249
ProcessCascadeSelected(const std::vector<NG::TextCascadePickerOptions> & options,uint32_t index,std::vector<uint32_t> & selectedValues)1250 void JSTextPicker::ProcessCascadeSelected(
1251 const std::vector<NG::TextCascadePickerOptions>& options, uint32_t index, std::vector<uint32_t>& selectedValues)
1252 {
1253 std::vector<std::string> rangeResultValue;
1254 for (size_t i = 0; i < options.size(); i++) {
1255 rangeResultValue.emplace_back(options[i].rangeResult[0]);
1256 }
1257
1258 if (static_cast<int32_t>(index) > static_cast<int32_t>(selectedValues.size()) - 1) {
1259 selectedValues.emplace_back(0);
1260 }
1261 if (selectedValues[index] >= rangeResultValue.size()) {
1262 selectedValues[index] = 0;
1263 }
1264 if (static_cast<int32_t>(selectedValues[index]) <= static_cast<int32_t>(options.size()) - 1 &&
1265 options[selectedValues[index]].children.size() > 0) {
1266 ProcessCascadeSelected(options[selectedValues[index]].children, index + 1, selectedValues);
1267 }
1268 }
1269
SetSelectedInternal(uint32_t count,std::vector<NG::TextCascadePickerOptions> & options,std::vector<uint32_t> & selectedValues)1270 void JSTextPicker::SetSelectedInternal(
1271 uint32_t count, std::vector<NG::TextCascadePickerOptions>& options, std::vector<uint32_t>& selectedValues)
1272 {
1273 for (uint32_t i = 0; i < count; i++) {
1274 if (selectedValues.size() > 0 && selectedValues.size() < i + 1) {
1275 selectedValues.emplace_back(0);
1276 } else {
1277 if (selectedValues.size() > 0 && options.size() > 0 && selectedValues[i] >= options[i].rangeResult.size()) {
1278 selectedValues[i] = 0;
1279 }
1280 }
1281 }
1282 }
1283
SetSelectedIndexMultiInternal(uint32_t count,std::vector<NG::TextCascadePickerOptions> & options,std::vector<uint32_t> & selectedValues)1284 void JSTextPicker::SetSelectedIndexMultiInternal(
1285 uint32_t count, std::vector<NG::TextCascadePickerOptions>& options, std::vector<uint32_t>& selectedValues)
1286 {
1287 if (!TextPickerModel::GetInstance()->IsCascade()) {
1288 SetSelectedInternal(count, options, selectedValues);
1289 } else {
1290 TextPickerModel::GetInstance()->SetHasSelectAttr(true);
1291 ProcessCascadeSelected(options, 0, selectedValues);
1292 uint32_t maxCount = TextPickerModel::GetInstance()->GetMaxCount();
1293 if (selectedValues.size() < maxCount) {
1294 auto differ = maxCount - selectedValues.size();
1295 for (uint32_t i = 0; i < differ; i++) {
1296 selectedValues.emplace_back(0);
1297 }
1298 }
1299 }
1300 }
1301
SetSelectedIndexSingleInternal(const std::vector<NG::TextCascadePickerOptions> & options,uint32_t count,uint32_t & selectedValue,std::vector<uint32_t> & selectedValues)1302 void JSTextPicker::SetSelectedIndexSingleInternal(const std::vector<NG::TextCascadePickerOptions>& options,
1303 uint32_t count, uint32_t& selectedValue, std::vector<uint32_t>& selectedValues)
1304 {
1305 if (options.size() > 0) {
1306 if (selectedValue >= options[0].rangeResult.size()) {
1307 selectedValue = 0;
1308 }
1309 selectedValues.emplace_back(selectedValue);
1310 for (uint32_t i = 1; i < count; i++) {
1311 selectedValues.emplace_back(0);
1312 }
1313 } else {
1314 for (uint32_t i = 0; i < count; i++) {
1315 selectedValues.emplace_back(0);
1316 }
1317 }
1318 }
1319
SetSelectedIndexMulti(const JsiRef<JsiValue> & jsSelectedValue)1320 void JSTextPicker::SetSelectedIndexMulti(const JsiRef<JsiValue>& jsSelectedValue)
1321 {
1322 std::vector<uint32_t> selectedValues;
1323 std::vector<NG::TextCascadePickerOptions> options;
1324 TextPickerModel::GetInstance()->GetMultiOptions(options);
1325 auto count =
1326 TextPickerModel::GetInstance()->IsCascade() ? TextPickerModel::GetInstance()->GetMaxCount() : options.size();
1327 if (jsSelectedValue->IsArray()) {
1328 if (!ParseJsIntegerArray(jsSelectedValue, selectedValues)) {
1329 selectedValues.clear();
1330 for (uint32_t i = 0; i < count; i++) {
1331 selectedValues.emplace_back(0);
1332 }
1333 TextPickerModel::GetInstance()->SetSelecteds(selectedValues);
1334 TextPickerModel::GetInstance()->SetHasSelectAttr(false);
1335 return;
1336 }
1337 SetSelectedIndexMultiInternal(count, options, selectedValues);
1338 } else {
1339 uint32_t selectedValue = 0;
1340 if (ParseJsInteger(jsSelectedValue, selectedValue)) {
1341 TextPickerModel::GetInstance()->SetHasSelectAttr(true);
1342 SetSelectedIndexSingleInternal(options, count, selectedValue, selectedValues);
1343 } else {
1344 selectedValues.clear();
1345 TextPickerModel::GetInstance()->SetHasSelectAttr(false);
1346 for (uint32_t i = 0; i < count; i++) {
1347 selectedValues.emplace_back(0);
1348 }
1349 }
1350 }
1351 TextPickerModel::GetInstance()->SetSelecteds(selectedValues);
1352 }
1353
SetSelectedIndexSingle(const JsiRef<JsiValue> & jsSelectedValue)1354 void JSTextPicker::SetSelectedIndexSingle(const JsiRef<JsiValue>& jsSelectedValue)
1355 {
1356 // Single
1357 std::vector<NG::RangeContent> rangeResult;
1358 TextPickerModel::GetInstance()->GetSingleRange(rangeResult);
1359 if (jsSelectedValue->IsArray()) {
1360 std::vector<uint32_t> selectedValues;
1361 if (!ParseJsIntegerArray(jsSelectedValue, selectedValues)) {
1362 uint32_t selectedValue = 0;
1363 TextPickerModel::GetInstance()->SetSelected(selectedValue);
1364 return;
1365 }
1366 if (selectedValues.size() > 0) {
1367 if (selectedValues[0] >= rangeResult.size()) {
1368 selectedValues[0] = 0;
1369 }
1370 } else {
1371 selectedValues.emplace_back(0);
1372 }
1373
1374 TextPickerModel::GetInstance()->SetSelected(selectedValues[0]);
1375 } else {
1376 uint32_t selectedValue = 0;
1377 if (ParseJsInteger(jsSelectedValue, selectedValue)) {
1378 if (selectedValue >= rangeResult.size()) {
1379 selectedValue = 0;
1380 }
1381 }
1382 TextPickerModel::GetInstance()->SetSelected(selectedValue);
1383 }
1384 }
1385
SetSelectedIndex(const JSCallbackInfo & info)1386 void JSTextPicker::SetSelectedIndex(const JSCallbackInfo& info)
1387 {
1388 if (info.Length() >= 1) {
1389 auto jsSelectedValue = info[0];
1390 if (jsSelectedValue->IsNull() || jsSelectedValue->IsUndefined()) {
1391 return;
1392 }
1393 if (TextPickerModel::GetInstance()->IsSingle()) {
1394 SetSelectedIndexSingle(jsSelectedValue);
1395 } else {
1396 SetSelectedIndexMulti(jsSelectedValue);
1397 }
1398 }
1399 }
1400
SetDivider(const JSCallbackInfo & info)1401 void JSTextPicker::SetDivider(const JSCallbackInfo& info)
1402 {
1403 NG::ItemDivider divider;
1404 auto pickerTheme = GetTheme<PickerTheme>();
1405 Dimension defaultStrokeWidth = 0.0_vp;
1406 Color defaultColor = Color::TRANSPARENT;
1407 // Set default strokeWidth and color
1408 if (pickerTheme) {
1409 defaultStrokeWidth = pickerTheme->GetDividerThickness();
1410 defaultColor = pickerTheme->GetDividerColor();
1411 divider.strokeWidth = defaultStrokeWidth;
1412 divider.color = defaultColor;
1413 }
1414
1415 if (info.Length() >= 1 && info[0]->IsObject()) {
1416 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
1417 ParseDivider(obj, divider);
1418 } else if (info.Length() >= 1 && info[0]->IsNull()) {
1419 divider.strokeWidth = 0.0_vp;
1420 }
1421
1422 TextPickerModel::GetInstance()->SetDivider(divider);
1423 }
1424
OnAccept(const JSCallbackInfo & info)1425 void JSTextPicker::OnAccept(const JSCallbackInfo& info) {}
1426
OnCancel(const JSCallbackInfo & info)1427 void JSTextPicker::OnCancel(const JSCallbackInfo& info) {}
1428
OnChange(const JSCallbackInfo & info)1429 void JSTextPicker::OnChange(const JSCallbackInfo& info)
1430 {
1431 if (!info[0]->IsFunction()) {
1432 return;
1433 }
1434 auto jsFunc = JSRef<JSFunc>::Cast(info[0]);
1435 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](
1436 const std::vector<std::string>& value, const std::vector<double>& index) {
1437 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1438 ACE_SCORING_EVENT("TextPicker.onChange");
1439 if (value.size() == 1 && index.size() == 1) {
1440 auto params = ConvertToJSValues(value[0], index[0]);
1441 func->Call(JSRef<JSObject>(), static_cast<int>(params.size()), params.data());
1442 } else {
1443 std::vector<JSRef<JSVal>> result;
1444 JSRef<JSArray> valueArray = JSRef<JSArray>::New();
1445 for (uint32_t i = 0; i < value.size(); i++) {
1446 valueArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(value[i])));
1447 }
1448 JSRef<JSVal> valueJs = JSRef<JSVal>::Cast(valueArray);
1449 result.emplace_back(valueJs);
1450 JSRef<JSArray> selectedArray = JSRef<JSArray>::New();
1451 for (uint32_t i = 0; i < index.size(); i++) {
1452 selectedArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(index[i])));
1453 }
1454 JSRef<JSVal> selectedJs = JSRef<JSVal>::Cast(selectedArray);
1455 result.emplace_back(selectedJs);
1456 func->Call(JSRef<JSObject>(), static_cast<int>(result.size()), result.data());
1457 }
1458 };
1459 TextPickerModel::GetInstance()->SetOnCascadeChange(std::move(onChange));
1460 info.ReturnSelf();
1461 }
1462
OnScrollStop(const JSCallbackInfo & info)1463 void JSTextPicker::OnScrollStop(const JSCallbackInfo& info)
1464 {
1465 if (!info[0]->IsFunction()) {
1466 return;
1467 }
1468 auto jsFunc = JSRef<JSFunc>::Cast(info[0]);
1469 auto onScrollStop = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](
1470 const std::vector<std::string>& value, const std::vector<double>& index) {
1471 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1472 ACE_SCORING_EVENT("TextPicker.onScrollStop");
1473 if (value.size() == 1 && index.size() == 1) {
1474 auto params = ConvertToJSValues(value[0], index[0]);
1475 func->Call(JSRef<JSObject>(), static_cast<int>(params.size()), params.data());
1476 } else {
1477 std::vector<JSRef<JSVal>> result;
1478 JSRef<JSArray> valueArray = JSRef<JSArray>::New();
1479 for (uint32_t i = 0; i < value.size(); i++) {
1480 valueArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(value[i])));
1481 }
1482 JSRef<JSVal> valueJs = JSRef<JSVal>::Cast(valueArray);
1483 result.emplace_back(valueJs);
1484 JSRef<JSArray> selectedArray = JSRef<JSArray>::New();
1485 for (uint32_t i = 0; i < index.size(); i++) {
1486 selectedArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(index[i])));
1487 }
1488 JSRef<JSVal> selectedJs = JSRef<JSVal>::Cast(selectedArray);
1489 result.emplace_back(selectedJs);
1490 func->Call(JSRef<JSObject>(), static_cast<int>(result.size()), result.data());
1491 }
1492 };
1493 TextPickerModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
1494 info.ReturnSelf();
1495 }
1496
OnEnterSelectedArea(const JSCallbackInfo & info)1497 void JSTextPicker::OnEnterSelectedArea(const JSCallbackInfo& info)
1498 {
1499 if (!info[0]->IsFunction()) {
1500 return;
1501 }
1502 auto jsFunc = JSRef<JSFunc>::Cast(info[0]);
1503 auto onEnterSelectedArea = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](
1504 const std::vector<std::string>& value, const std::vector<double>& index) {
1505 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1506 ACE_SCORING_EVENT("TextPicker.onEnterSelectedArea");
1507 if (value.size() == 1 && index.size() == 1) {
1508 auto params = ConvertToJSValues(value[0], index[0]);
1509 func->Call(JSRef<JSObject>(), static_cast<int>(params.size()), params.data());
1510 } else {
1511 std::vector<JSRef<JSVal>> result;
1512 JSRef<JSArray> valueArray = JSRef<JSArray>::New();
1513 for (uint32_t i = 0; i < value.size(); i++) {
1514 valueArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(value[i])));
1515 }
1516 JSRef<JSVal> valueJs = JSRef<JSVal>::Cast(valueArray);
1517 result.emplace_back(valueJs);
1518 JSRef<JSArray> selectedArray = JSRef<JSArray>::New();
1519 for (uint32_t i = 0; i < index.size(); i++) {
1520 selectedArray->SetValueAt(i, JSRef<JSVal>::Make(ToJSValue(index[i])));
1521 }
1522 JSRef<JSVal> selectedJs = JSRef<JSVal>::Cast(selectedArray);
1523 result.emplace_back(selectedJs);
1524 func->Call(JSRef<JSObject>(), static_cast<int>(result.size()), result.data());
1525 }
1526 };
1527 TextPickerModel::GetInstance()->SetOnEnterSelectedArea(std::move(onEnterSelectedArea));
1528 info.ReturnSelf();
1529 }
SetEnableHapticFeedback(const JSCallbackInfo & info)1530 void JSTextPicker::SetEnableHapticFeedback(const JSCallbackInfo& info)
1531 {
1532 bool isEnableHapticFeedback = DEFAULT_ENABLE_HAPTIC_FEEDBACK;
1533 if (info.Length() >= 1 && info[0]->IsBoolean()) {
1534 isEnableHapticFeedback = info[0]->ToBoolean();
1535 }
1536 TextPickerModel::GetInstance()->SetEnableHapticFeedback(isEnableHapticFeedback);
1537 }
1538
SetSelectedBackgroundStyle(const JSCallbackInfo & info)1539 void JSTextPicker::SetSelectedBackgroundStyle(const JSCallbackInfo& info)
1540 {
1541 if (info[0]->IsUndefined()) {
1542 return;
1543 }
1544 auto theme = GetTheme<PickerTheme>();
1545 CHECK_NULL_VOID(theme);
1546 NG::PickerBackgroundStyle backgroundStyle;
1547 backgroundStyle.color = theme->GetSelectedBackgroundColor();
1548 backgroundStyle.borderRadius = theme->GetSelectedBorderRadius();
1549 if (info[0]->IsObject()) {
1550 JSTextPickerParser::ParsePickerBackgroundStyle(info[0], backgroundStyle);
1551 }
1552 TextPickerModel::GetInstance()->SetSelectedBackgroundStyle(backgroundStyle);
1553 }
1554
JSBind(BindingTarget globalObj)1555 void JSTextPickerDialog::JSBind(BindingTarget globalObj)
1556 {
1557 JSClass<JSTextPickerDialog>::Declare("TextPickerDialog");
1558 JSClass<JSTextPickerDialog>::StaticMethod("show", &JSTextPickerDialog::Show);
1559
1560 JSClass<JSTextPickerDialog>::Bind<>(globalObj);
1561 }
1562
TextPickerDialogAppearEvent(const JSCallbackInfo & info,TextPickerDialogEvent & textPickerDialogEvent)1563 void TextPickerDialogAppearEvent(const JSCallbackInfo& info, TextPickerDialogEvent& textPickerDialogEvent)
1564 {
1565 std::function<void()> didAppearEvent;
1566 std::function<void()> willAppearEvent;
1567 if (!info[0]->IsObject()) {
1568 return;
1569 }
1570 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1571 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1572 auto onDidAppear = paramObject->GetProperty("onDidAppear");
1573 if (!onDidAppear->IsUndefined() && onDidAppear->IsFunction()) {
1574 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidAppear));
1575 didAppearEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
1576 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1577 ACE_SCORING_EVENT("TextPickerDialog.onDidAppear");
1578 PipelineContext::SetCallBackNode(node);
1579 func->Execute();
1580 };
1581 }
1582 auto onWillAppear = paramObject->GetProperty("onWillAppear");
1583 if (!onWillAppear->IsUndefined() && onWillAppear->IsFunction()) {
1584 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillAppear));
1585 willAppearEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
1586 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1587 ACE_SCORING_EVENT("TextPickerDialog.onWillAppear");
1588 PipelineContext::SetCallBackNode(node);
1589 func->Execute();
1590 };
1591 }
1592 textPickerDialogEvent.onDidAppear = std::move(didAppearEvent);
1593 textPickerDialogEvent.onWillAppear = std::move(willAppearEvent);
1594 }
1595
TextPickerDialogDisappearEvent(const JSCallbackInfo & info,TextPickerDialogEvent & textPickerDialogEvent)1596 void TextPickerDialogDisappearEvent(const JSCallbackInfo& info, TextPickerDialogEvent& textPickerDialogEvent)
1597 {
1598 std::function<void()> didDisappearEvent;
1599 std::function<void()> willDisappearEvent;
1600 if (!info[0]->IsObject()) {
1601 return;
1602 }
1603 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1604 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1605 auto onDidDisappear = paramObject->GetProperty("onDidDisappear");
1606 if (!onDidDisappear->IsUndefined() && onDidDisappear->IsFunction()) {
1607 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidDisappear));
1608 didDisappearEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
1609 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1610 ACE_SCORING_EVENT("TextPickerDialog.onDidDisappear");
1611 PipelineContext::SetCallBackNode(node);
1612 func->Execute();
1613 };
1614 }
1615 auto onWillDisappear = paramObject->GetProperty("onWillDisappear");
1616 if (!onWillDisappear->IsUndefined() && onWillDisappear->IsFunction()) {
1617 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillDisappear));
1618 willDisappearEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
1619 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1620 ACE_SCORING_EVENT("TextPickerDialog.onWillDisappear");
1621 PipelineContext::SetCallBackNode(node);
1622 func->Execute();
1623 };
1624 }
1625 textPickerDialogEvent.onDidDisappear = std::move(didDisappearEvent);
1626 textPickerDialogEvent.onWillDisappear = std::move(willDisappearEvent);
1627 }
1628
Show(const JSCallbackInfo & info)1629 void JSTextPickerDialog::Show(const JSCallbackInfo& info)
1630 {
1631 auto scopedDelegate = EngineHelper::GetCurrentDelegateSafely();
1632 CHECK_NULL_VOID(scopedDelegate);
1633 if (!info[0]->IsObject()) {
1634 return;
1635 }
1636
1637 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1638 std::function<void()> cancelEvent;
1639 std::function<void(const std::string&)> acceptEvent;
1640 std::function<void(const std::string&)> changeEvent;
1641 auto onCancel = paramObject->GetProperty("onCancel");
1642 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1643 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
1644 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
1645 cancelEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
1646 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1647 ACE_SCORING_EVENT("TextPickerDialog.onCancel");
1648 PipelineContext::SetCallBackNode(node);
1649 func->Execute();
1650 };
1651 }
1652 auto onAccept = paramObject->GetProperty("onAccept");
1653 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
1654 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
1655 acceptEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1656 const std::string& info) {
1657 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1658 std::vector<std::string> keys = { "value", "index" };
1659 ACE_SCORING_EVENT("TextPickerDialog.onAccept");
1660 PipelineContext::SetCallBackNode(node);
1661 func->Execute(keys, info);
1662 };
1663 }
1664 auto onChange = paramObject->GetProperty("onChange");
1665 if (!onChange->IsUndefined() && onChange->IsFunction()) {
1666 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
1667 changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1668 const std::string& info) {
1669 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1670 std::vector<std::string> keys = { "value", "index" };
1671 ACE_SCORING_EVENT("TextPickerDialog.onChange");
1672 PipelineContext::SetCallBackNode(node);
1673 func->Execute(keys, info);
1674 };
1675 }
1676 std::function<void(const std::string&)> scrollStopEvent;
1677 auto onScrollStop = paramObject->GetProperty("onScrollStop");
1678 if (!onScrollStop->IsUndefined() && onScrollStop->IsFunction()) {
1679 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onScrollStop));
1680 scrollStopEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1681 const std::string& info) {
1682 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1683 std::vector<std::string> keys = { "value", "index" };
1684 ACE_SCORING_EVENT("TextPickerDialog.onScrollStop");
1685 PipelineContext::SetCallBackNode(node);
1686 func->Execute(keys, info);
1687 };
1688 }
1689 std::function<void(const std::string&)> enterSelectedAreaEvent;
1690 auto onEnterSelectedArea = paramObject->GetProperty("onEnterSelectedArea");
1691 if (!onEnterSelectedArea->IsUndefined() && onEnterSelectedArea->IsFunction()) {
1692 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onEnterSelectedArea));
1693 enterSelectedAreaEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
1694 const std::string& info) {
1695 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1696 std::vector<std::string> keys = { "value", "index" };
1697 ACE_SCORING_EVENT("TextPickerDialog.onEnterSelectedArea");
1698 PipelineContext::SetCallBackNode(node);
1699 func->Execute(keys, info);
1700 };
1701 }
1702 NG::TextPickerSettingData settingData;
1703 TextPickerDialog textPickerDialog;
1704
1705 auto pickerText = TextPickerDialogModel::GetInstance()->CreateObject();
1706 if (pickerText == nullptr) {
1707 // parse Multi column text
1708 if (!ParseShowData(paramObject, settingData)) {
1709 return;
1710 }
1711 } else {
1712 auto getSelected = paramObject->GetProperty("selected");
1713 auto defaultHeight = paramObject->GetProperty("defaultPickerItemHeight");
1714 auto canLoop = paramObject->GetProperty("canLoop");
1715 JSRef<JSArray> getRange = paramObject->GetProperty("range");
1716 std::vector<std::string> getRangeVector;
1717 if (!JSViewAbstract::ParseJsStrArray(getRange, getRangeVector)) {
1718 return;
1719 }
1720 std::string value = "";
1721 uint32_t selectedValue = 0;
1722 auto getValue = paramObject->GetProperty("value");
1723 if (!JSViewAbstract::ParseJsInteger(getSelected, selectedValue) &&
1724 JSViewAbstract::ParseJsString(getValue, value)) {
1725 auto valueIterator = std::find(getRangeVector.begin(), getRangeVector.end(), value);
1726 if (valueIterator != getRangeVector.end()) {
1727 selectedValue = static_cast<uint32_t>(std::distance(getRangeVector.begin(), valueIterator));
1728 }
1729 }
1730 if (selectedValue >= getRangeVector.size()) {
1731 selectedValue = 0;
1732 }
1733 CalcDimension height;
1734 if (defaultHeight->IsNumber() || defaultHeight->IsString()) {
1735 if (!JSViewAbstract::ParseJsDimensionFp(defaultHeight, height)) {
1736 return;
1737 }
1738 }
1739 if (!defaultHeight->IsEmpty()) {
1740 textPickerDialog.isDefaultHeight = true;
1741 }
1742 textPickerDialog.height = height;
1743 textPickerDialog.selectedValue = selectedValue;
1744 textPickerDialog.getRangeVector = getRangeVector;
1745 }
1746
1747 // Parse alignment
1748 auto alignmentValue = paramObject->GetProperty("alignment");
1749 if (alignmentValue->IsNumber()) {
1750 auto alignment = alignmentValue->ToNumber<int32_t>();
1751 if (alignment >= 0 && alignment < static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
1752 textPickerDialog.alignment = DIALOG_ALIGNMENT[alignment];
1753 }
1754 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1755 if (alignment == static_cast<int32_t>(DialogAlignment::TOP) ||
1756 alignment == static_cast<int32_t>(DialogAlignment::TOP_START) ||
1757 alignment == static_cast<int32_t>(DialogAlignment::TOP_END)) {
1758 textPickerDialog.offset = TEXT_PICKER_OFFSET_DEFAULT_TOP;
1759 }
1760 }
1761 }
1762
1763 // Parse offset
1764 auto offsetValue = paramObject->GetProperty("offset");
1765 if (offsetValue->IsObject()) {
1766 auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
1767 CalcDimension dx;
1768 auto dxValue = offsetObj->GetProperty("dx");
1769 JSAlertDialog::ParseJsDimensionVp(dxValue, dx);
1770 CalcDimension dy;
1771 auto dyValue = offsetObj->GetProperty("dy");
1772 JSAlertDialog::ParseJsDimensionVp(dyValue, dy);
1773 textPickerDialog.offset = DimensionOffset(dx, dy);
1774 }
1775
1776 // Parse maskRect.
1777 auto maskRectValue = paramObject->GetProperty("maskRect");
1778 DimensionRect maskRect;
1779 if (JSViewAbstract::ParseJsDimensionRect(maskRectValue, maskRect)) {
1780 textPickerDialog.maskRect = maskRect;
1781 }
1782
1783 auto backgroundColorValue = paramObject->GetProperty("backgroundColor");
1784 Color backgroundColor;
1785 if (JSViewAbstract::ParseJsColor(backgroundColorValue, backgroundColor)) {
1786 textPickerDialog.backgroundColor = backgroundColor;
1787 }
1788
1789 auto backgroundBlurStyle = paramObject->GetProperty("backgroundBlurStyle");
1790 if (backgroundBlurStyle->IsNumber()) {
1791 auto blurStyle = backgroundBlurStyle->ToNumber<int32_t>();
1792 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
1793 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
1794 textPickerDialog.backgroundBlurStyle = blurStyle;
1795 }
1796 }
1797 auto shadowValue = paramObject->GetProperty("shadow");
1798 Shadow shadow;
1799 if ((shadowValue->IsObject() || shadowValue->IsNumber()) && JSViewAbstract::ParseShadowProps(shadowValue, shadow)) {
1800 textPickerDialog.shadow = shadow;
1801 }
1802
1803 auto enableHoverModeValue = paramObject->GetProperty("enableHoverMode");
1804 if (enableHoverModeValue->IsBoolean()) {
1805 textPickerDialog.enableHoverMode = enableHoverModeValue->ToBoolean();
1806 }
1807
1808 auto hoverModeAreaValue = paramObject->GetProperty("hoverModeArea");
1809 textPickerDialog.hoverModeArea = HoverModeAreaType::BOTTOM_SCREEN;
1810 if (hoverModeAreaValue->IsNumber()) {
1811 auto hoverModeArea = hoverModeAreaValue->ToNumber<int32_t>();
1812 if (hoverModeArea >= 0 && hoverModeArea < static_cast<int32_t>(HOVER_MODE_AREA_TYPE.size())) {
1813 textPickerDialog.hoverModeArea = HOVER_MODE_AREA_TYPE[hoverModeArea];
1814 }
1815 }
1816
1817 auto blurStyleValue = paramObject->GetProperty("backgroundBlurStyleOptions");
1818 if (blurStyleValue->IsObject()) {
1819 if (!textPickerDialog.blurStyleOption.has_value()) {
1820 textPickerDialog.blurStyleOption.emplace();
1821 }
1822 JSViewAbstract::ParseBlurStyleOption(blurStyleValue, textPickerDialog.blurStyleOption.value());
1823 }
1824
1825 auto effectOptionValue = paramObject->GetProperty("backgroundEffect");
1826 if (effectOptionValue->IsObject()) {
1827 if (!textPickerDialog.effectOption.has_value()) {
1828 textPickerDialog.effectOption.emplace();
1829 }
1830 JSViewAbstract::ParseEffectOption(effectOptionValue, textPickerDialog.effectOption.value());
1831 }
1832
1833 auto buttonInfos = ParseButtonStyles(paramObject);
1834
1835 TextPickerDialogEvent textPickerDialogEvent { nullptr, nullptr, nullptr, nullptr };
1836 TextPickerDialogAppearEvent(info, textPickerDialogEvent);
1837 TextPickerDialogDisappearEvent(info, textPickerDialogEvent);
1838 TextPickerDialogModel::GetInstance()->SetTextPickerDialogShow(pickerText, settingData, std::move(cancelEvent),
1839 std::move(acceptEvent), std::move(changeEvent), std::move(scrollStopEvent), std::move(enterSelectedAreaEvent),
1840 textPickerDialog, textPickerDialogEvent, buttonInfos);
1841 }
1842
TextPickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogTextEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent)1843 void JSTextPickerDialog::TextPickerDialogShow(const JSRef<JSObject>& paramObj,
1844 const std::map<std::string, NG::DialogTextEvent>& dialogEvent,
1845 const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent)
1846 {
1847 auto container = Container::CurrentSafely();
1848 if (!container) {
1849 return;
1850 }
1851 auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
1852 if (!pipelineContext) {
1853 return;
1854 }
1855
1856 auto executor = pipelineContext->GetTaskExecutor();
1857 if (!executor) {
1858 return;
1859 }
1860
1861 auto theme = JSTextPicker::GetTheme<DialogTheme>();
1862 CHECK_NULL_VOID(theme);
1863
1864 NG::TextPickerSettingData settingData;
1865 if (!ParseShowData(paramObj, settingData)) {
1866 return;
1867 }
1868
1869 DialogProperties properties;
1870 properties.alignment = theme->GetAlignment();
1871 if (properties.alignment == DialogAlignment::BOTTOM &&
1872 Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_ELEVEN)) {
1873 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
1874 }
1875
1876 bool isEnableHapticFeedback = DEFAULT_ENABLE_HAPTIC_FEEDBACK;
1877 auto enableHapticFeedbackValue = paramObj->GetProperty("enableHapticFeedback");
1878 if (enableHapticFeedbackValue->IsBoolean()) {
1879 isEnableHapticFeedback = enableHapticFeedbackValue->ToBoolean();
1880 }
1881 settingData.isEnableHapticFeedback = isEnableHapticFeedback;
1882 properties.customStyle = false;
1883 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1884 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
1885 }
1886 auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
1887 auto overlayManager = context ? context->GetOverlayManager() : nullptr;
1888 executor->PostTask(
1889 [properties, settingData, dialogEvent, dialogCancelEvent, weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
1890 auto overlayManager = weak.Upgrade();
1891 CHECK_NULL_VOID(overlayManager);
1892 overlayManager->ShowTextDialog(properties, settingData, dialogEvent, dialogCancelEvent);
1893 },
1894 TaskExecutor::TaskType::UI, "ArkUIDialogShowTextPicker",
1895 TaskExecutor::GetPriorityTypeWithCheck(PriorityType::VIP));
1896 }
1897
ParseShowDataOptions(const JSRef<JSObject> & paramObject,ParseTextArrayParam & param,NG::TextCascadePickerOptionsAttr & attr)1898 bool JSTextPickerDialog::ParseShowDataOptions(
1899 const JSRef<JSObject>& paramObject, ParseTextArrayParam& param, NG::TextCascadePickerOptionsAttr& attr)
1900 {
1901 bool optionsMultiContentCheckErr = false;
1902 bool optionsCascadeContentCheckErr = false;
1903 if (!JSTextPickerParser::ParseMultiTextArray(paramObject, param)) {
1904 param.options.clear();
1905 optionsMultiContentCheckErr = true;
1906 }
1907
1908 if (optionsMultiContentCheckErr) {
1909 if (!JSTextPickerParser::ParseCascadeTextArray(paramObject, param, attr)) {
1910 param.options.clear();
1911 optionsCascadeContentCheckErr = true;
1912 } else {
1913 JSRef<JSArray> getRange = paramObject->GetProperty("range");
1914 JSTextPickerParser::GenerateCascadeOptions(getRange, param.options);
1915 attr.isCascade = true;
1916
1917 JSTextPickerParser::ParseColumnWidths(paramObject, param);
1918 }
1919 }
1920 if (optionsMultiContentCheckErr && optionsCascadeContentCheckErr) {
1921 param.options.clear();
1922 return false;
1923 }
1924 return true;
1925 }
1926
ParseShowDataAttribute(const JSRef<JSObject> & paramObject,NG::TextPickerSettingData & settingData)1927 bool JSTextPickerDialog::ParseShowDataAttribute(
1928 const JSRef<JSObject>& paramObject, NG::TextPickerSettingData& settingData)
1929 {
1930 CalcDimension height;
1931 auto defaultHeight = paramObject->GetProperty("defaultPickerItemHeight");
1932 if (defaultHeight->IsNumber() || defaultHeight->IsString()) {
1933 if (!JSViewAbstract::ParseJsDimensionFp(defaultHeight, height)) {
1934 return false;
1935 }
1936 }
1937 settingData.height = height;
1938 ParseTextProperties(paramObject, settingData.properties);
1939 auto selectedBackgroundStyle = paramObject->GetProperty("selectedBackgroundStyle");
1940 if (selectedBackgroundStyle->IsObject()) {
1941 JSTextPickerParser::ParsePickerBackgroundStyle(selectedBackgroundStyle, settingData.pickerBgStyle);
1942 } else {
1943 settingData.pickerBgStyle.color = Color::TRANSPARENT;
1944 settingData.pickerBgStyle.borderRadius = NG::BorderRadiusProperty(8.0_vp);
1945 }
1946 return true;
1947 }
1948
ParseCanLoop(const JSRef<JSObject> & paramObject,bool & canLoop)1949 bool JSTextPickerDialog::ParseCanLoop(const JSRef<JSObject>& paramObject, bool& canLoop)
1950 {
1951 bool result = false;
1952 auto prop = paramObject->GetProperty("canLoop");
1953 bool value = false;
1954 if (prop->IsBoolean() && JSViewAbstract::ParseJsBool(prop, value)) {
1955 canLoop = value;
1956 result = true;
1957 } else {
1958 canLoop = true;
1959 result = false;
1960 }
1961 return result;
1962 }
1963
ParseDisableTextStyleAnimation(const JSRef<JSObject> & paramObject,bool & isDisableTextStyleAnimation)1964 void JSTextPickerDialog::ParseDisableTextStyleAnimation(
1965 const JSRef<JSObject>& paramObject, bool& isDisableTextStyleAnimation)
1966 {
1967 auto prop = paramObject->GetProperty("disableTextStyleAnimation");
1968 bool value = false;
1969 if (prop->IsBoolean() && JSViewAbstract::ParseJsBool(prop, value)) {
1970 isDisableTextStyleAnimation = value;
1971 } else {
1972 isDisableTextStyleAnimation = false;
1973 }
1974 }
1975
ParseShowDataMultiContent(const std::vector<NG::TextCascadePickerOptions> & options,const std::vector<uint32_t> & selectedValues,const std::vector<std::string> & values,NG::TextCascadePickerOptionsAttr & attr,NG::TextPickerSettingData & settingData)1976 void JSTextPickerDialog::ParseShowDataMultiContent(const std::vector<NG::TextCascadePickerOptions>& options,
1977 const std::vector<uint32_t>& selectedValues, const std::vector<std::string>& values,
1978 NG::TextCascadePickerOptionsAttr& attr, NG::TextPickerSettingData& settingData)
1979 {
1980 settingData.columnKind = NG::TEXT;
1981 for (auto& item : selectedValues) {
1982 settingData.selectedValues.emplace_back(item);
1983 }
1984 for (auto& item : values) {
1985 settingData.values.emplace_back(item);
1986 }
1987 for (auto& item : options) {
1988 settingData.options.emplace_back(item);
1989 }
1990 settingData.attr.isCascade = attr.isCascade;
1991 settingData.attr.isHasSelectAttr = attr.isHasSelectAttr;
1992 }
1993
ParseShowData(const JSRef<JSObject> & paramObject,NG::TextPickerSettingData & settingData)1994 bool JSTextPickerDialog::ParseShowData(const JSRef<JSObject>& paramObject, NG::TextPickerSettingData& settingData)
1995 {
1996 ParseTextArrayParam param;
1997 bool rangeContentCheckErr = false;
1998 bool optionsCascadeContentCheckErr = false;
1999 NG::TextCascadePickerOptionsAttr attr;
2000 auto getRange = paramObject->GetProperty("range");
2001 if (getRange->IsNull() || getRange->IsUndefined()) {
2002 return false;
2003 }
2004 if (!JSTextPickerParser::ParseTextArray(paramObject, param)) {
2005 if (!JSTextPickerParser::ParseIconTextArray(paramObject, param)) {
2006 rangeContentCheckErr = true;
2007 param.result.clear();
2008 }
2009 }
2010 if (rangeContentCheckErr) {
2011 optionsCascadeContentCheckErr = !ParseShowDataOptions(paramObject, param, attr);
2012 }
2013 if (rangeContentCheckErr && optionsCascadeContentCheckErr) {
2014 return false;
2015 }
2016 if (memset_s(&settingData, sizeof(NG::TextPickerSettingData), 0, sizeof(NG::TextPickerSettingData)) != EOK) {
2017 return false;
2018 }
2019 if (!ParseShowDataAttribute(paramObject, settingData)) {
2020 return false;
2021 }
2022 ParseCanLoop(paramObject, settingData.canLoop);
2023 ParseDisableTextStyleAnimation(paramObject, settingData.isDisableTextStyleAnimation);
2024 if (param.result.size() > 0) {
2025 settingData.selected = param.selected;
2026 settingData.columnKind = param.kind;
2027 for (const auto& item : param.result) {
2028 settingData.rangeVector.emplace_back(item);
2029 }
2030 } else {
2031 ParseShowDataMultiContent(param.options, param.selecteds, param.values, attr, settingData);
2032 }
2033 bool isEnableHapticFeedback = DEFAULT_ENABLE_HAPTIC_FEEDBACK;
2034 auto enableHapticFeedbackValue = paramObject->GetProperty("enableHapticFeedback");
2035 if (enableHapticFeedbackValue->IsBoolean()) {
2036 isEnableHapticFeedback = enableHapticFeedbackValue->ToBoolean();
2037 }
2038 settingData.isEnableHapticFeedback = isEnableHapticFeedback;
2039
2040 for (auto& item : param.columnWidths) {
2041 settingData.columnWidths.emplace_back(item);
2042 }
2043 return true;
2044 }
2045
ParseTextProperties(const JSRef<JSObject> & paramObj,NG::PickerTextProperties & result)2046 void JSTextPickerDialog::ParseTextProperties(const JSRef<JSObject>& paramObj, NG::PickerTextProperties& result)
2047 {
2048 auto disappearProperty = paramObj->GetProperty("disappearTextStyle");
2049 auto normalProperty = paramObj->GetProperty("textStyle");
2050 auto selectedProperty = paramObj->GetProperty("selectedTextStyle");
2051 auto defaultProperty = paramObj->GetProperty("defaultTextStyle");
2052
2053 if (!disappearProperty->IsNull() && disappearProperty->IsObject()) {
2054 JSRef<JSObject> disappearObj = JSRef<JSObject>::Cast(disappearProperty);
2055 JSTextPickerParser::ParseTextStyle(disappearObj, result.disappearTextStyle_, "disappearTextStyle");
2056 }
2057
2058 if (!normalProperty->IsNull() && normalProperty->IsObject()) {
2059 JSRef<JSObject> noramlObj = JSRef<JSObject>::Cast(normalProperty);
2060 JSTextPickerParser::ParseTextStyle(noramlObj, result.normalTextStyle_, "textStyle");
2061 }
2062
2063 if (!selectedProperty->IsNull() && selectedProperty->IsObject()) {
2064 JSRef<JSObject> selectedObj = JSRef<JSObject>::Cast(selectedProperty);
2065 JSTextPickerParser::ParseTextStyle(selectedObj, result.selectedTextStyle_, "selectedTextStyle");
2066 }
2067
2068 if (!defaultProperty->IsNull() && defaultProperty->IsObject()) {
2069 JSRef<JSObject> defaultObj = JSRef<JSObject>::Cast(defaultProperty);
2070 JSTextPickerParser::ParseTextStyle(defaultObj, result.defaultTextStyle_, "defaultTextStyle");
2071 }
2072 }
2073
ParseEnterSelectedAreaEvent(const JSRef<JSObject> & paramObject,const JSCallbackInfo & info,const WeakPtr<NG::FrameNode> & targetNode,std::map<std::string,NG::DialogTextEvent> & dialogEvent)2074 void JSTextPickerDialog::ParseEnterSelectedAreaEvent(const JSRef<JSObject>& paramObject, const JSCallbackInfo& info,
2075 const WeakPtr<NG::FrameNode>& targetNode, std::map<std::string, NG::DialogTextEvent>& dialogEvent)
2076 {
2077 auto onEnterSelectedArea = paramObject->GetProperty("onEnterSelectedArea");
2078 if (!onEnterSelectedArea->IsUndefined() && onEnterSelectedArea->IsFunction()) {
2079 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onEnterSelectedArea));
2080 auto enterSelectedAreaId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2081 const std::string& info) {
2082 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2083 std::vector<std::string> keys = { "value", "index" };
2084 ACE_SCORING_EVENT("TextPickerDialog.onEnterSelectedArea");
2085 PipelineContext::SetCallBackNode(node);
2086 func->Execute(keys, info);
2087 };
2088 dialogEvent["enterSelectedAreaId"] = enterSelectedAreaId;
2089 }
2090 }
2091
DialogEvent(const JSCallbackInfo & info)2092 std::map<std::string, NG::DialogTextEvent> JSTextPickerDialog::DialogEvent(const JSCallbackInfo& info)
2093 {
2094 std::map<std::string, NG::DialogTextEvent> dialogEvent;
2095 if (!info[0]->IsObject()) {
2096 return dialogEvent;
2097 }
2098 auto paramObject = JSRef<JSObject>::Cast(info[0]);
2099 auto onAccept = paramObject->GetProperty("onAccept");
2100 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
2101 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
2102 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
2103 auto acceptId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2104 const std::string& info) {
2105 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2106 std::vector<std::string> keys = { "value", "index" };
2107 ACE_SCORING_EVENT("TextPickerDialog.onAccept");
2108 PipelineContext::SetCallBackNode(node);
2109 func->Execute(keys, info);
2110 };
2111 dialogEvent["acceptId"] = acceptId;
2112 }
2113 auto onChange = paramObject->GetProperty("onChange");
2114 if (!onChange->IsUndefined() && onChange->IsFunction()) {
2115 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
2116 auto changeId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2117 const std::string& info) {
2118 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2119 std::vector<std::string> keys = { "value", "index" };
2120 ACE_SCORING_EVENT("TextPickerDialog.onChange");
2121 PipelineContext::SetCallBackNode(node);
2122 func->Execute(keys, info);
2123 };
2124 dialogEvent["changeId"] = changeId;
2125 }
2126 auto onScrollStop = paramObject->GetProperty("onScrollStop");
2127 if (!onScrollStop->IsUndefined() && onScrollStop->IsFunction()) {
2128 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onScrollStop));
2129 auto scrollStopId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2130 const std::string& info) {
2131 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2132 std::vector<std::string> keys = { "value", "index" };
2133 ACE_SCORING_EVENT("TextPickerDialog.onScrollStop");
2134 PipelineContext::SetCallBackNode(node);
2135 func->Execute(keys, info);
2136 };
2137 dialogEvent["scrollStopId"] = scrollStopId;
2138 }
2139 ParseEnterSelectedAreaEvent(paramObject, info, targetNode, dialogEvent);
2140 return dialogEvent;
2141 }
2142
DialogCancelEvent(const JSCallbackInfo & info)2143 std::map<std::string, NG::DialogGestureEvent> JSTextPickerDialog::DialogCancelEvent(const JSCallbackInfo& info)
2144 {
2145 std::map<std::string, NG::DialogGestureEvent> dialogCancelEvent;
2146 if (!info[0]->IsObject()) {
2147 return dialogCancelEvent;
2148 }
2149 auto paramObject = JSRef<JSObject>::Cast(info[0]);
2150 auto onCancel = paramObject->GetProperty("onCancel");
2151 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
2152 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
2153 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
2154 auto cancelId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2155 const GestureEvent& /* info */) {
2156 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2157 ACE_SCORING_EVENT("TextPickerDialog.onCancel");
2158 PipelineContext::SetCallBackNode(node);
2159 func->Execute();
2160 };
2161 dialogCancelEvent["cancelId"] = cancelId;
2162 }
2163 return dialogCancelEvent;
2164 }
2165
AddEvent(RefPtr<PickerTextComponent> & picker,const JSCallbackInfo & info)2166 void JSTextPickerDialog::AddEvent(RefPtr<PickerTextComponent>& picker, const JSCallbackInfo& info)
2167 {
2168 if (!info[0]->IsObject()) {
2169 return;
2170 }
2171 auto paramObject = JSRef<JSObject>::Cast(info[0]);
2172 auto onAccept = paramObject->GetProperty("onAccept");
2173 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
2174 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
2175 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
2176 auto acceptId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2177 const std::string& info) {
2178 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2179 std::vector<std::string> keys = { "value", "index" };
2180 ACE_SCORING_EVENT("TextPickerDialog.onAccept");
2181 PipelineContext::SetCallBackNode(node);
2182 func->Execute(keys, info);
2183 });
2184 picker->SetDialogAcceptEvent(acceptId);
2185 }
2186 auto onCancel = paramObject->GetProperty("onCancel");
2187 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
2188 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
2189 auto cancelId =
2190 EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
2191 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2192 ACE_SCORING_EVENT("TextPickerDialog.onCancel");
2193 PipelineContext::SetCallBackNode(node);
2194 func->Execute();
2195 });
2196 picker->SetDialogCancelEvent(cancelId);
2197 }
2198 auto onChange = paramObject->GetProperty("onChange");
2199 if (!onChange->IsUndefined() && onChange->IsFunction()) {
2200 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
2201 auto changeId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
2202 const std::string& info) {
2203 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2204 std::vector<std::string> keys = { "value", "index" };
2205 ACE_SCORING_EVENT("TextPickerDialog.onChange");
2206 PipelineContext::SetCallBackNode(node);
2207 func->Execute(keys, info);
2208 });
2209 picker->SetDialogChangeEvent(changeId);
2210 }
2211 }
2212
ParseText(RefPtr<PickerTextComponent> & component,const JSRef<JSObject> & paramObj)2213 void JSTextPickerDialog::ParseText(RefPtr<PickerTextComponent>& component, const JSRef<JSObject>& paramObj)
2214 {
2215 auto getSelected = paramObj->GetProperty("selected");
2216 auto defaultHeight = paramObj->GetProperty("defaultPickerItemHeight");
2217 auto canLoop = paramObj->GetProperty("canLoop");
2218 JSRef<JSArray> getRange = paramObj->GetProperty("range");
2219 std::vector<std::string> getRangeVector;
2220 if (!JSViewAbstract::ParseJsStrArray(getRange, getRangeVector)) {
2221 return;
2222 }
2223
2224 std::string value = "";
2225 uint32_t selectedValue = 0;
2226 auto getValue = paramObj->GetProperty("value");
2227 if (!JSViewAbstract::ParseJsInteger(getSelected, selectedValue) && JSViewAbstract::ParseJsString(getValue, value)) {
2228 auto valueIterator = std::find(getRangeVector.begin(), getRangeVector.end(), value);
2229 if (valueIterator != getRangeVector.end()) {
2230 selectedValue = static_cast<uint32_t>(std::distance(getRangeVector.begin(), valueIterator));
2231 }
2232 }
2233
2234 if (selectedValue >= getRangeVector.size()) {
2235 selectedValue = 0;
2236 }
2237
2238 CalcDimension height;
2239 if (defaultHeight->IsNumber() || defaultHeight->IsString()) {
2240 if (!JSViewAbstract::ParseJsDimensionFp(defaultHeight, height)) {
2241 return;
2242 }
2243 }
2244
2245 component->SetIsDialog(true);
2246 component->SetIsCreateDialogComponent(true);
2247 if (!defaultHeight->IsEmpty()) {
2248 component->SetColumnHeight(height);
2249 component->SetDefaultHeight(true);
2250 }
2251 component->SetSelected(selectedValue);
2252 component->SetRange(getRangeVector);
2253 }
2254 } // namespace OHOS::Ace::Framework
2255