• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_list.h"
17 
18 #include "base/log/event_report.h"
19 #include "base/utils/linear_map.h"
20 #include "base/utils/utils.h"
21 #include "core/components/list/list_theme.h"
22 #include "core/components/scroll/scroll_bar_theme.h"
23 #include "core/components/scroll/scroll_fade_effect.h"
24 #include "core/components/scroll/scroll_spring_effect.h"
25 #include "core/components/theme/theme_manager.h"
26 #include "frameworks/bridge/common/dom/dom_list_item.h"
27 #include "frameworks/bridge/common/dom/dom_list_item_group.h"
28 #include "frameworks/bridge/common/utils/utils.h"
29 
30 namespace OHOS::Ace::Framework {
31 namespace {
32 
33 constexpr int32_t DEFAULT_NODE_INDEX = -1;
34 constexpr char INDEXER_ALPHABET_DIV = 10; // newline character
35 
36 } // namespace
37 
DOMList(NodeId nodeId,const std::string & nodeName)38 DOMList::DOMList(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName) {}
39 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)40 bool DOMList::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
41 {
42     // static linear map must be sorted by key.
43     static const LinearMapNode<void (*)(DOMList&, const std::string&)> attrOperators[] = {
44         {
45             DOM_LIST_ACCESSIBILITY_DISABLED,
46             [](DOMList& list, const std::string& val) { list.accessibilityDisabled_ = StringToBool(val); },
47         },
48         {
49             LIST_BEGIN_INDEX,
50             [](DOMList& list, const std::string& val) { list.beginIndex_ = StringUtils::StringToInt(val); },
51         },
52         {
53             LIST_CACHED_COUNT,
54             [](DOMList& list, const std::string& val) { list.cachedCount_ = StringUtils::StringToInt(val); },
55         },
56         {
57             DOM_LIST_CENTER_LAYOUT,
58             [](DOMList& list, const std::string& val) { list.centerLayout_ = StringToBool(val); },
59         },
60         {
61             DOM_LIST_CHAIN_ANIMATION,
62             [](DOMList& list, const std::string& val) { list.chainAnimation_ = StringToBool(val); },
63         },
64         {
65             DOM_LIST_DIVIDER,
66             [](DOMList& list, const std::string& val) { list.needDivider_ = StringToBool(val); },
67         },
68         {
69             LIST_END_INDEX,
70             [](DOMList& list, const std::string& val) { list.endIndex_ = StringUtils::StringToInt(val); },
71         },
72         {
73             DOM_LIST_INDEXER,
74             [](DOMList& list, const std::string& val) { list.ParseIndexer(val); },
75         },
76         {
77             DOM_LIST_INDEXER_BUBBLE,
78             [](DOMList& list, const std::string& val) {
79                 list.bubble_.first = StringToBool(val);
80                 list.bubble_.second = true;
81             },
82         },
83         {
84             DOM_LIST_INDEXER_MODE,
85             [](DOMList& list, const std::string& val) {
86                 list.circleMode_.first = StringToBool(val);
87                 list.circleMode_.second = true;
88             },
89         },
90         {
91             DOM_LIST_INDEXER_MULTI,
92             [](DOMList& list, const std::string& val) {
93               list.multiLanguage_.first = StringToBool(val);
94               list.multiLanguage_.second = true;
95             },
96         },
97         {
98             LIST_INDEX_OFFSET,
99             [](DOMList& list, const std::string& val) { list.indexOffset_ = StringUtils::StringToInt(val); },
100         },
101         {
102             DOM_LIST_INITIAL_INDEX,
103             [](DOMList& list, const std::string& val) { list.initialIndex_ = StringToInt(val); },
104         },
105         {
106             DOM_LIST_INITIAL_OFFSET,
107             [](DOMList& list, const std::string& val) { list.initialOffset_ = StringToDouble(val); },
108         },
109         {
110             DOM_LIST_ITEM_CENTER,
111             [](DOMList& list, const std::string& val) { list.itemCenter_ = StringToBool(val); },
112         },
113         {
114             DOM_LIST_ITEM_OPACITY,
115             [](DOMList& list, const std::string& val) { list.itemOpacity_ = StringToBool(val); },
116         },
117         {
118             DOM_LIST_ITEM_SCALE,
119             [](DOMList& list, const std::string& val) { list.itemScale_ = StringToBool(val); },
120         },
121         {
122             LIST_REPEATED_LENGTH,
123             [](DOMList& list, const std::string& val) { list.repeatedLength_ = StringUtils::StringToInt(val); },
124         },
125         {
126             DOM_LIST_ROTATION_VIBRATE,
127             [](DOMList& list, const std::string& val) {
128 #ifdef WEARABLE_PRODUCT
129                 list.rotationVibrate_ = StringToBool(val);
130                 list.scrollVibrate_ = false;
131 #endif
132             },
133         },
134         {
135             DOM_SCROLL_SCROLLBAR,
136             [](DOMList& list, const std::string& val) {
137                 if (val == DOM_SCROLL_SCROLLBAR_ON) {
138                     list.displayMode_ = DisplayMode::ON;
139                 } else if (val == DOM_SCROLL_SCROLLBAR_AUTO) {
140                     list.displayMode_ = DisplayMode::AUTO;
141                 } else {
142                     list.displayMode_ = DisplayMode::OFF;
143                 }
144             },
145         },
146         {
147             DOM_SCROLL_EFFECT,
148             [](DOMList& list, const std::string& val) {
149                 if (val == DOM_SCROLL_EFFECT_SPRING) {
150                     list.edgeEffect_ = EdgeEffect::SPRING;
151                 } else if (val == DOM_SCROLL_EFFECT_FADE) {
152                     list.edgeEffect_ = EdgeEffect::FADE;
153                 } else {
154                     list.edgeEffect_ = EdgeEffect::NONE;
155                 }
156             },
157         },
158         {
159             DOM_LIST_SCROLLPAGE,
160             [](DOMList& list, const std::string& val) { list.scrollPage_ = StringToBool(val); },
161         },
162         {
163             DOM_LIST_SCROLL_VIBRATE,
164             [](DOMList& list, const std::string& val) { list.scrollVibrate_ = StringToBool(val); },
165         },
166         {
167             DOM_LIST_ATTR_SELECTED,
168             [](DOMList& list, const std::string& val) { list.selectedItem_ = val; },
169         },
170         {
171             DOM_SCROLL_SHAPE_MODE,
172             [](DOMList& list, const std::string& val) {
173                 if (val == DOM_SCROLL_SHAPE_MODE_RECT) {
174                     list.shapeMode_ = ShapeMode::RECT;
175                 } else if (val == DOM_SCROLL_SHAPE_MODE_ROUND) {
176                     list.shapeMode_ = ShapeMode::ROUND;
177                 } else {
178                     list.shapeMode_ = ShapeMode::DEFAULT;
179                 }
180             },
181         },
182         {
183             DOM_LIST_UPDATE_EFFECT,
184             [](DOMList& list, const std::string& val) { list.updateEffect_ = StringToBool(val); },
185         },
186     };
187     auto operatorIter = BinarySearchFindIndex(attrOperators, ArraySize(attrOperators), attr.first.c_str());
188     if (operatorIter != -1) {
189         attrOperators[operatorIter].value(*this, attr.second);
190         return true;
191     }
192     return false;
193 }
194 
ParseIndexer(const std::string & indexerAlphabet)195 void DOMList::ParseIndexer(const std::string& indexerAlphabet)
196 {
197     indexerAlphabet_.clear();
198     indexer_ = false;
199 
200     auto context = GetPipelineContext().Upgrade();
201     if (context && context->IsJsCard()) {
202         return;
203     }
204 
205     if (indexerAlphabet.empty() || indexerAlphabet.find("false") != std::string::npos) {
206         return;
207     }
208 
209     if (indexerAlphabet.find("true") != std::string::npos) {
210         indexer_ = true;
211         return;
212     }
213 
214     StringUtils::StringSplitter(indexerAlphabet, INDEXER_ALPHABET_DIV, indexerAlphabet_);
215     int32_t alphabetCount = static_cast<int32_t>(indexerAlphabet_.size());
216     indexer_ = alphabetCount > 0;
217 }
218 
SupportChainAnimation() const219 bool DOMList::SupportChainAnimation() const
220 {
221     return chainAnimation_ && !indexer_;
222 }
223 
AddSpecializedEvent(int32_t pageId,const std::string & event)224 bool DOMList::AddSpecializedEvent(int32_t pageId, const std::string& event)
225 {
226     // static linear map must be sorted by key.
227     static const LinearMapNode<void (*)(int32_t, DOMList&)> eventOperators[] = {
228         {
229             DOM_LIST_EVENT_INDEXER_CHANGE,
230             [](int32_t pageId, DOMList& list) {
231                 list.onIndexerChange_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_INDEXER_CHANGE, pageId);
232             },
233         },
234         {
235             LIST_EVENT_REQUEST_ITEM,
236             [](int32_t pageId, DOMList& list) {
237                 list.onRequestItem_ = EventMarker(list.GetNodeIdForEvent(), LIST_EVENT_REQUEST_ITEM, pageId);
238             },
239         },
240         {
241             DOM_LIST_EVENT_SCROLL,
242             [](int32_t pageId, DOMList& list) {
243                 list.onScroll_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_SCROLL, pageId);
244             },
245         },
246         {
247             DOM_LIST_EVENT_SCROLL_BOTTOM,
248             [](int32_t pageId, DOMList& list) {
249                 list.onScrollBottom_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_SCROLL_BOTTOM, pageId);
250             },
251         },
252         {
253             DOM_LIST_EVENT_SCROLL_END,
254             [](int32_t pageId, DOMList& list) {
255                 list.onScrollEnd_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_SCROLL_END, pageId);
256             },
257         },
258         {
259             DOM_LIST_EVENT_SCROLL_TOP,
260             [](int32_t pageId, DOMList& list) {
261                 list.onScrollTop_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_SCROLL_TOP, pageId);
262             },
263         },
264         {
265             DOM_LIST_EVENT_SCROLL_TOUCH_UP,
266             [](int32_t pageId, DOMList& list) {
267                 list.onScrollTouchUp_ = EventMarker(list.GetNodeIdForEvent(), DOM_LIST_EVENT_SCROLL_TOUCH_UP, pageId);
268             },
269         },
270     };
271     auto iter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
272     if (iter != -1) {
273         eventOperators[iter].value(pageId, *this);
274         return true;
275     }
276     return false;
277 }
278 
ResetInitializedStyle()279 void DOMList::ResetInitializedStyle()
280 {
281     if (!listComponent_) {
282         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
283         return;
284     }
285     // list theme
286     RefPtr<ListTheme> listTheme = GetTheme<ListTheme>();
287     if (listTheme) {
288         listComponent_->InitStyle(listTheme);
289         if (declaration_) {
290             auto& backgroundStyle =
291                 static_cast<CommonBackgroundStyle&>(declaration_->GetStyle(StyleTag::COMMON_BACKGROUND_STYLE));
292             if (declaration_->HasBackGroundColor() && backgroundStyle.IsValid()) {
293                 listComponent_->SetBackgroundColor(backgroundStyle.backgroundColor);
294             }
295         }
296         scrollDistance_ = listTheme->GetScrollDistance();
297     }
298 
299     if (!scrollBar_ || displayMode_ == DisplayMode::OFF) {
300         return;
301     }
302     // scrollBar_ theme
303     RefPtr<ScrollBarTheme> scrollBarTheme = GetTheme<ScrollBarTheme>();
304     if (scrollBarTheme) {
305         if (scrollBar_->GetShapeMode() == ShapeMode::DEFAULT) {
306             scrollBar_->SetShapeMode(scrollBarTheme->GetShapeMode());
307         }
308         scrollBar_->SetInactiveWidth(scrollBarTheme->GetNormalWidth());
309         scrollBar_->SetNormalWidth(scrollBarTheme->GetNormalWidth());
310         scrollBar_->SetActiveWidth(scrollBarTheme->GetActiveWidth());
311         scrollBar_->SetMinHeight(scrollBarTheme->GetMinHeight());
312         scrollBar_->SetMinDynamicHeight(scrollBarTheme->GetMinDynamicHeight());
313         if (scrollbarPositionY_.first == false) {
314             scrollBar_->SetReservedHeight(scrollBarTheme->GetReservedHeight());
315         } else {
316             scrollBar_->SetReservedHeight(scrollbarPositionY_.second);
317         }
318         scrollBar_->SetTouchWidth(scrollBarTheme->GetTouchWidth());
319         scrollBar_->SetBackgroundColor(scrollBarTheme->GetBackgroundColor());
320         scrollBar_->SetForegroundColor(scrollBarTheme->GetForegroundColor());
321         scrollBar_->SetPadding(scrollBarTheme->GetPadding());
322     }
323 }
324 
CreateOrUpdateList()325 void DOMList::CreateOrUpdateList()
326 {
327     if (!listComponent_) {
328         listComponent_ = AceType::MakeRefPtr<ListComponent>();
329     }
330 
331     listComponent_->SetScrollVibrate(scrollVibrate_);
332     listComponent_->MarkNeedRotationVibrate(rotationVibrate_);
333 
334     listComponent_->SetDirection(flexDirection_);
335     if (flexDirection_ == FlexDirection::COLUMN || flexDirection_ == FlexDirection::COLUMN_REVERSE) {
336         listComponent_->SetScrollPage(scrollPage_);
337         boxComponent_->SetScrollPage(scrollPage_);
338     } else {
339         listComponent_->SetScrollPage(false);
340         boxComponent_->SetScrollPage(false);
341     }
342     listComponent_->SetChainProperty(chainProperty_);
343     listComponent_->SetChainAnimation(SupportChainAnimation());
344     if (useDefaultOverSpringProperty_) {
345         if (SupportChainAnimation()) {
346             listComponent_->SetOverSpringProperty(SpringChainProperty::GetDefaultOverSpringProperty());
347         } else {
348             listComponent_->SetOverSpringProperty(Scrollable::GetDefaultOverSpringProperty());
349         }
350     } else {
351         listComponent_->SetOverSpringProperty(1.0, overStiffness_, overDamping_);
352     }
353 
354     listComponent_->SetFlexAlign(crossAxisAlign_);
355     listComponent_->SetRightToLeft(IsRightToLeft());
356     listComponent_->SetOnRequestItem(onRequestItem_);
357     listComponent_->SetOnScroll(onScroll_);
358     listComponent_->SetOnScrollBottom(onScrollBottom_);
359     listComponent_->SetOnScrollTop(onScrollTop_);
360     listComponent_->SetOnScrollEnd(onScrollEnd_);
361     listComponent_->SetOnScrollTouchUp(onScrollTouchUp_);
362     if (cachedCount_ > 0) {
363         listComponent_->SetCachedCount(cachedCount_);
364     }
365     listComponent_->SetBeginIndex(beginIndex_);
366     listComponent_->SetEndIndex(endIndex_);
367     listComponent_->SetRepeatedLength(repeatedLength_);
368     listComponent_->SetIndexOffset(indexOffset_);
369     listComponent_->SetColumnCount(listColumns_);
370     listComponent_->SetItemExtent(itemExtent_);
371     listComponent_->SetUpdateEffect(updateEffect_);
372     listComponent_->SetAccessibilityDisabled(accessibilityDisabled_);
373     if (listColumns_ > 1) {
374         // itemScale is not supported in 'columns > 1' case.
375         itemScale_ = false;
376     }
377     listComponent_->SetItemScale(itemScale_);
378     listComponent_->MarkCenterLayout(centerLayout_);
379     listComponent_->SetSupportItemCenter(itemCenter_);
380     if (edgeEffect_ == EdgeEffect::SPRING) {
381         listComponent_->SetScrollEffect(AceType::MakeRefPtr<ScrollSpringEffect>());
382     } else if (edgeEffect_ == EdgeEffect::FADE) {
383         listComponent_->SetScrollEffect(AceType::MakeRefPtr<ScrollFadeEffect>(fadeColor_));
384     } else {
385         listComponent_->SetScrollEffect(AceType::MakeRefPtr<ScrollEdgeEffect>(EdgeEffect::NONE));
386     }
387 
388     // keep list state during update.
389     if (!listComponent_->GetPositionController()) {
390         listComponent_->SetPositionController(AceType::MakeRefPtr<ScrollPositionController>());
391     }
392     if (declaration_) {
393         declaration_->SetPositionController(listComponent_->GetPositionController());
394     }
395     listComponent_->GetPositionController()->SetInitialIndex(initialIndex_);
396     listComponent_->GetPositionController()->SetInitialOffset(initialOffset_);
397 
398     if (declaration_ && !GetRotateId().IsEmpty()) {
399         listComponent_->SetOnRotateId(GetRotateId());
400     }
401 
402     SetScrollBar();
403     ResetInitializedStyle();
404     InitScrollBarWithSpecializedStyle();
405     SetChildActive();
406 }
407 
CreateOrUpdateIndexer()408 void DOMList::CreateOrUpdateIndexer()
409 {
410     CreateOrUpdateList();
411     bool isCircle = circleMode_.second ? circleMode_.first : SystemProperties::GetDeviceType() == DeviceType::WATCH;
412     bool bubble = bubble_.second ? bubble_.first : true;
413     bool multiLanguage = multiLanguage_.second ? multiLanguage_.first : false;
414     if (!indexerComponent_) {
415         if (indexerAlphabet_.empty()) {
416             indexerComponent_ = AceType::MakeRefPtr<IndexerListComponent>(
417                 listComponent_, isCircle, IsRightToLeft(), bubble, multiLanguage);
418         } else {
419             indexerComponent_ = AceType::MakeRefPtr<IndexerListComponent>(
420                 listComponent_, indexerAlphabet_, isCircle, IsRightToLeft(), bubble, multiLanguage);
421         }
422         if (isCircle && !onIndexerChange_.IsEmpty()) {
423             indexerComponent_->SetIndexerChangeEvent(onIndexerChange_);
424         }
425     }
426     indexerComponent_->SetBubbleEnabled(bubble_.first);
427 }
428 
SetScrollBar()429 void DOMList::SetScrollBar()
430 {
431     if (displayMode_ == DisplayMode::ON || displayMode_ == DisplayMode::AUTO) {
432         if (shapeMode_ == ShapeMode::ROUND || shapeMode_ == ShapeMode::RECT) {
433             scrollBar_ = AceType::MakeRefPtr<ScrollBar>(displayMode_, shapeMode_);
434         } else {
435             scrollBar_ = AceType::MakeRefPtr<ScrollBar>(displayMode_, ShapeMode::DEFAULT);
436         }
437         scrollBar_->SetPositionMode(IsRightToLeft() ? PositionMode::LEFT : PositionMode::RIGHT);
438     } else {
439         scrollBar_ = AceType::MakeRefPtr<ScrollBar>(DisplayMode::OFF, ShapeMode::DEFAULT);
440     }
441     listComponent_->SetScrollBar(scrollBar_);
442 }
443 
InitScrollBarWithSpecializedStyle()444 void DOMList::InitScrollBarWithSpecializedStyle()
445 {
446     if (!scrollBar_) {
447         return;
448     }
449 
450     if (scrollbarColor_.first) {
451         scrollBar_->SetForegroundColor(scrollbarColor_.second);
452     }
453     if (scrollbarWidth_.first) {
454         scrollBar_->SetInactiveWidth(scrollbarWidth_.second);
455         scrollBar_->SetNormalWidth(scrollbarWidth_.second);
456         scrollBar_->SetActiveWidth(scrollbarWidth_.second);
457         scrollBar_->SetTouchWidth(scrollbarWidth_.second);
458     }
459     if (scrollbarPositionX_.first) {
460         scrollBar_->SetPosition(scrollbarPositionX_.second);
461     }
462 }
463 
SetChildActive()464 void DOMList::SetChildActive()
465 {
466     if (selectedItem_.empty()) {
467         return;
468     }
469     for (const auto& child : GetChildList()) {
470         auto childItem = AceType::DynamicCast<DOMListItem>(child);
471         if (!childItem) {
472             continue;
473         }
474         auto listItem = AceType::DynamicCast<ListItemComponent>(childItem->GetSpecializedComponent());
475         if (!listItem) {
476             continue;
477         }
478         auto itemKey = childItem->GetItemKey();
479         bool isItemActive = !itemKey.empty() && selectedItem_ == itemKey;
480         if (listItem->IsActive() != isItemActive) {
481             listItem->SetIsActive(isItemActive);
482             childItem->MarkNeedUpdate();
483         }
484     }
485 }
486 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)487 bool DOMList::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
488 {
489     static const LinearMapNode<bool (*)(const std::string& val, DOMList& list)> styleOperators[] = {
490         { DOM_ALIGN_ITEMS,
491             [](const std::string& val, DOMList& list) {
492               list.crossAxisAlign_ = ConvertStrToFlexAlign(val);
493               return true;
494             } },
495         { DOM_BACKGROUND_COLOR,
496             [](const std::string& val, DOMList& list) {
497               // The list component uses backgroundColor as the foreground color.
498               // The backgroundColor still needs to be set to the background color of the box component, so return
499               // false.
500               list.backgroundColor_ = list.ParseColor(val);
501               return false;
502             } },
503         { DOM_LIST_COLUMNS,
504             [](const std::string& val, DOMList& list) {
505               list.listColumns_ = StringUtils::StringToInt(val);
506               return true;
507             } },
508         { DOM_LIST_DIVIDER_COLOR,
509             [](const std::string& val, DOMList& list) {
510               list.dividerColor_ = list.ParseColor(val);
511               return true;
512             } },
513         { DOM_LIST_DIVIDER_HEIGHT,
514             [](const std::string& val, DOMList& list) {
515               list.dividerHeight_ = list.ParseDimension(val);
516               return true;
517             } },
518         { DOM_LIST_DIVIDER_LENGTH,
519             [](const std::string& val, DOMList& list) {
520               list.dividerLength_ = list.ParseDimension(val);
521               return true;
522             } },
523         { DOM_LIST_DIVIDER_ORIGIN,
524             [](const std::string& val, DOMList& list) {
525               list.dividerOrigin_ = list.ParseDimension(val);
526               return true;
527             } },
528         { DOM_FADE_COLOR,
529             [](const std::string& val, DOMList& list) {
530               list.fadeColor_ = list.ParseColor(val);
531               return true;
532             } },
533         { DOM_FLEX_DIRECTION,
534             [](const std::string& val, DOMList& list) {
535                 if (val == DOM_FLEX_ROW) {
536                     list.flexDirection_ = FlexDirection::ROW;
537                 } else if (val == DOM_FLEX_ROW_REVERSE) {
538                     list.flexDirection_ = FlexDirection::ROW_REVERSE;
539                 } else if (val == DOM_FLEX_COLUMN_REVERSE) {
540                     list.flexDirection_ = FlexDirection::COLUMN_REVERSE;
541                 } else {
542                     list.flexDirection_ = FlexDirection::COLUMN;
543                 }
544                 return true;
545             } },
546         { DOM_LIST_ITEM_EXTENT,
547             [](const std::string& val, DOMList& list) {
548                 list.itemExtent_ = list.ParseDimension(val);
549                 return true;
550             } },
551         { DOM_SCROLL_OVER_SCROLL_EFFECT,
552             [](const std::string& val, DOMList& list) {
553                 if (val == DOM_SCROLL_EFFECT_SPRING) {
554                     list.edgeEffect_ = EdgeEffect::SPRING;
555                 } else if (val == DOM_SCROLL_EFFECT_FADE) {
556                     list.edgeEffect_ = EdgeEffect::FADE;
557                 } else {
558                     list.edgeEffect_ = EdgeEffect::NONE;
559                 }
560                 return true;
561             } },
562         { DOM_SCROLL_SCROLLBAR_COLOR,
563             [](const std::string& val, DOMList& list) {
564                 list.scrollbarColor_.first = true;
565                 list.scrollbarColor_.second = list.ParseColor(val);
566                 return true;
567             } },
568         { DOM_SCROLL_SCROLLBAR_OFFSET,
569             [](const std::string& val, DOMList& list) {
570                 std::vector<std::string> offset;
571                 OHOS::Ace::StringUtils::StringSplitter(val, ',', offset);
572                 list.scrollbarPositionX_.first = true;
573                 auto position = list.ParseDimension(offset[0]);
574                 list.scrollbarPositionX_.second = position.IsValid() ? position : Dimension();
575                 if (offset.size() > 1) {
576                     list.scrollbarPositionY_.first = true;
577                     auto positionY = list.ParseDimension(offset[1]);
578                     list.scrollbarPositionY_.second = positionY.IsValid() ? positionY : Dimension();
579                 }
580                 return true;
581             } },
582         { DOM_SCROLL_SCROLLBAR_WIDTH,
583             [](const std::string& val, DOMList& list) {
584                 list.scrollbarWidth_.first = true;
585                 auto width = list.ParseDimension(val);
586                 list.scrollbarWidth_.second = width.IsValid() ? width : Dimension();
587                 return true;
588             } },
589         { DOM_SCROLL_SCROLLBAR_POSITION,
590             [](const std::string& val, DOMList& list) {
591                 list.scrollbarPositionX_.first = true;
592                 auto position = list.ParseDimension(val);
593                 list.scrollbarPositionX_.second = position.IsValid() ? position : Dimension();
594                 return true;
595             } },
596     };
597     auto operatorIter = BinarySearchFindIndex(styleOperators, ArraySize(styleOperators), style.first.c_str());
598     if (operatorIter != -1) {
599         return styleOperators[operatorIter].value(style.second, *this);
600     }
601     return false;
602 }
603 
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)604 void DOMList::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
605 {
606     auto childListItem = AceType::DynamicCast<DOMListItem>(child);
607     if (!childListItem) {
608         return;
609     }
610 
611     // childIndex is generated by js framework, just the position of this new list item should be added into the list.
612     auto childIndex = childListItem->GetItemIndex();
613     if (childIndex != DEFAULT_NODE_INDEX) {
614         if (indexer_) {
615             needUpdateIds_ = true;
616             indexerComponent_->InsertChild(childIndex, child->GetRootComponent());
617         } else {
618             listComponent_->InsertChild(childIndex, child->GetRootComponent());
619         }
620     } else {
621         if (indexer_) {
622             needUpdateIds_ = true;
623             indexerComponent_->AppendChild(child->GetRootComponent());
624         } else {
625             listComponent_->AppendChild(child->GetRootComponent());
626         }
627     }
628     auto item = AceType::DynamicCast<ListItemComponent>(childListItem->GetSpecializedComponent());
629     if (!item) {
630         return;
631     }
632     if (!selectedItem_.empty() && !childListItem->GetItemKey().empty() &&
633         (selectedItem_ == childListItem->GetItemKey())) {
634         item->SetIsActive(true);
635     } else {
636         item->SetIsActive(false);
637     }
638 }
639 
CallSpecializedMethod(const std::string & method,const std::string & args)640 void DOMList::CallSpecializedMethod(const std::string& method, const std::string& args)
641 {
642     if (method == DOM_LIST_METHOD_SCROLL_TO) {
643         std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
644         if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != 1) {
645             LOGW("list parse args error");
646             return;
647         }
648         std::unique_ptr<JsonValue> indexValue = argsValue->GetArrayItem(0)->GetValue("index");
649         if (!indexValue || !indexValue->IsNumber()) {
650             return;
651         }
652         int32_t index = indexValue->GetInt();
653         ScrollToMethod(index);
654     } else if (method == DOM_LIST_METHOD_SCROLL_ARROW) {
655         std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
656         if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != 1) {
657             LOGW("list parse args error");
658             return;
659         }
660         std::unique_ptr<JsonValue> scrollArrowParams = argsValue->GetArrayItem(0);
661         bool reverse = scrollArrowParams->GetBool("reverse", false);
662         bool isSmooth = scrollArrowParams->GetBool("smooth", false);
663         ScrollArrowMethod(reverse, isSmooth);
664     } else if (method == DOM_LIST_METHOD_SCROLL_TOP || method == DOM_LIST_METHOD_SCROLL_BOTTOM) {
665         ScrollToEdgeMethod(method, args);
666     } else if (method == DOM_LIST_METHOD_SCROLL_PAGE) {
667         ScrollPageMethod(method, args);
668     } else if (method == DOM_LIST_METHOD_EXPAND_GROUP || method == DOM_LIST_METHOD_COLLAPSE_GROUP) {
669         std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
670         std::string groupId;
671         if (argsValue && argsValue->IsArray() && argsValue->GetArraySize() == 1) {
672             std::unique_ptr<JsonValue> expandParams = argsValue->GetArrayItem(0);
673             std::unique_ptr<JsonValue> value = expandParams->GetValue("groupid");
674             if (value && value->IsString()) {
675                 groupId = value->GetString();
676             }
677         }
678         if (method == DOM_LIST_METHOD_EXPAND_GROUP) {
679             ExpandGroup(groupId, true);
680         } else {
681             ExpandGroup(groupId, false);
682         }
683     } else if (method == DOM_ROTATION) {
684         auto controller = listComponent_->GetRotationController();
685         if (controller) {
686             controller->RequestRotation(true);
687         }
688     } else {
689         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
690     }
691 }
692 
OnScrollBy(double dx,double dy,bool isSmooth)693 void DOMList::OnScrollBy(double dx, double dy, bool isSmooth)
694 {
695     ScrollByMethod(dx, dy, isSmooth);
696 }
697 
ExpandGroup(const std::string & groupId,bool expand)698 void DOMList::ExpandGroup(const std::string& groupId, bool expand)
699 {
700     if (!listComponent_) {
701         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
702         return;
703     }
704     if (groupId.empty()) {
705         listComponent_->SetGroupState(INDEX_EXPAND_ALL, expand);
706     }
707     auto children = GetChildList();
708     for (const auto& child : children) {
709         auto itemGroup = AceType::DynamicCast<DOMListItemGroup>(child);
710         if (!itemGroup) {
711             continue;
712         }
713         if (groupId.empty() || groupId == itemGroup->GetGroupId()) {
714             if (!groupId.empty()) {
715                 listComponent_->SetGroupState(itemGroup->GetItemIndex(), expand);
716                 itemGroup->Update();
717                 break;
718             }
719             itemGroup->Update();
720         }
721     }
722 }
723 
ScrollToMethod(int32_t index)724 void DOMList::ScrollToMethod(int32_t index)
725 {
726     if (!listComponent_) {
727         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
728         return;
729     }
730     auto controller = listComponent_->GetPositionController();
731     if (!controller) {
732         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
733         return;
734     }
735     controller->JumpTo(index);
736 }
737 
ScrollByMethod(double x,double y,bool isSmooth)738 void DOMList::ScrollByMethod(double x, double y, bool isSmooth)
739 {
740     if (!listComponent_) {
741         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
742         return;
743     }
744     auto controller = listComponent_->GetPositionController();
745     if (!controller) {
746         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
747         return;
748     }
749     controller->ScrollBy(x, y, isSmooth);
750 }
751 
ScrollArrowMethod(bool reverse,bool isSmooth)752 void DOMList::ScrollArrowMethod(bool reverse, bool isSmooth)
753 {
754     if (!listComponent_) {
755         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
756         return;
757     }
758     auto controller = listComponent_->GetPositionController();
759     if (!controller) {
760         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
761         return;
762     }
763     controller->ScrollArrow(scrollDistance_, reverse, isSmooth);
764 }
765 
ScrollToEdgeMethod(const std::string & method,const std::string & args)766 void DOMList::ScrollToEdgeMethod(const std::string& method, const std::string& args)
767 {
768     if (!listComponent_) {
769         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
770         return;
771     }
772     auto controller = listComponent_->GetPositionController();
773     if (!controller) {
774         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
775         return;
776     }
777 
778     std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
779     if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != 1) {
780         LOGW("list parse args error");
781         return;
782     }
783     std::unique_ptr<JsonValue> params = argsValue->GetArrayItem(0);
784     bool isSmooth = params->GetBool("smooth", false);
785     if (method == DOM_LIST_METHOD_SCROLL_TOP) {
786         controller->ScrollToEdge(ScrollEdgeType::SCROLL_TOP, isSmooth);
787     } else {
788         controller->ScrollToEdge(ScrollEdgeType::SCROLL_BOTTOM, isSmooth);
789     }
790 }
791 
ScrollPageMethod(const std::string & method,const std::string & args)792 void DOMList::ScrollPageMethod(const std::string& method, const std::string& args)
793 {
794     if (!listComponent_) {
795         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
796         return;
797     }
798     auto controller = listComponent_->GetPositionController();
799     if (!controller) {
800         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
801         return;
802     }
803 
804     std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
805     if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != 1) {
806         LOGW("list parse args error");
807         return;
808     }
809     std::unique_ptr<JsonValue> params = argsValue->GetArrayItem(0);
810     bool reverse = params->GetBool("reverse", false);
811     bool isSmooth = params->GetBool("smooth", false);
812     controller->ScrollPage(reverse, isSmooth);
813 }
814 
GetCurrentOffset() const815 Offset DOMList::GetCurrentOffset() const
816 {
817     if (!listComponent_) {
818         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
819         return Offset::Zero();
820     }
821     auto controller = listComponent_->GetPositionController();
822     if (!controller) {
823         EventReport::SendComponentException(ComponentExcepType::LIST_COMPONENT_ERR);
824         return Offset::Zero();
825     }
826     return controller->GetCurrentOffset();
827 }
828 
OnChildNodeRemoved(const RefPtr<DOMNode> & child)829 void DOMList::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
830 {
831     if (!listComponent_ || !child) {
832         return;
833     }
834     listComponent_->RemoveChild(child->GetRootComponent());
835 }
836 
PrepareSpecializedComponent()837 void DOMList::PrepareSpecializedComponent()
838 {
839     if (indexer_) {
840         CreateOrUpdateIndexer();
841     } else {
842         CreateOrUpdateList();
843     }
844 }
845 
OnMounted(const RefPtr<DOMNode> & parentNode)846 void DOMList::OnMounted(const RefPtr<DOMNode>& parentNode)
847 {
848     auto parent = parentNode;
849     while (parent) {
850         if (parent->GetTag() == DOM_NODE_TAG_REFRESH) {
851             listComponent_->SetInRefresh(true);
852             break;
853         }
854         parent = parent->GetParentNode();
855     }
856 }
857 
GetAccessibilityNode()858 RefPtr<AccessibilityNode> DOMList::GetAccessibilityNode()
859 {
860     auto pipelineContext = pipelineContext_.Upgrade();
861     if (!pipelineContext) {
862         return RefPtr<AccessibilityNode>();
863     }
864     auto accessibilityManager = pipelineContext->GetAccessibilityManager();
865     if (!accessibilityManager) {
866         return RefPtr<AccessibilityNode>();
867     }
868     auto accessibilityNode = accessibilityManager->GetAccessibilityNodeById(GetNodeId());
869     if (!accessibilityNode) {
870         return RefPtr<AccessibilityNode>();
871     }
872 
873     return accessibilityNode;
874 }
875 
UpdateAccessibilityOrder()876 void DOMList::UpdateAccessibilityOrder()
877 {
878     auto accessibilityNode = GetAccessibilityNode();
879     if (!accessibilityNode) {
880         return;
881     }
882 
883     if (listComponent_) {
884         listComponent_->UpdateListItemIndex();
885     }
886 
887     children_.sort([](const RefPtr<DOMNode>& node1, const RefPtr<DOMNode>& node2) {
888         RefPtr<ListItemComponent> item1, item2;
889         auto itemNode1 = DOMListItem::GetDOMListItem(node1);
890         auto itemNode2 = DOMListItem::GetDOMListItem(node2);
891         if (itemNode1) {
892             item1 = itemNode1->GetListItemComponent();
893         }
894         if (itemNode2) {
895             item2 = itemNode2->GetListItemComponent();
896         }
897         if (item1 && item2) {
898             return item1->GetIndex() < item2->GetIndex();
899         }
900         return false;
901     });
902 
903     std::list<RefPtr<AccessibilityNode>> children;
904     auto nodes = accessibilityNode->GetChildList();
905     for (const auto& child : children_) {
906         auto item = DOMListItem::GetDOMListItem(child);
907         if (item) {
908             auto it = std::find_if(
909                 nodes.begin(), nodes.end(), [nodeId = item->GetNodeId()](const RefPtr<AccessibilityNode>& node) {
910                     return node->GetNodeId() == nodeId;
911                 });
912             if (it != nodes.end()) {
913                 children.emplace_back(*it);
914             }
915         }
916     }
917     if (!children.empty()) {
918         accessibilityNode->ResetChildList(children);
919     }
920 }
921 
UpdateAccessibilityByVisible()922 void DOMList::UpdateAccessibilityByVisible()
923 {
924     auto pipelineContext = pipelineContext_.Upgrade();
925     if (!pipelineContext) {
926         return;
927     }
928     auto accessibilityManager = pipelineContext->GetAccessibilityManager();
929     if (!accessibilityManager) {
930         return;
931     }
932     auto accessibilityNode = accessibilityManager->GetAccessibilityNodeById(GetNodeId());
933     if (!accessibilityNode) {
934         return;
935     }
936 
937     bool visibleRange = false;
938     std::list<RefPtr<AccessibilityNode>> children;
939     for (auto& child : children_) {
940         auto childAccessibilityNode = accessibilityManager->GetAccessibilityNodeById(child->GetNodeId());
941         if (childAccessibilityNode &&
942             childAccessibilityNode->GetWidth() != 0 && childAccessibilityNode->GetHeight() != 0) {
943             children.emplace_back(childAccessibilityNode);
944             visibleRange = true;
945         } else {
946             if (visibleRange) {
947                 break; // Just load the visible range item.
948             }
949         }
950     }
951     if (!children.empty()) {
952         accessibilityNode->ResetChildList(children);
953     }
954 }
955 
OnPageLoadFinish()956 void DOMList::OnPageLoadFinish()
957 {
958     if (listComponent_) {
959         listComponent_->SetPageReady(true);
960     }
961 
962     auto accessibilityNode = GetAccessibilityNode();
963     if (!accessibilityNode) {
964         return;
965     }
966 
967     accessibilityNode->SetActionUpdateIdsImpl([weakList = AceType::WeakClaim(this), indexer = this->indexer_]() {
968         auto list = weakList.Upgrade();
969         if (list) {
970             if (indexer && list->needUpdateIds_) {
971                 list->UpdateAccessibilityOrder();
972                 list->needUpdateIds_ = false;
973             }
974 
975             list->UpdateAccessibilityByVisible();
976         }
977     });
978 }
979 
AdjustSpecialParamInLiteMode()980 void DOMList::AdjustSpecialParamInLiteMode()
981 {
982     itemScale_ = false;
983 }
984 
985 } // namespace OHOS::Ace::Framework
986