• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_indexer.h"
17 
18 #include "base/geometry/dimension.h"
19 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
20 #include "bridge/declarative_frontend/jsview/js_scroller.h"
21 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
22 #include "bridge/declarative_frontend/view_stack_processor.h"
23 #include "core/components_ng/pattern/indexer/indexer_event_hub.h"
24 #include "core/components_ng/pattern/indexer/indexer_theme.h"
25 #include "core/components_ng/pattern/indexer/indexer_view.h"
26 #include "core/components_v2/indexer/indexer_component.h"
27 #include "core/components_v2/indexer/indexer_event_info.h"
28 #include "core/components_v2/indexer/render_indexer.h"
29 
30 namespace OHOS::Ace::Framework {
31 namespace {
32 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
33 const std::vector<V2::AlignStyle> ALIGN_STYLE = { V2::AlignStyle::LEFT, V2::AlignStyle::RIGHT };
34 const std::vector<NG::AlignStyle> NG_ALIGN_STYLE = {NG::AlignStyle::LEFT, NG::AlignStyle::RIGHT};
35 }; // namespace
36 
Create(const JSCallbackInfo & args)37 void JSIndexer::Create(const JSCallbackInfo& args)
38 {
39     if (args.Length() >= 1 && args[0]->IsObject()) {
40         auto param = JsonUtil::ParseJsonString(args[0]->ToString());
41         if (!param || param->IsNull()) {
42             LOGE("JSIndexer::Create param is null");
43             return;
44         }
45         std::vector<std::string> indexerArray;
46 
47         auto arrayVal = param->GetValue("arrayValue");
48         if (!arrayVal || !arrayVal->IsArray()) {
49             LOGW("info is invalid");
50             return;
51         }
52 
53         size_t length = static_cast<uint32_t>(arrayVal->GetArraySize());
54         if (length <= 0) {
55             LOGE("info is invalid");
56             return;
57         }
58         for (size_t i = 0; i < length; i++) {
59             auto value = arrayVal->GetArrayItem(i);
60             if (!value) {
61                 return;
62             }
63             indexerArray.emplace_back(value->GetString());
64         }
65 
66         auto selectedVal = param->GetInt("selected", 0);
67 
68         if (Container::IsCurrentUseNewPipeline()) {
69             NG::IndexerView::Create(indexerArray, selectedVal);
70             return;
71         }
72 
73         auto indexerComponent =
74             AceType::MakeRefPtr<V2::IndexerComponent>(indexerArray, selectedVal);
75         ViewStackProcessor::GetInstance()->ClaimElementId(indexerComponent);
76         ViewStackProcessor::GetInstance()->Push(indexerComponent);
77         JSInteractableView::SetFocusable(true);
78         JSInteractableView::SetFocusNode(true);
79         args.ReturnSelf();
80     }
81 }
82 
SetSelectedColor(const JSCallbackInfo & args)83 void JSIndexer::SetSelectedColor(const JSCallbackInfo& args)
84 {
85     if (args.Length() < 1) {
86         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
87         return;
88     }
89     Color color;
90     if (!ParseJsColor(args[0], color)) {
91         return;
92     }
93     if (Container::IsCurrentUseNewPipeline()) {
94         NG::IndexerView::SetSelectedColor(color);
95         return;
96     }
97     auto indexerComponent =
98         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
99     if (indexerComponent) {
100         auto textStyle = indexerComponent->GetActiveTextStyle();
101         textStyle.SetTextColor(color);
102         indexerComponent->SetActiveTextStyle(std::move(textStyle));
103     }
104 }
105 
SetColor(const JSCallbackInfo & args)106 void JSIndexer::SetColor(const JSCallbackInfo& args)
107 {
108     if (args.Length() < 1) {
109         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
110         return;
111     }
112     Color color;
113     if (!ParseJsColor(args[0], color)) {
114         return;
115     }
116     if (Container::IsCurrentUseNewPipeline()) {
117         NG::IndexerView::SetColor(color);
118         return;
119     }
120     auto indexerComponent =
121         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
122     if (indexerComponent) {
123         auto textStyle = indexerComponent->GetNormalTextStyle();
124         textStyle.SetTextColor(color);
125         indexerComponent->SetNormalTextStyle(std::move(textStyle));
126     }
127 }
128 
SetPopupColor(const JSCallbackInfo & args)129 void JSIndexer::SetPopupColor(const JSCallbackInfo& args)
130 {
131     if (args.Length() < 1) {
132         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
133         return;
134     }
135     Color color;
136     if (!ParseJsColor(args[0], color)) {
137         return;
138     }
139     if (Container::IsCurrentUseNewPipeline()) {
140         NG::IndexerView::SetPopupColor(color);
141         return;
142     }
143     auto indexerComponent =
144         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
145     if (indexerComponent) {
146         auto textStyle = indexerComponent->GetBubbleTextStyle();
147         textStyle.SetTextColor(color);
148         indexerComponent->SetBubbleTextStyle(std::move(textStyle));
149     }
150 }
151 
SetSelectedBackgroundColor(const JSCallbackInfo & args)152 void JSIndexer::SetSelectedBackgroundColor(const JSCallbackInfo& args)
153 {
154     if (args.Length() < 1) {
155         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
156         return;
157     }
158     Color color;
159     if (!ParseJsColor(args[0], color)) {
160         return;
161     }
162     if (Container::IsCurrentUseNewPipeline()) {
163         NG::IndexerView::SetSelectedBackgroundColor(color);
164         return;
165     }
166     auto indexerComponent =
167         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
168     if (indexerComponent) {
169         indexerComponent->SetSelectedBackgroundColor(color);
170     }
171 }
172 
SetPopupBackground(const JSCallbackInfo & args)173 void JSIndexer::SetPopupBackground(const JSCallbackInfo& args)
174 {
175     if (args.Length() < 1) {
176         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
177         return;
178     }
179     Color color;
180     if (!ParseJsColor(args[0], color)) {
181         return;
182     }
183     if (Container::IsCurrentUseNewPipeline()) {
184         NG::IndexerView::SetPopupBackground(color);
185         return;
186     }
187     auto indexerComponent =
188         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
189     if (indexerComponent) {
190         indexerComponent->SetBubbleBackgroundColor(color);
191     }
192 }
193 
SetUsingPopup(bool state)194 void JSIndexer::SetUsingPopup(bool state)
195 {
196     if (Container::IsCurrentUseNewPipeline()) {
197         NG::IndexerView::SetUsingPopup(state);
198         return;
199     }
200     auto indexerComponent =
201         AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
202     if (indexerComponent) {
203         indexerComponent->SetBubbleEnabled(state);
204     }
205 }
206 
SetSelectedFont(const JSCallbackInfo & args)207 void JSIndexer::SetSelectedFont(const JSCallbackInfo& args)
208 {
209     if (Container::IsCurrentUseNewPipeline()) {
210         if (args.Length() >= 1 && args[0]->IsObject()) {
211             TextStyle textStyle;
212             GetFontContent(args, textStyle);
213             NG::IndexerView::SetSelectedFont(textStyle);
214         }
215         return;
216     }
217     if (args.Length() >= 1 && args[0]->IsObject()) {
218         auto indexerComponent =
219             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
220         if (indexerComponent) {
221             auto textStyle = indexerComponent->GetActiveTextStyle();
222             GetFontContent(args, textStyle);
223             indexerComponent->SetActiveTextStyle(std::move(textStyle));
224         }
225     }
226 }
227 
SetPopupFont(const JSCallbackInfo & args)228 void JSIndexer::SetPopupFont(const JSCallbackInfo& args)
229 {
230     if (Container::IsCurrentUseNewPipeline()) {
231         if (args.Length() >= 1 && args[0]->IsObject()) {
232             TextStyle textStyle;
233             GetFontContent(args, textStyle);
234             NG::IndexerView::SetPopupFont(textStyle);
235         }
236         return;
237     }
238     if (args.Length() >= 1 && args[0]->IsObject()) {
239         auto indexerComponent =
240             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
241         if (indexerComponent) {
242             auto textStyle = indexerComponent->GetBubbleTextStyle();
243             GetFontContent(args, textStyle);
244             indexerComponent->SetBubbleTextStyle(std::move(textStyle));
245         }
246     }
247 }
248 
SetFont(const JSCallbackInfo & args)249 void JSIndexer::SetFont(const JSCallbackInfo& args)
250 {
251     if (Container::IsCurrentUseNewPipeline()) {
252         if (args.Length() >= 1 && args[0]->IsObject()) {
253             TextStyle textStyle;
254             GetFontContent(args, textStyle);
255             NG::IndexerView::SetFont(textStyle);
256         }
257         return;
258     }
259     if (args.Length() >= 1 && args[0]->IsObject()) {
260         auto indexerComponent =
261             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
262         if (indexerComponent) {
263             auto textStyle = indexerComponent->GetNormalTextStyle();
264             GetFontContent(args, textStyle);
265             indexerComponent->SetNormalTextStyle(std::move(textStyle));
266         }
267     }
268 }
269 
JsOnSelected(const JSCallbackInfo & args)270 void JSIndexer::JsOnSelected(const JSCallbackInfo& args)
271 {
272     if (Container::IsCurrentUseNewPipeline()) {
273         if (args[0]->IsFunction()) {
274             auto onSelected = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](const int32_t selected) {
275                 JAVASCRIPT_EXECUTION_SCOPE(execCtx);
276                 auto params = ConvertToJSValues(selected);
277                 func->Call(JSRef<JSObject>(), params.size(), params.data());
278             };
279             NG::IndexerView::SetOnSelected(onSelected);
280         }
281         return;
282     }
283     if (args[0]->IsFunction()) {
284         auto onSelected = EventMarker(
285             [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](const BaseEventInfo* info) {
286                 JAVASCRIPT_EXECUTION_SCOPE(execCtx);
287                 auto eventInfo = TypeInfoHelper::DynamicCast<V2::IndexerEventInfo>(info);
288                 if (!eventInfo) {
289                     return;
290                 }
291                 auto params = ConvertToJSValues(eventInfo->GetSelectedIndex());
292                 func->Call(JSRef<JSObject>(), params.size(), params.data());
293             });
294 
295         auto indexerComponent =
296             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
297         if (indexerComponent) {
298             indexerComponent->SetSelectedEvent(onSelected);
299         }
300     }
301 }
302 
JsOnRequestPopupData(const JSCallbackInfo & args)303 void JSIndexer::JsOnRequestPopupData(const JSCallbackInfo& args)
304 {
305     if (Container::IsCurrentUseNewPipeline()) {
306         if (args[0]->IsFunction()) {
307             auto requestPopupData = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]
308                 (const int32_t selected) {
309                     std::vector<std::string> popupData;
310                     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, popupData);
311                     auto params = ConvertToJSValues(selected);
312                     JSRef<JSArray> result = func->Call(JSRef<JSObject>(), params.size(), params.data());
313                     if (result.IsEmpty()) {
314                         LOGE("Error calling onRequestPopupData result is empty.");
315                         return popupData;
316                     }
317 
318                     if (!result->IsArray()) {
319                         LOGE("Error calling onRequestPopupData result is not array.");
320                         return popupData;
321                     }
322 
323                     for (size_t i = 0; i < result->Length(); i++) {
324                         if (result->GetValueAt(i)->IsString()) {
325                             auto item = result->GetValueAt(i);
326                             popupData.emplace_back(item->ToString());
327                         } else {
328                             LOGE("Error calling onRequestPopupData index %{public}zu is not string.", i);
329                         }
330                     }
331                     return popupData;
332             };
333             NG::IndexerView::SetOnRequestPopupData(requestPopupData);
334         }
335         return;
336     }
337     if (args[0]->IsFunction()) {
338         auto requestPopupData =
339             [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]
340             (std::shared_ptr<V2::IndexerEventInfo> info) {
341                     std::vector<std::string> popupData;
342                     JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, popupData);
343                     auto params = ConvertToJSValues(info->GetSelectedIndex());
344                     JSRef<JSArray> result = func->Call(JSRef<JSObject>(), params.size(), params.data());
345                     if (result.IsEmpty()) {
346                         LOGE("Error calling onRequestPopupData result is empty.");
347                         return popupData;
348                     }
349 
350                     if (!result->IsArray()) {
351                         LOGE("Error calling onRequestPopupData result is not array.");
352                         return popupData;
353                     }
354 
355                     for (size_t i = 0; i < result->Length(); i++) {
356                         if (result->GetValueAt(i)->IsString()) {
357                             auto item = result->GetValueAt(i);
358                             popupData.emplace_back(item->ToString());
359                         } else {
360                             LOGE("Error calling onRequestPopupData index %{public}zu is not string.", i);
361                         }
362                     }
363                     return popupData;
364             };
365 
366         auto indexerComponent =
367             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
368         if (indexerComponent) {
369             indexerComponent->SetRequestPopupDataFunc(requestPopupData);
370         }
371     }
372 }
373 
JsOnPopupSelected(const JSCallbackInfo & args)374 void JSIndexer::JsOnPopupSelected(const JSCallbackInfo& args)
375 {
376     if (Container::IsCurrentUseNewPipeline()) {
377         if (args[0]->IsFunction()) {
378             auto onPopupSelected = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](const int32_t selected) {
379                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
380                 auto params = ConvertToJSValues(selected);
381                 func->Call(JSRef<JSObject>(), params.size(), params.data());
382             };
383             NG::IndexerView::SetOnPopupSelected(onPopupSelected);
384         }
385         return;
386     }
387     if (args[0]->IsFunction()) {
388         auto onPopupSelected = EventMarker(
389             [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](const BaseEventInfo* info) {
390                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
391                 auto eventInfo = TypeInfoHelper::DynamicCast<V2::IndexerEventInfo>(info);
392                 if (!eventInfo) {
393                     return;
394                 }
395                 auto params = ConvertToJSValues(eventInfo->GetSelectedIndex());
396                 func->Call(JSRef<JSObject>(), params.size(), params.data());
397             });
398 
399         auto indexerComponent =
400             AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
401         if (indexerComponent) {
402             indexerComponent->SetPopupSelectedEvent(onPopupSelected);
403         }
404     }
405 }
406 
GetFontContent(const JSCallbackInfo & args,TextStyle & textStyle)407 void JSIndexer::GetFontContent(const JSCallbackInfo& args, TextStyle& textStyle)
408 {
409     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
410     JSRef<JSVal> size = obj->GetProperty("size");
411     Dimension fontSize;
412     if (ParseJsDimensionVp(size, fontSize)) {
413         textStyle.SetFontSize(fontSize);
414     }
415 
416     JSRef<JSVal> weight = obj->GetProperty("weight");
417     if (weight->IsString()) {
418         textStyle.SetFontWeight(ConvertStrToFontWeight(weight->ToString()));
419     }
420 
421     JSRef<JSVal> family = obj->GetProperty("family");
422     std::vector<std::string> fontFamilies;
423     if (ParseJsFontFamilies(family, fontFamilies)) {
424         textStyle.SetFontFamilies(fontFamilies);
425     }
426 
427     JSRef<JSVal> style = obj->GetProperty("style");
428     if (style->IsNumber()) {
429         int32_t value = style->ToNumber<int32_t>();
430         if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
431             textStyle.SetFontStyle(FONT_STYLES[value]);
432         }
433     }
434 }
435 
SetItemSize(const JSCallbackInfo & args)436 void JSIndexer::SetItemSize(const JSCallbackInfo& args)
437 {
438     if (Container::IsCurrentUseNewPipeline()) {
439         if (args.Length() >= 1) {
440             Dimension value;
441             if (ParseJsDimensionVp(args[0], value)) {
442                 NG::IndexerView::SetItemSize(value);
443             }
444         }
445     }
446     if (args.Length() >= 1) {
447         Dimension value;
448         if (ParseJsDimensionVp(args[0], value)) {
449             auto indexerComponent =
450                 AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
451             if (indexerComponent) {
452                 indexerComponent->SetItemSize(value);
453             }
454         }
455     }
456 }
457 
SetAlignStyle(int32_t value)458 void JSIndexer::SetAlignStyle(int32_t value)
459 {
460     if (Container::IsCurrentUseNewPipeline()) {
461         if (value >= 0 && value < static_cast<int32_t>(ALIGN_STYLE.size())) {
462             NG::IndexerView::SetAlignStyle(NG_ALIGN_STYLE[value]);
463         }
464     }
465     if (value >= 0 && value < static_cast<int32_t>(ALIGN_STYLE.size())) {
466         auto indexerComponent =
467                 AceType::DynamicCast<V2::IndexerComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
468         if (indexerComponent) {
469             indexerComponent->SetAlignStyle(ALIGN_STYLE[value]);
470         }
471     }
472 }
473 
SetSelected(const JSCallbackInfo & args)474 void JSIndexer::SetSelected(const JSCallbackInfo& args)
475 {
476     if (Container::IsCurrentUseNewPipeline()) {
477         if (args.Length() >= 1) {
478             int32_t selected = 0;
479             if (ParseJsInteger<int32_t>(args[0], selected)) {
480                 NG::IndexerView::SetSelected(selected);
481             }
482         }
483     }
484 }
485 
SetPopupPosition(const JSCallbackInfo & args)486 void JSIndexer::SetPopupPosition(const JSCallbackInfo& args)
487 {
488     if (Container::IsCurrentUseNewPipeline()) {
489         if (args.Length() >= 1) {
490             JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
491             float positionX = 0.0f;
492             float positionY = 0.0f;
493             if (ConvertFromJSValue(obj->GetProperty("x"), positionX)) {
494                 NG::IndexerView::SetPopupPositionX(Dimension(positionX, DimensionUnit::VP));
495             }
496             if (ConvertFromJSValue(obj->GetProperty("y"), positionY)) {
497                 NG::IndexerView::SetPopupPositionY(Dimension(positionY, DimensionUnit::VP));
498             }
499         }
500     }
501 }
502 
JSBind(BindingTarget globalObj)503 void JSIndexer::JSBind(BindingTarget globalObj)
504 {
505     MethodOptions opt = MethodOptions::NONE;
506     JSClass<JSIndexer>::Declare("AlphabetIndexer");
507     JSClass<JSIndexer>::StaticMethod("create", &JSIndexer::Create);
508     // API7 onSelected deprecated
509     JSClass<JSIndexer>::StaticMethod("onSelected", &JSIndexer::JsOnSelected);
510     JSClass<JSIndexer>::StaticMethod("onSelect", &JSIndexer::JsOnSelected);
511     JSClass<JSIndexer>::StaticMethod("color", &JSIndexer::SetColor, opt);
512     JSClass<JSIndexer>::StaticMethod("selectedColor", &JSIndexer::SetSelectedColor, opt);
513     JSClass<JSIndexer>::StaticMethod("popupColor", &JSIndexer::SetPopupColor, opt);
514     JSClass<JSIndexer>::StaticMethod("selectedBackgroundColor", &JSIndexer::SetSelectedBackgroundColor, opt);
515     JSClass<JSIndexer>::StaticMethod("popupBackground", &JSIndexer::SetPopupBackground, opt);
516     JSClass<JSIndexer>::StaticMethod("usingPopup", &JSIndexer::SetUsingPopup, opt);
517     JSClass<JSIndexer>::StaticMethod("selectedFont", &JSIndexer::SetSelectedFont);
518     JSClass<JSIndexer>::StaticMethod("font", &JSIndexer::SetFont);
519     JSClass<JSIndexer>::StaticMethod("popupFont", &JSIndexer::SetPopupFont);
520     JSClass<JSIndexer>::StaticMethod("itemSize", &JSIndexer::SetItemSize, opt);
521     JSClass<JSIndexer>::StaticMethod("alignStyle", &JSIndexer::SetAlignStyle, opt);
522     JSClass<JSIndexer>::StaticMethod("onRequestPopupData", &JSIndexer::JsOnRequestPopupData, opt);
523     JSClass<JSIndexer>::StaticMethod("selected", &JSIndexer::SetSelected, opt);
524     JSClass<JSIndexer>::StaticMethod("popupPosition", &JSIndexer::SetPopupPosition, opt);
525     // keep compatible, need remove after
526     JSClass<JSIndexer>::StaticMethod("onPopupSelected", &JSIndexer::JsOnPopupSelected, opt);
527     JSClass<JSIndexer>::StaticMethod("onPopupSelect", &JSIndexer::JsOnPopupSelected, opt);
528     JSClass<JSIndexer>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
529     JSClass<JSIndexer>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
530     JSClass<JSIndexer>::Inherit<JSViewAbstract>();
531     JSClass<JSIndexer>::Bind(globalObj);
532 }
533 } // namespace OHOS::Ace::Framework
534