1 /*
2  * Copyright (c) 2021 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/common/dom/dom_calendar.h"
17 
18 #include "frameworks/bridge/common/utils/utils.h"
19 
20 namespace OHOS::Ace::Framework {
21 namespace {
22 
23 constexpr uint32_t METHOD_GO_TO_ARGS_SIZE = 1;
24 const char GO_TO_ARG_KEY_YEAR[] = "year";
25 const char GO_TO_ARG_KEY_MONTH[] = "month";
26 const char GO_TO_ARG_KEY_DAY[] = "day";
27 
28 } // namespace
29 
DomCalendar(NodeId nodeId,const std::string & nodeName)30 DomCalendar::DomCalendar(NodeId nodeId, const std::string& nodeName)
31     : DOMNode(nodeId, nodeName),
32       calendarComponent_(AceType::MakeRefPtr<CalendarComponent>(std::to_string(nodeId), nodeName))
33 {
34     if (IsRightToLeft()) {
35         calendarComponent_->SetTextDirection(TextDirection::RTL);
36     }
37 }
38 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)39 bool DomCalendar::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
40 {
41     static const LinearMapNode<bool (*)(const std::string&, DomCalendar&)> calendarAttrOperators[] = {
42         { DOM_CALENDAR_DATA,
43             [](const std::string& value, DomCalendar& calendar) {
44                 calendar.calendarComponent_->SetCalendarData(value);
45                 return true;
46             } },
47         { DOM_CALENDAR_CARD_CALENDAR,
48             [](const std::string& value, DomCalendar& calendar) {
49                 calendar.calendarComponent_->SetCardCalendar(StringToBool(value));
50                 return true;
51             } },
52         { DOM_CALENDAR_DATE,
53             [](const std::string& value, DomCalendar& calendar) {
54                 CalendarDay day;
55                 auto isLegal = StringUtils::StringToCalendarDay(value, day);
56                 if (isLegal) {
57                     calendar.calendarComponent_->SetCalendarDate(day);
58                     return true;
59                 }
60                 return false;
61             } },
62         { DOM_CALENDAR_DATE_ADAPTER,
63             [](const std::string& value, DomCalendar& calendar) { return calendar.ParseDataAdapter(value); } },
64         { DOM_CALENDAR_DIRECTION,
65             [](const std::string& value, DomCalendar& calendar) {
66               if (value == "vertical") {
67                   calendar.calendarComponent_->SetAxis(Axis::VERTICAL);
68               } else if (value == "horizontal") {
69                   calendar.calendarComponent_->SetAxis(Axis::HORIZONTAL);
70               } else {
71                   LOGW("input do not match any direction");
72               }
73               return true;
74             } },
75         { DOM_CALENDAR_HOLIDAYS,
76             [](const std::string& value, DomCalendar& calendar) {
77                 calendar.calendarComponent_->SetHolidays(value);
78                 return true;
79             } },
80         { DOM_CALENDAR_OFF_DAYS,
81             [](const std::string& value, DomCalendar& calendar) {
82                 calendar.calendarComponent_->SetOffDays(value);
83                 return true;
84             } },
85         { DOM_CALENDAR_SHOW_HOLIDAY,
86             [](const std::string& value, DomCalendar& calendar) {
87                 calendar.calendarComponent_->SetShowHoliday(StringToBool(value));
88                 return true;
89             } },
90         { DOM_CALENDAR_SHOW_LUNAR,
91             [](const std::string& value, DomCalendar& calendar) {
92                 calendar.calendarComponent_->SetShowLunar(StringToBool(value));
93                 return true;
94             } },
95         { DOM_CALENDAR_START_DAY_OF_WEEK,
96             [](const std::string& value, DomCalendar& calendar) {
97                 auto indexOfWeek = StringToInt(value);
98                 if (0 <= indexOfWeek && indexOfWeek < 7) {
99                     calendar.calendarComponent_->SetStartDayOfWeek(indexOfWeek);
100                     return true;
101                 }
102                 return false;
103             } },
104         { DOM_CALENDAR_TYPE,
105             [](const std::string& value, DomCalendar& calendar) {
106                 if (value == "normal") {
107                     calendar.calendarComponent_->SetCalendarType(CalendarType::NORMAL);
108                 } else if (value == "simple") {
109                     calendar.calendarComponent_->SetCalendarType(CalendarType::SIMPLE);
110                 }
111                 return true;
112             } },
113         { DOM_CALENDAR_WORK_DAYS,
114             [](const std::string& value, DomCalendar& calendar) {
115                 calendar.calendarComponent_->SetWorkDays(value);
116                 return true;
117             } },
118     };
119     auto operatorIter =
120         BinarySearchFindIndex(calendarAttrOperators, ArraySize(calendarAttrOperators), attr.first.c_str());
121     if (operatorIter != -1) {
122         return calendarAttrOperators[operatorIter].value(attr.second, *this);
123     }
124     return false;
125 }
126 
CallSpecializedMethod(const std::string & method,const std::string & args)127 void DomCalendar::CallSpecializedMethod(const std::string& method, const std::string& args)
128 {
129     if (method == DOM_CALENDAR_METHOD_GO_TO) {
130         HandleGoTo(args);
131     }
132 }
133 
AddSpecializedEvent(int32_t pageId,const std::string & event)134 bool DomCalendar::AddSpecializedEvent(int32_t pageId, const std::string& event)
135 {
136     if (event == DOM_CALENDAR_EVENT_SELECTED_CHANGE) {
137         selectedChangeEvent_ = EventMarker(GetNodeIdForEvent(), event, pageId);
138         calendarComponent_->SetSelectedChangeEvent(selectedChangeEvent_);
139         return true;
140     } else if (event == DOM_CALENDAR_EVENT_REQUEST_DATA) {
141         requestDataEvent_ = EventMarker(GetNodeIdForEvent(), event, pageId);
142         calendarComponent_->SetRequestDataEvent(requestDataEvent_);
143         return true;
144     }
145     return false;
146 }
147 
ParseDataAdapter(const std::string & value)148 bool DomCalendar::ParseDataAdapter(const std::string& value)
149 {
150     std::unique_ptr<JsonValue> dataAdapterValue = JsonUtil::ParseJsonString(value);
151     if (!dataAdapterValue) {
152         return false;
153     }
154     std::unique_ptr<JsonValue> bundleNameValue = dataAdapterValue->GetValue("bundleName");
155     if (!bundleNameValue || !bundleNameValue->IsString()) {
156         return false;
157     }
158     std::unique_ptr<JsonValue> abilityNameValue = dataAdapterValue->GetValue("abilityName");
159     if (!abilityNameValue || !abilityNameValue->IsString()) {
160         return false;
161     }
162     std::unique_ptr<JsonValue> messageCodeValue = dataAdapterValue->GetValue("messageCode");
163     if (!messageCodeValue || !messageCodeValue->IsNumber()) {
164         return false;
165     }
166     std::string bundleName = bundleNameValue->GetString();
167     std::string abilityName = abilityNameValue->GetString();
168     int32_t messageCode = messageCodeValue->GetInt();
169     CalendarDataAdapterAction dataAdapterAction {
170         { .bundleName = bundleName, .abilityName = abilityName, .messageCode = messageCode }
171     };
172     calendarComponent_->SetDataAdapterAction(dataAdapterAction);
173     return true;
174 }
175 
HandleGoTo(const std::string & args)176 void DomCalendar::HandleGoTo(const std::string& args)
177 {
178     std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
179     if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != METHOD_GO_TO_ARGS_SIZE) {
180         return;
181     }
182     auto gotoArg = argsValue->GetArrayItem(0);
183     if (!gotoArg || !gotoArg->Contains(GO_TO_ARG_KEY_YEAR) || !gotoArg->Contains(GO_TO_ARG_KEY_MONTH)) {
184         return;
185     }
186 
187     std::unique_ptr<JsonValue> yearValue = gotoArg->GetValue(GO_TO_ARG_KEY_YEAR);
188     if (!yearValue || !yearValue->IsNumber()) {
189         return;
190     }
191 
192     std::unique_ptr<JsonValue> monthValue = gotoArg->GetValue(GO_TO_ARG_KEY_MONTH);
193     if (!monthValue || !monthValue->IsNumber()) {
194         return;
195     }
196     int32_t year = yearValue->GetInt();
197     int32_t month = monthValue->GetInt();
198     // default selected first day of month
199     int32_t day = -1;
200 
201     std::unique_ptr<JsonValue> dayValue = gotoArg->GetValue(GO_TO_ARG_KEY_DAY);
202     if (dayValue && dayValue->IsNumber()) {
203         day = dayValue->GetInt();
204     }
205     calendarComponent_->GoTo(year, month, day);
206 }
207 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)208 bool DomCalendar::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
209 {
210     static const LinearMapNode<void (*)(const std::string&, CalendarThemeStructure&, const DomCalendar&)>
211         calendarStyleOperators[] = {
212             { "boundaryColumnOffset",
213                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
214                     theme.boundaryColOffset = node.ParseDimension(value);
215                 } },
216             { "boundaryRowOffset",
217                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
218                     theme.boundaryRowOffset = node.ParseDimension(value);
219                 } },
220             { "columnSpace", [](const std::string& value, CalendarThemeStructure& theme,
221                                  const DomCalendar& node) { theme.colSpace = node.ParseDimension(value); } },
222             { "dailyFiveRowSpace",
223                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
224                     theme.dailyFiveRowSpace = node.ParseDimension(value);
225                 } },
226             { "dailySixRowSpace",
227                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
228                     theme.dailySixRowSpace = node.ParseDimension(value);
229                 } },
230             { "dayColor", [](const std::string& value, CalendarThemeStructure& theme,
231                               const DomCalendar& node) { theme.dayColor = node.ParseColor(value); } },
232             { "dayFontSize", [](const std::string& value, CalendarThemeStructure& theme,
233                                  const DomCalendar& node) { theme.dayFontSize = node.ParseDimension(value); } },
234             { "dayHeight", [](const std::string& value, CalendarThemeStructure& theme,
235                                const DomCalendar& node) { theme.dayHeight = node.ParseDimension(value); } },
236             { "dayWidth", [](const std::string& value, CalendarThemeStructure& theme,
237                               const DomCalendar& node) { theme.dayWidth = node.ParseDimension(value); } },
238             { "dayYAxisOffset", [](const std::string& value, CalendarThemeStructure& theme,
239                                     const DomCalendar& node) { theme.dayYAxisOffset = node.ParseDimension(value); } },
240             { "focusedAreaBackgroundColor",
241                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
242                     theme.focusedAreaBackgroundColor = node.ParseColor(value);
243                 } },
244             { "focusedAreaRadius",
245                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
246                     theme.focusedAreaRadius = node.ParseDimension(value);
247                 } },
248             { "focusedDayColor", [](const std::string& value, CalendarThemeStructure& theme,
249                                      const DomCalendar& node) { theme.focusedDayColor = node.ParseColor(value); } },
250             { "focusedLunarColor", [](const std::string& value, CalendarThemeStructure& theme,
251                                        const DomCalendar& node) { theme.focusedLunarColor = node.ParseColor(value); } },
252             { "gregorianCalendarHeight",
253                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
254                     theme.gregorianCalendarHeight = node.ParseDimension(value);
255                 } },
256             { "lunarColor", [](const std::string& value, CalendarThemeStructure& theme,
257                                 const DomCalendar& node) { theme.lunarColor = node.ParseColor(value); } },
258             { "lunarDayFontSize",
259                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
260                     theme.lunarDayFontSize = node.ParseDimension(value);
261                 } },
262             { "lunarDayYAxisOffset",
263                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
264                     theme.lunarDayYAxisOffset = node.ParseDimension(value);
265                 } },
266             { "lunarHeight", [](const std::string& value, CalendarThemeStructure& theme,
267                                  const DomCalendar& node) { theme.lunarHeight = node.ParseDimension(value); } },
268             { "markLunarColor", [](const std::string& value, CalendarThemeStructure& theme,
269                                     const DomCalendar& node) { theme.markLunarColor = node.ParseColor(value); } },
270             { "nonCurrentMonthDayColor",
271                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
272                     theme.nonCurrentMonthDayColor = node.ParseColor(value);
273                 } },
274             { "nonCurrentMonthLunarColor",
275                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
276                     theme.nonCurrentMonthLunarColor = node.ParseColor(value);
277                 } },
278             { "nonCurrentMonthOffDayMarkColor",
279                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
280                     theme.nonCurrentMonthOffDayMarkColor = node.ParseColor(value);
281                 } },
282             { "nonCurrentMonthWorkDayMarkColor",
283                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
284                     theme.nonCurrentMonthWorkDayMarkColor = node.ParseColor(value);
285                 } },
286             { "offDayMarkColor", [](const std::string& value, CalendarThemeStructure& theme,
287                                      const DomCalendar& node) { theme.offDayMarkColor = node.ParseColor(value); } },
288             { "offDayMarkSize", [](const std::string& value, CalendarThemeStructure& theme,
289                                     const DomCalendar& node) { theme.offDayMarkSize = node.ParseDimension(value); } },
290             { "scheduleMarkerRadius",
291                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
292                     theme.scheduleMarkerRadius = node.ParseDimension(value);
293                 } },
294             { "scheduleMarkerXAxisOffset",
295                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
296                     theme.scheduleMarkerXAxisOffset = node.ParseDimension(value);
297                 } },
298             { "scheduleMarkerYAxisOffset",
299                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
300                     theme.scheduleMarkerYAxisOffset = node.ParseDimension(value);
301                 } },
302             { "simpleOffTextColor",
303                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
304                     theme.simpleOffTextColor = node.ParseColor(value);
305                 } },
306             { "simpleWorkTextColor",
307                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
308                     theme.simpleWorkTextColor = node.ParseColor(value);
309                 } },
310             { "underscoreLength",
311                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
312                     theme.underscoreLength = node.ParseDimension(value);
313                 } },
314             { "underscoreWidth", [](const std::string& value, CalendarThemeStructure& theme,
315                                      const DomCalendar& node) { theme.underscoreWidth = node.ParseDimension(value); } },
316             { "underscoreXAxisOffset",
317                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
318                     theme.underscoreXAxisOffset = node.ParseDimension(value);
319                 } },
320             { "underscoreYAxisOffset",
321                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
322                     theme.underscoreYAxisOffset = node.ParseDimension(value);
323                 } },
324             { "weekAndDayRowSpace",
325                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
326                     theme.weekAndDayRowSpace = node.ParseDimension(value);
327                 } },
328             { "weekColor", [](const std::string& value, CalendarThemeStructure& theme,
329                                const DomCalendar& node) { theme.weekColor = node.ParseColor(value); } },
330             { "weekFontSize", [](const std::string& value, CalendarThemeStructure& theme,
331                                   const DomCalendar& node) { theme.weekFontSize = node.ParseDimension(value); } },
332             { "weekHeight", [](const std::string& value, CalendarThemeStructure& theme,
333                                 const DomCalendar& node) { theme.weekHeight = node.ParseDimension(value); } },
334             { "weekWidth", [](const std::string& value, CalendarThemeStructure& theme,
335                                const DomCalendar& node) { theme.weekWidth = node.ParseDimension(value); } },
336             { "weekendDayColor", [](const std::string& value, CalendarThemeStructure& theme,
337                                      const DomCalendar& node) { theme.weekendDayColor = node.ParseColor(value); } },
338             { "weekendLunarColor", [](const std::string& value, CalendarThemeStructure& theme,
339                                        const DomCalendar& node) { theme.weekendLunarColor = node.ParseColor(value); } },
340             { "workDayMarkColor", [](const std::string& value, CalendarThemeStructure& theme,
341                                       const DomCalendar& node) { theme.workDayMarkColor = node.ParseColor(value); } },
342             { "workDayMarkSize", [](const std::string& value, CalendarThemeStructure& theme,
343                                      const DomCalendar& node) { theme.workDayMarkSize = node.ParseDimension(value); } },
344             { "workStateHorizontalMovingDistance",
345                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
346                     theme.workStateHorizontalMovingDistance = node.ParseDimension(value);
347                 } },
348             { "workStateOffset", [](const std::string& value, CalendarThemeStructure& theme,
349                                      const DomCalendar& node) { theme.workStateOffset = node.ParseDimension(value); } },
350             { "workStateVerticalMovingDistance",
351                 [](const std::string& value, CalendarThemeStructure& theme, const DomCalendar& node) {
352                     theme.workStateVerticalMovingDistance = node.ParseDimension(value);
353                 } },
354             { "workStateWidth", [](const std::string& value, CalendarThemeStructure& theme,
355                                     const DomCalendar& node) { theme.workStateWidth = node.ParseDimension(value); } },
356         };
357     auto context = GetPipelineContext().Upgrade();
358     if (!context) {
359         return false;
360     }
361     auto theme = calendarComponent_->GetCalendarTheme();
362     if (!theme) {
363         theme = GetTheme<CalendarTheme>();
364         calendarComponent_->SetCalendarTheme(theme);
365     }
366     auto operatorIter =
367         BinarySearchFindIndex(calendarStyleOperators, ArraySize(calendarStyleOperators), style.first.c_str());
368     if (operatorIter != -1) {
369         auto& calendarTheme = context->IsJsCard() ? theme->GetCardCalendarTheme() : theme->GetCalendarTheme();
370         calendarStyleOperators[operatorIter].value(style.second, calendarTheme, *this);
371         return true;
372     }
373     return false;
374 }
375 
376 } // namespace OHOS::Ace::Framework
377