1 /*
2 * Copyright (c) 2023 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 "frameworks/bridge/declarative_frontend/jsview/js_calendar_picker.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "base/utils/date_util.h"
20 #include "bridge/common/utils/engine_helper.h"
21 #include "bridge/declarative_frontend/engine/functions/js_function.h"
22 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
23 #include "bridge/declarative_frontend/jsview/js_utils.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/calendar_picker_model_impl.h"
26 #include "core/components/calendar/calendar_theme.h"
27 #include "core/components/dialog/dialog_theme.h"
28 #include "core/components_ng/base/view_abstract_model.h"
29 #include "core/components_ng/base/view_stack_processor.h"
30 #include "core/components_ng/pattern/calendar_picker/calendar_picker_model_ng.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace {
34 std::unique_ptr<CalendarPickerModel> CalendarPickerModel::instance_ = nullptr;
35 std::mutex CalendarPickerModel::mutex_;
GetInstance()36 CalendarPickerModel* CalendarPickerModel::GetInstance()
37 {
38 if (!instance_) {
39 std::lock_guard<std::mutex> lock(mutex_);
40 if (!instance_) {
41 #ifdef NG_BUILD
42 instance_.reset(new NG::CalendarPickerModelNG());
43 #else
44 if (Container::IsCurrentUseNewPipeline()) {
45 instance_.reset(new NG::CalendarPickerModelNG());
46 } else {
47 instance_.reset(new Framework::CalendarPickerModelImpl());
48 }
49 #endif
50 }
51 }
52 return instance_.get();
53 }
54 } // namespace OHOS::Ace
55
56 namespace OHOS::Ace::Framework {
57 namespace {
ParseFontOfButtonStyle(const JSRef<JSObject> & pickerButtonParamObject,ButtonInfo & buttonInfo)58 void ParseFontOfButtonStyle(const JSRef<JSObject>& pickerButtonParamObject, ButtonInfo& buttonInfo)
59 {
60 CalcDimension fontSize;
61 JSRef<JSVal> sizeProperty = pickerButtonParamObject->GetProperty("fontSize");
62 if (JSViewAbstract::ParseJsDimensionVpNG(sizeProperty, fontSize) && fontSize.Unit() != DimensionUnit::PERCENT &&
63 GreatOrEqual(fontSize.Value(), 0.0)) {
64 if (JSViewAbstract::ParseJsDimensionFp(sizeProperty, fontSize)) {
65 buttonInfo.fontSize = fontSize;
66 }
67 }
68 Color fontColor;
69 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("fontColor"), fontColor)) {
70 buttonInfo.fontColor = fontColor;
71 }
72 auto fontWeight = pickerButtonParamObject->GetProperty("fontWeight");
73 if (fontWeight->IsString() || fontWeight->IsNumber()) {
74 buttonInfo.fontWeight = ConvertStrToFontWeight(fontWeight->ToString(), FontWeight::MEDIUM);
75 }
76 JSRef<JSVal> style = pickerButtonParamObject->GetProperty("fontStyle");
77 if (style->IsNumber()) {
78 auto value = style->ToNumber<int32_t>();
79 if (value >= 0 && value < static_cast<int32_t>(FontStyle::NONE)) {
80 buttonInfo.fontStyle = static_cast<FontStyle>(value);
81 }
82 }
83 JSRef<JSVal> family = pickerButtonParamObject->GetProperty("fontFamily");
84 std::vector<std::string> fontFamilies;
85 if (JSViewAbstract::ParseJsFontFamilies(family, fontFamilies)) {
86 buttonInfo.fontFamily = fontFamilies;
87 }
88 }
89
ParseButtonStyle(const JSRef<JSObject> & pickerButtonParamObject)90 ButtonInfo ParseButtonStyle(const JSRef<JSObject>& pickerButtonParamObject)
91 {
92 ButtonInfo buttonInfo;
93 if (pickerButtonParamObject->GetProperty("type")->IsNumber()) {
94 buttonInfo.type =
95 static_cast<ButtonType>(pickerButtonParamObject->GetProperty("type")->ToNumber<int32_t>());
96 }
97 if (pickerButtonParamObject->GetProperty("style")->IsNumber()) {
98 auto styleModeIntValue = pickerButtonParamObject->GetProperty("style")->ToNumber<int32_t>();
99 if (styleModeIntValue >= static_cast<int32_t>(ButtonStyleMode::NORMAL) &&
100 styleModeIntValue <= static_cast<int32_t>(ButtonStyleMode::TEXT)) {
101 buttonInfo.buttonStyle = static_cast<ButtonStyleMode>(styleModeIntValue);
102 }
103 }
104 if (pickerButtonParamObject->GetProperty("role")->IsNumber()) {
105 auto buttonRoleIntValue = pickerButtonParamObject->GetProperty("role")->ToNumber<int32_t>();
106 if (buttonRoleIntValue >= static_cast<int32_t>(ButtonRole::NORMAL) &&
107 buttonRoleIntValue <= static_cast<int32_t>(ButtonRole::ERROR)) {
108 buttonInfo.role = static_cast<ButtonRole>(buttonRoleIntValue);
109 }
110 }
111 ParseFontOfButtonStyle(pickerButtonParamObject, buttonInfo);
112 Color backgroundColor;
113 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("backgroundColor"), backgroundColor)) {
114 buttonInfo.backgroundColor = backgroundColor;
115 }
116 auto radius = ParseBorderRadiusAttr(pickerButtonParamObject->GetProperty("borderRadius"));
117 if (radius.has_value()) {
118 buttonInfo.borderRadius = radius.value();
119 }
120
121 auto primaryValue = pickerButtonParamObject->GetProperty("primary");
122 if (primaryValue->IsBoolean()) {
123 buttonInfo.isPrimary = primaryValue->ToBoolean();
124 }
125
126 return buttonInfo;
127 }
128
ParseButtonStyles(const JSRef<JSObject> & paramObject)129 std::vector<ButtonInfo> ParseButtonStyles(const JSRef<JSObject>& paramObject)
130 {
131 std::vector<ButtonInfo> buttonInfos;
132 auto acceptButtonStyle = paramObject->GetProperty("acceptButtonStyle");
133 if (acceptButtonStyle->IsObject()) {
134 auto acceptButtonStyleParamObject = JSRef<JSObject>::Cast(acceptButtonStyle);
135 buttonInfos.emplace_back(ParseButtonStyle(acceptButtonStyleParamObject));
136 buttonInfos[0].isAcceptButton = true;
137 } else {
138 ButtonInfo buttonInfo;
139 buttonInfos.emplace_back(buttonInfo);
140 }
141 auto cancelButtonStyle = paramObject->GetProperty("cancelButtonStyle");
142 if (cancelButtonStyle->IsObject()) {
143 auto cancelButtonStyleParamObject = JSRef<JSObject>::Cast(cancelButtonStyle);
144 buttonInfos.emplace_back(ParseButtonStyle(cancelButtonStyleParamObject));
145 }
146
147 return buttonInfos;
148 }
149 } // namespace
150
GetMSByDate(const std::string & date)151 double GetMSByDate(const std::string& date)
152 {
153 auto json = JsonUtil::ParseJsonString(date);
154 if (!json || json->IsNull()) {
155 return 0.0f;
156 }
157
158 std::tm dateTime = { 0 };
159 auto year = json->GetValue("year");
160 if (year && year->IsNumber()) {
161 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
162 }
163 auto month = json->GetValue("month");
164 if (month && month->IsNumber()) {
165 dateTime.tm_mon = month->GetInt() - 1;
166 }
167 auto day = json->GetValue("day");
168 if (day && day->IsNumber()) {
169 dateTime.tm_mday = day->GetInt();
170 }
171 auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
172 auto local = std::localtime(&now);
173 CHECK_NULL_RETURN(local, 0.0f);
174 dateTime.tm_hour = local->tm_hour;
175 dateTime.tm_min = local->tm_min;
176 dateTime.tm_sec = local->tm_sec;
177 return Date::GetMilliSecondsByDateTime(dateTime);
178 }
179
JSBind(BindingTarget globalObj)180 void JSCalendarPicker::JSBind(BindingTarget globalObj)
181 {
182 JSClass<JSCalendarPicker>::Declare("CalendarPicker");
183 JSClass<JSCalendarPicker>::StaticMethod("create", &JSCalendarPicker::Create, MethodOptions::NONE);
184 JSClass<JSCalendarPicker>::StaticMethod("edgeAlign", &JSCalendarPicker::SetEdgeAlign);
185 JSClass<JSCalendarPicker>::StaticMethod("textStyle", &JSCalendarPicker::SetTextStyle);
186 JSClass<JSCalendarPicker>::StaticMethod("onChange", &JSCalendarPicker::SetOnChange);
187 JSClass<JSCalendarPicker>::StaticMethod("border", &JSCalendarPicker::SetBorder);
188 JSClass<JSCalendarPicker>::StaticMethod("padding", &JSCalendarPicker::JsPadding);
189 JSClass<JSCalendarPicker>::StaticMethod("height", &JSCalendarPicker::JsHeight);
190 JSClass<JSCalendarPicker>::StaticMethod("borderColor", &JSCalendarPicker::JsBorderColor);
191 JSClass<JSCalendarPicker>::StaticMethod("borderRadius", &JSCalendarPicker::JsBorderRadius);
192 JSClass<JSCalendarPicker>::InheritAndBind<JSViewAbstract>(globalObj);
193 }
194
SetBorder(const JSCallbackInfo & info)195 void JSCalendarPicker::SetBorder(const JSCallbackInfo& info)
196 {
197 if (!info[0]->IsObject()) {
198 CalendarPickerModel::GetInstance()->ClearBorder();
199 return;
200 }
201 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
202 auto valueWidth = object->GetProperty("width");
203 CalcDimension value;
204 if (ParseJsDimensionVpNG(valueWidth, value) || valueWidth->IsObject()) {
205 ParseBorderWidth(valueWidth);
206 } else {
207 CalendarPickerModel::GetInstance()->ClearBorderWidth();
208 }
209
210 // use default value when undefined.
211 ParseCalendarPickerBorderColor(object->GetProperty("color"));
212
213 auto valueRadius = object->GetProperty("radius");
214 if (!valueRadius->IsUndefined()) {
215 ParseBorderRadius(valueRadius);
216 }
217 // use default value when undefined.
218 ParseBorderStyle(object->GetProperty("style"));
219
220 info.ReturnSelf();
221 }
222
ParseCalendarPickerBorderColor(const JSRef<JSVal> & args)223 void JSCalendarPicker::ParseCalendarPickerBorderColor(const JSRef<JSVal>& args)
224 {
225 auto pipelineContext = PipelineContext::GetCurrentContext();
226 CHECK_NULL_VOID(pipelineContext);
227 RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
228 CHECK_NULL_VOID(theme);
229 if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
230 ViewAbstractModel::GetInstance()->SetBorderColor(theme->GetEntryBorderColor());
231 } else {
232 JSViewAbstract::ParseBorderColor(args);
233 }
234 }
235
SetEdgeAlign(const JSCallbackInfo & info)236 void JSCalendarPicker::SetEdgeAlign(const JSCallbackInfo& info)
237 {
238 NG::CalendarEdgeAlign alignType = NG::CalendarEdgeAlign::EDGE_ALIGN_END;
239 DimensionOffset offset;
240 if (info[0]->IsNumber()) {
241 alignType = static_cast<NG::CalendarEdgeAlign>(info[0]->ToNumber<int32_t>());
242 }
243
244 if (!info[1]->IsObject()) {
245 CalendarPickerModel::GetInstance()->SetEdgeAlign(alignType, offset);
246 return;
247 }
248 auto offsetObj = JSRef<JSObject>::Cast(info[1]);
249 CalcDimension dx;
250 auto dxValue = offsetObj->GetProperty("dx");
251 ParseJsDimensionVp(dxValue, dx);
252 CalcDimension dy;
253 auto dyValue = offsetObj->GetProperty("dy");
254 ParseJsDimensionVp(dyValue, dy);
255 offset = DimensionOffset(dx, dy);
256
257 CalendarPickerModel::GetInstance()->SetEdgeAlign(alignType, offset);
258 }
259
SetTextStyle(const JSCallbackInfo & info)260 void JSCalendarPicker::SetTextStyle(const JSCallbackInfo& info)
261 {
262 auto pipeline = PipelineBase::GetCurrentContext();
263 CHECK_NULL_VOID(pipeline);
264 RefPtr<CalendarTheme> calendarTheme = pipeline->GetTheme<CalendarTheme>();
265 CHECK_NULL_VOID(calendarTheme);
266 NG::PickerTextStyle textStyle;
267 textStyle.fontSize = calendarTheme->GetEntryFontSize();
268 textStyle.textColor = calendarTheme->GetEntryFontColor();
269 textStyle.fontWeight = FontWeight::NORMAL;
270 if (!info[0]->IsObject()) {
271 CalendarPickerModel::GetInstance()->SetTextStyle(textStyle);
272 return;
273 }
274 JSCalendarPicker::ParseTextStyle(info[0], textStyle);
275 CalendarPickerModel::GetInstance()->SetTextStyle(textStyle);
276 }
277
SetOnChange(const JSCallbackInfo & info)278 void JSCalendarPicker::SetOnChange(const JSCallbackInfo& info)
279 {
280 if (!info[0]->IsFunction()) {
281 return;
282 }
283
284 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
285 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
286 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
287 const std::string& info) {
288 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
289 ACE_SCORING_EVENT("CalendarPicker.onChange");
290 PipelineContext::SetCallBackNode(node);
291 auto dateObj = JSDate::New(GetMSByDate(info));
292 func->ExecuteJS(1, &dateObj);
293 };
294 CalendarPickerModel::GetInstance()->SetOnChange(std::move(onChange));
295 }
296
JsPadding(const JSCallbackInfo & info)297 void JSCalendarPicker::JsPadding(const JSCallbackInfo& info)
298 {
299 NG::PaddingProperty padding;
300 if (info[0]->IsObject()) {
301 std::optional<CalcDimension> left;
302 std::optional<CalcDimension> right;
303 std::optional<CalcDimension> top;
304 std::optional<CalcDimension> bottom;
305 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
306
307 CalcDimension leftDimen;
308 if (ParseJsDimensionVpNG(paddingObj->GetProperty("left"), leftDimen) && leftDimen.IsNonNegative()) {
309 left = leftDimen;
310 }
311 CalcDimension rightDimen;
312 if (ParseJsDimensionVpNG(paddingObj->GetProperty("right"), rightDimen) && rightDimen.IsNonNegative()) {
313 right = rightDimen;
314 }
315 CalcDimension topDimen;
316 if (ParseJsDimensionVpNG(paddingObj->GetProperty("top"), topDimen) && topDimen.IsNonNegative()) {
317 top = topDimen;
318 }
319 CalcDimension bottomDimen;
320 if (ParseJsDimensionVpNG(paddingObj->GetProperty("bottom"), bottomDimen) &&
321 bottomDimen.IsNonNegative()) {
322 bottom = bottomDimen;
323 }
324 if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
325 padding = SetPaddings(top, bottom, left, right);
326 CalendarPickerModel::GetInstance()->SetPadding(padding);
327 return;
328 }
329 }
330
331 CalcDimension length(-1);
332 if (ParseJsDimensionVpNG(info[0], length) && length.IsNonNegative()) {
333 padding.SetEdges(NG::CalcLength(length));
334 CalendarPickerModel::GetInstance()->SetPadding(padding);
335 } else {
336 CalendarPickerModel::GetInstance()->ClearPadding();
337 }
338 }
339
JsHeight(const JSCallbackInfo & info)340 void JSCalendarPicker::JsHeight(const JSCallbackInfo& info)
341 {
342 auto jsValue = info[0];
343 CalcDimension value;
344 if (ParseJsDimensionVpNG(jsValue, value) && value.IsValid()) {
345 JSViewAbstract::JsHeight(info);
346 } else {
347 CalendarPickerModel::GetInstance()->ClearHeight();
348 }
349 }
350
JsBorderColor(const JSCallbackInfo & info)351 void JSCalendarPicker::JsBorderColor(const JSCallbackInfo& info)
352 {
353 Color borderColor;
354 auto jsValue = info[0];
355 if (ParseJsColor(jsValue, borderColor) || jsValue->IsObject()) {
356 JSViewAbstract::JsBorderColor(info);
357 } else {
358 CalendarPickerModel::GetInstance()->ClearBorderColor();
359 }
360 }
361
JsBorderRadius(const JSCallbackInfo & info)362 void JSCalendarPicker::JsBorderRadius(const JSCallbackInfo& info)
363 {
364 auto jsValue = info[0];
365 CalcDimension value;
366 if (ParseJsDimensionVpNG(jsValue, value) || jsValue->IsObject()) {
367 JSViewAbstract::JsBorderRadius(info);
368 } else {
369 CalendarPickerModel::GetInstance()->ClearBorderRadius();
370 }
371 }
372
SetPaddings(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)373 NG::PaddingProperty JSCalendarPicker::SetPaddings(const std::optional<CalcDimension>& top,
374 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
375 const std::optional<CalcDimension>& right)
376 {
377 NG::PaddingProperty paddings;
378 if (top.has_value()) {
379 if (top.value().Unit() == DimensionUnit::CALC) {
380 paddings.top =
381 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
382 } else {
383 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
384 }
385 }
386 if (bottom.has_value()) {
387 if (bottom.value().Unit() == DimensionUnit::CALC) {
388 paddings.bottom = NG::CalcLength(
389 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
390 } else {
391 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
392 }
393 }
394 if (left.has_value()) {
395 if (left.value().Unit() == DimensionUnit::CALC) {
396 paddings.left =
397 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
398 } else {
399 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
400 }
401 }
402 if (right.has_value()) {
403 if (right.value().Unit() == DimensionUnit::CALC) {
404 paddings.right =
405 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
406 } else {
407 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
408 }
409 }
410
411 return paddings;
412 }
413
ParseSelectedDateObject(const JSCallbackInfo & info,const JSRef<JSObject> & selectedObject)414 void JSCalendarPicker::ParseSelectedDateObject(const JSCallbackInfo& info, const JSRef<JSObject>& selectedObject)
415 {
416 JSRef<JSVal> changeEventVal = selectedObject->GetProperty("changeEvent");
417 if (!changeEventVal->IsFunction()) {
418 return;
419 }
420 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
421 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
422 auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
423 const std::string& info) {
424 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
425 ACE_SCORING_EVENT("DatePicker.SelectedDateTimeChangeEvent");
426 PipelineContext::SetCallBackNode(node);
427 auto dateObj = JSDate::New(GetMSByDate(info));
428 func->ExecuteJS(1, &dateObj);
429 };
430 CalendarPickerModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
431 }
432
Create(const JSCallbackInfo & info)433 void JSCalendarPicker::Create(const JSCallbackInfo& info)
434 {
435 NG::CalendarSettingData settingData;
436 RefPtr<CalendarTheme> calendarTheme = GetTheme<CalendarTheme>();
437 CHECK_NULL_VOID(calendarTheme);
438 CalcDimension dayRadius;
439 if (info[0]->IsObject()) {
440 auto obj = JSRef<JSObject>::Cast(info[0]);
441 if (!ParseJsDimensionVpNG(obj->GetProperty("hintRadius"), dayRadius)) {
442 dayRadius = calendarTheme->GetCalendarDayRadius();
443 }
444 auto selected = obj->GetProperty("selected");
445 auto parseSelectedDate = ParseDate(selected);
446 if (selected->IsObject() && parseSelectedDate.GetYear() != 0) {
447 JSRef<JSObject> selectedDateObj = JSRef<JSObject>::Cast(selected);
448 JSRef<JSVal> changeEventVal = selectedDateObj->GetProperty("changeEvent");
449 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
450 ParseSelectedDateObject(info, selectedDateObj);
451 settingData.selectedDate = ParseDate(selectedDateObj->GetProperty("value"));
452 } else {
453 settingData.selectedDate = parseSelectedDate;
454 }
455 }
456 } else {
457 dayRadius = calendarTheme->GetCalendarDayRadius();
458 }
459 settingData.dayRadius = dayRadius;
460 CalendarPickerModel::GetInstance()->Create(settingData);
461 }
462
ParseTextStyle(const JSRef<JSObject> & paramObj,NG::PickerTextStyle & textStyle)463 void JSCalendarPicker::ParseTextStyle(const JSRef<JSObject>& paramObj, NG::PickerTextStyle& textStyle)
464 {
465 auto fontColor = paramObj->GetProperty("color");
466 auto fontStyle = paramObj->GetProperty("font");
467
468 Color color;
469 if (ParseJsColor(fontColor, color)) {
470 textStyle.textColor = color;
471 }
472
473 if (!fontStyle->IsObject()) {
474 return;
475 }
476 JSRef<JSObject> fontObj = JSRef<JSObject>::Cast(fontStyle);
477 auto fontSize = fontObj->GetProperty("size");
478 auto fontWeight = fontObj->GetProperty("weight");
479 if (fontSize->IsNull() || fontSize->IsUndefined()) {
480 textStyle.fontSize = Dimension(-1);
481 } else {
482 CalcDimension size;
483 if (!ParseJsDimensionFpNG(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
484 textStyle.fontSize = Dimension(-1);
485 } else {
486 textStyle.fontSize = size;
487 }
488 }
489
490 if (!fontWeight->IsNull() && !fontWeight->IsUndefined()) {
491 std::string weight;
492 if (fontWeight->IsNumber()) {
493 weight = std::to_string(fontWeight->ToNumber<int32_t>());
494 } else {
495 ParseJsString(fontWeight, weight);
496 }
497 textStyle.fontWeight = ConvertStrToFontWeight(weight);
498 }
499 }
500
ParseDate(const JSRef<JSVal> & dateVal)501 PickerDate JSCalendarPicker::ParseDate(const JSRef<JSVal>& dateVal)
502 {
503 auto pickerDate = PickerDate::Current();
504 if (!dateVal->IsObject()) {
505 return pickerDate;
506 }
507 auto dateObj = JSRef<JSObject>::Cast(dateVal);
508 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
509 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
510 auto dateFuncJsVal = dateObj->GetProperty("getDate");
511 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
512 return pickerDate;
513 }
514 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
515 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
516 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
517 JSRef<JSVal> year = yearFunc->Call(dateObj);
518 JSRef<JSVal> month = monthFunc->Call(dateObj);
519 JSRef<JSVal> date = dateFunc->Call(dateObj);
520
521 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
522 pickerDate.SetYear(year->ToNumber<int32_t>());
523 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
524 pickerDate.SetDay(date->ToNumber<int32_t>());
525 }
526 return pickerDate;
527 }
528
JSBind(BindingTarget globalObj)529 void JSCalendarPickerDialog::JSBind(BindingTarget globalObj)
530 {
531 JSClass<JSCalendarPickerDialog>::Declare("CalendarPickerDialog");
532 JSClass<JSCalendarPickerDialog>::StaticMethod("show", &JSCalendarPickerDialog::Show);
533 JSClass<JSCalendarPickerDialog>::Bind<>(globalObj);
534 }
535
Show(const JSCallbackInfo & info)536 void JSCalendarPickerDialog::Show(const JSCallbackInfo& info)
537 {
538 auto scopedDelegate = EngineHelper::GetCurrentDelegateSafely();
539 CHECK_NULL_VOID(scopedDelegate);
540 if (!info[0]->IsObject()) {
541 return;
542 }
543
544 if (Container::IsCurrentUseNewPipeline()) {
545 auto paramObject = JSRef<JSObject>::Cast(info[0]);
546 auto buttonInfos = ParseButtonStyles(paramObject);
547 auto dialogEvent = ChangeDialogEvent(info);
548 auto dialogCancelEvent = DialogCancelEvent(info);
549 auto dialogLifeCycleEvent = LifeCycleDialogEvent(info);
550 CalendarPickerDialogShow(paramObject, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos);
551 }
552 }
553
ChangeDialogEvent(const JSCallbackInfo & info)554 std::map<std::string, NG::DialogEvent> JSCalendarPickerDialog::ChangeDialogEvent(const JSCallbackInfo& info)
555 {
556 std::map<std::string, NG::DialogEvent> dialogEvent;
557 if (!info[0]->IsObject()) {
558 return dialogEvent;
559 }
560 auto paramObject = JSRef<JSObject>::Cast(info[0]);
561 auto onChange = paramObject->GetProperty("onChange");
562 if (!onChange->IsUndefined() && onChange->IsFunction()) {
563 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
564 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
565 auto changeId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
566 const std::string& info) {
567 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
568 ACE_SCORING_EVENT("CalendarDialog.onChange");
569 PipelineContext::SetCallBackNode(node);
570 auto dateObj = JSDate::New(GetMSByDate(info));
571 func->ExecuteJS(1, &dateObj);
572 };
573 dialogEvent["changeId"] = changeId;
574 }
575 auto onAccept = paramObject->GetProperty("onAccept");
576 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
577 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
578 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
579 auto acceptId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
580 const std::string& info) {
581 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
582 ACE_SCORING_EVENT("CalendarDialog.onAccept");
583 PipelineContext::SetCallBackNode(node);
584 auto dateObj = JSDate::New(GetMSByDate(info));
585 func->ExecuteJS(1, &dateObj);
586 };
587 dialogEvent["acceptId"] = acceptId;
588 }
589 return dialogEvent;
590 }
591
DialogCancelEvent(const JSCallbackInfo & info)592 std::map<std::string, NG::DialogGestureEvent> JSCalendarPickerDialog::DialogCancelEvent(const JSCallbackInfo& info)
593 {
594 std::map<std::string, NG::DialogGestureEvent> dialogCancelEvent;
595 if (!info[0]->IsObject()) {
596 return dialogCancelEvent;
597 }
598 auto paramObject = JSRef<JSObject>::Cast(info[0]);
599 auto onCancel = paramObject->GetProperty("onCancel");
600 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
601 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
602 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
603 auto cancelId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
604 const GestureEvent& /* info */) {
605 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
606 ACE_SCORING_EVENT("CalendarDialog.onCancel");
607 PipelineContext::SetCallBackNode(node);
608 func->Execute();
609 };
610 dialogCancelEvent["cancelId"] = cancelId;
611 }
612 return dialogCancelEvent;
613 }
614
AppearDialogEvent(const JSCallbackInfo & info,std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent)615 void AppearDialogEvent(const JSCallbackInfo& info, std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent)
616 {
617 if (!info[0]->IsObject()) {
618 return;
619 }
620 auto paramObject = JSRef<JSObject>::Cast(info[0]);
621 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
622 auto onDidAppear = paramObject->GetProperty("onDidAppear");
623 if (!onDidAppear->IsUndefined() && onDidAppear->IsFunction()) {
624 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidAppear));
625 auto didAppearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
626 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
627 ACE_SCORING_EVENT("CalendarDialog.onDidAppear");
628 PipelineContext::SetCallBackNode(node);
629 func->Execute();
630 };
631 dialogLifeCycleEvent["didAppearId"] = didAppearId;
632 }
633 auto onWillAppear = paramObject->GetProperty("onWillAppear");
634 if (!onWillAppear->IsUndefined() && onWillAppear->IsFunction()) {
635 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillAppear));
636 auto willAppearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
637 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
638 ACE_SCORING_EVENT("CalendarDialog.onWillAppear");
639 PipelineContext::SetCallBackNode(node);
640 func->Execute();
641 };
642 dialogLifeCycleEvent["willAppearId"] = willAppearId;
643 }
644 }
645
DisappearDialogEvent(const JSCallbackInfo & info,std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent)646 void DisappearDialogEvent(
647 const JSCallbackInfo& info, std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent)
648 {
649 if (!info[0]->IsObject()) {
650 return;
651 }
652 auto paramObject = JSRef<JSObject>::Cast(info[0]);
653 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
654 auto onDidDisappear = paramObject->GetProperty("onDidDisappear");
655 if (!onDidDisappear->IsUndefined() && onDidDisappear->IsFunction()) {
656 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidDisappear));
657 auto didDisappearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
658 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
659 ACE_SCORING_EVENT("CalendarDialog.onDidDisappear");
660 PipelineContext::SetCallBackNode(node);
661 func->Execute();
662 };
663 dialogLifeCycleEvent["didDisappearId"] = didDisappearId;
664 }
665 auto onWillDisappear = paramObject->GetProperty("onWillDisappear");
666 if (!onWillDisappear->IsUndefined() && onWillDisappear->IsFunction()) {
667 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillDisappear));
668 auto willDisappearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc),
669 node = targetNode]() {
670 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
671 ACE_SCORING_EVENT("CalendarDialog.onWillDisappear");
672 PipelineContext::SetCallBackNode(node);
673 func->Execute();
674 };
675 dialogLifeCycleEvent["willDisappearId"] = willDisappearId;
676 }
677 }
678
LifeCycleDialogEvent(const JSCallbackInfo & info)679 std::map<std::string, NG::DialogCancelEvent> JSCalendarPickerDialog::LifeCycleDialogEvent(const JSCallbackInfo& info)
680 {
681 std::map<std::string, NG::DialogCancelEvent> dialogLifeCycleEvent;
682 if (!info[0]->IsObject()) {
683 return dialogLifeCycleEvent;
684 }
685 AppearDialogEvent(info, dialogLifeCycleEvent);
686 DisappearDialogEvent(info, dialogLifeCycleEvent);
687 return dialogLifeCycleEvent;
688 }
689
ParseDate(const JSRef<JSVal> & dateVal)690 PickerDate JSCalendarPickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
691 {
692 auto pickerDate = PickerDate();
693 if (!dateVal->IsObject()) {
694 return pickerDate;
695 }
696 auto dateObj = JSRef<JSObject>::Cast(dateVal);
697
698 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
699 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
700 auto dateFuncJsVal = dateObj->GetProperty("getDate");
701 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
702 return pickerDate;
703 }
704 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
705 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
706 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
707 JSRef<JSVal> year = yearFunc->Call(dateObj);
708 JSRef<JSVal> month = monthFunc->Call(dateObj);
709 JSRef<JSVal> date = dateFunc->Call(dateObj);
710
711 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
712 pickerDate.SetYear(year->ToNumber<int32_t>());
713 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
714 pickerDate.SetDay(date->ToNumber<int32_t>());
715 }
716 return pickerDate;
717 }
718
CalendarPickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent,const std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent,const std::vector<ButtonInfo> & buttonInfos)719 void JSCalendarPickerDialog::CalendarPickerDialogShow(const JSRef<JSObject>& paramObj,
720 const std::map<std::string, NG::DialogEvent>& dialogEvent,
721 const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent,
722 const std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent,
723 const std::vector<ButtonInfo>& buttonInfos)
724 {
725 auto container = Container::CurrentSafely();
726 CHECK_NULL_VOID(container);
727 auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
728 CHECK_NULL_VOID(pipelineContext);
729 auto executor = pipelineContext->GetTaskExecutor();
730 CHECK_NULL_VOID(executor);
731
732 auto theme = GetTheme<DialogTheme>();
733 CHECK_NULL_VOID(theme);
734 auto calendarTheme = pipelineContext->GetTheme<CalendarTheme>();
735 NG::CalendarSettingData settingData;
736 auto selectedDate = paramObj->GetProperty("selected");
737 auto parseSelectedDate = ParseDate(selectedDate);
738 if (selectedDate->IsObject() && parseSelectedDate.GetYear() != 0) {
739 settingData.selectedDate = parseSelectedDate;
740 }
741
742 CalcDimension radius;
743 if (ParseJsDimensionVpNG(paramObj->GetProperty("hintRadius"), radius)) {
744 settingData.dayRadius = radius;
745 }
746
747 DialogProperties properties;
748 properties.alignment = theme->GetAlignment();
749 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
750 properties.alignment = DialogAlignment::CENTER;
751 }
752
753 auto backgroundColorValue = paramObj->GetProperty("backgroundColor");
754 Color backgroundColor;
755 if (JSViewAbstract::ParseJsColor(backgroundColorValue, backgroundColor)) {
756 properties.backgroundColor = backgroundColor;
757 }
758
759 auto backgroundBlurStyle = paramObj->GetProperty("backgroundBlurStyle");
760 if (backgroundBlurStyle->IsNumber()) {
761 auto blurStyle = backgroundBlurStyle->ToNumber<int32_t>();
762 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
763 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
764 properties.backgroundBlurStyle = blurStyle;
765 }
766 }
767
768 auto shadowValue = paramObj->GetProperty("shadow");
769 Shadow shadow;
770 if ((shadowValue->IsObject() || shadowValue->IsNumber()) && JSViewAbstract::ParseShadowProps(shadowValue, shadow)) {
771 properties.shadow = shadow;
772 }
773
774 properties.customStyle = false;
775 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
776 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
777 NG::BorderRadiusProperty dialogRadius;
778 dialogRadius.SetRadius(calendarTheme->GetDialogBorderRadius());
779 properties.borderRadius = dialogRadius;
780 }
781 JSViewAbstract::SetDialogHoverModeProperties(paramObj, properties);
782
783 auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
784 auto overlayManager = context ? context->GetOverlayManager() : nullptr;
785 executor->PostTask(
786 [properties, settingData, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos,
787 weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
788 auto overlayManager = weak.Upgrade();
789 CHECK_NULL_VOID(overlayManager);
790 overlayManager->ShowCalendarDialog(
791 properties, settingData, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos);
792 },
793 TaskExecutor::TaskType::UI, "ArkUIDialogShowCalendarPicker");
794 }
795 } // namespace OHOS::Ace::Framework
796