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