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