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