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