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