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 "frameworks/bridge/declarative_frontend/jsview/js_tabs.h"
17
18 #include "core/components/tab_bar/tab_bar_component.h"
19 #include "core/components/tab_bar/tab_content_component.h"
20 #include "core/components_v2/tabs/tabs_component.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/js_tabs_controller.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23
24 namespace OHOS::Ace::Framework {
25 namespace {
26
27 constexpr Dimension DEFAULT_TAB_BAR_HEIGHT = 56.0_vp;
28 const std::vector<BarPosition> BAR_POSITIONS = { BarPosition::START, BarPosition::END };
29
TabContentChangeEventToJSValue(const TabContentChangeEvent & eventInfo)30 JSRef<JSVal> TabContentChangeEventToJSValue(const TabContentChangeEvent& eventInfo)
31 {
32 return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
33 }
34
35 } // namespace
36
SetOnChange(const JSCallbackInfo & args)37 void JSTabs::SetOnChange(const JSCallbackInfo& args)
38 {
39 if (args[0]->IsFunction()) {
40 auto changeHandler = AceType::MakeRefPtr<JsEventFunction<TabContentChangeEvent, 1>>(
41 JSRef<JSFunc>::Cast(args[0]), TabContentChangeEventToJSValue);
42 auto onChange = EventMarker([executionContext = args.GetExecutionContext(), func = std::move(changeHandler)](
43 const BaseEventInfo* info) {
44 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
45 auto TabsInfo = TypeInfoHelper::DynamicCast<TabContentChangeEvent>(info);
46 if (!TabsInfo) {
47 LOGE("HandleChangeEvent TabsInfo == nullptr");
48 return;
49 }
50 ACE_SCORING_EVENT("Tabs.onChange");
51 func->Execute(*TabsInfo);
52 });
53 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
54 if (component) {
55 auto tabContent = component->GetTabContentChild();
56 if (tabContent) {
57 tabContent->SetChangeEventId(onChange);
58 }
59 }
60 }
61 args.ReturnSelf();
62 }
63
Create(const JSCallbackInfo & info)64 void JSTabs::Create(const JSCallbackInfo& info)
65 {
66 BarPosition barVal = BarPosition::START;
67 RefPtr<TabController> tabController;
68 if (info[0]->IsObject()) {
69 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
70 JSRef<JSVal> val = obj->GetProperty("barPosition");
71 if (val->IsNumber()) {
72 auto barPositionVal = val->ToNumber<int32_t>();
73 if (barPositionVal >= 0 && barPositionVal < static_cast<int32_t>(BAR_POSITIONS.size())) {
74 barVal = BAR_POSITIONS[barPositionVal];
75 }
76 }
77 JSRef<JSVal> controller = obj->GetProperty("controller");
78 if (controller->IsObject()) {
79 auto jsTabsController = JSRef<JSObject>::Cast(controller)->Unwrap<JSTabsController>();
80 if (jsTabsController) {
81 tabController = jsTabsController->GetController();
82 }
83 }
84 JSRef<JSVal> index = obj->GetProperty("index");
85 if (index->IsNumber()) {
86 if (!tabController) {
87 tabController = JSTabsController::CreateController();
88 }
89 tabController->SetInitialIndex(index->ToNumber<int32_t>());
90 }
91 }
92 std::list<RefPtr<Component>> children;
93 auto tabsComponent = AceType::MakeRefPtr<V2::TabsComponent>(children, barVal, tabController);
94 auto tabBar = tabsComponent->GetTabBarChild();
95 if (tabBar) {
96 auto theme = GetTheme<TabTheme>();
97 tabBar->InitStyle(theme);
98 auto box = AceType::DynamicCast<BoxComponent>(tabBar->GetParent().Upgrade());
99 if (box) {
100 box->SetHeight(DEFAULT_TAB_BAR_HEIGHT);
101 }
102 }
103 ViewStackProcessor::GetInstance()->PushTabs(tabsComponent);
104 ViewStackProcessor::GetInstance()->Push(tabsComponent);
105 }
106
Pop()107 void JSTabs::Pop()
108 {
109 ViewStackProcessor::GetInstance()->PopTabs();
110 JSContainerBase::Pop();
111 }
112
SetVertical(const std::string & value)113 void JSTabs::SetVertical(const std::string& value)
114 {
115 auto tabsComponent = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
116 if (!tabsComponent) {
117 return;
118 }
119 bool isVertical = StringToBool(value);
120 if (isVertical) {
121 tabsComponent->SetDirection(FlexDirection::ROW);
122 } else {
123 tabsComponent->SetDirection(FlexDirection::COLUMN);
124 }
125 auto tabBar = tabsComponent->GetTabBarChild();
126 if (tabBar) {
127 tabBar->SetVertical(isVertical);
128 }
129 auto tabContent = tabsComponent->GetTabContentChild();
130 if (tabContent) {
131 tabContent->SetVertical(isVertical);
132 }
133 }
134
SetScrollable(const std::string & value)135 void JSTabs::SetScrollable(const std::string& value)
136 {
137 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
138 if (!component) {
139 return;
140 }
141 auto tabContent = component->GetTabContentChild();
142 if (tabContent) {
143 tabContent->SetScrollable(StringToBool(value));
144 }
145 }
146
SetBarMode(const std::string & value)147 void JSTabs::SetBarMode(const std::string& value)
148 {
149 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
150 if (!component) {
151 return;
152 }
153 auto tabBar = component->GetTabBarChild();
154 if (tabBar) {
155 tabBar->SetMode(ConvertStrToTabBarMode(value));
156 }
157 }
158
SetBarWidth(const JSCallbackInfo & info)159 void JSTabs::SetBarWidth(const JSCallbackInfo& info)
160 {
161 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
162 if (!component) {
163 return;
164 }
165 if (info.Length() < 1) {
166 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
167 return;
168 }
169 Dimension width;
170 if (!ParseJsDimensionVp(info[0], width)) {
171 LOGE("The arg is wrong, fail to parse dimension");
172 return;
173 }
174 auto tabBar = component->GetTabBarChild();
175 if (!tabBar) {
176 LOGE("can not find tab bar component");
177 return;
178 }
179 auto box = AceType::DynamicCast<BoxComponent>(tabBar->GetParent().Upgrade());
180 if (box) {
181 box->SetWidth(width);
182 } else {
183 LOGE("can not find box component");
184 }
185 }
186
SetBarHeight(const JSCallbackInfo & info)187 void JSTabs::SetBarHeight(const JSCallbackInfo& info)
188 {
189 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
190 if (!component) {
191 return;
192 }
193 if (info.Length() < 1) {
194 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
195 return;
196 }
197 Dimension height;
198 if (!ParseJsDimensionVp(info[0], height)) {
199 LOGE("The arg is wrong, fail to parse dimension");
200 return;
201 }
202 auto tabBar = component->GetTabBarChild();
203 if (!tabBar) {
204 LOGE("can not find tab bar component");
205 return;
206 }
207 auto box = AceType::DynamicCast<BoxComponent>(tabBar->GetParent().Upgrade());
208 if (box) {
209 box->SetHeight(height);
210 } else {
211 LOGE("can not find box component");
212 }
213 }
214
SetIndex(int32_t index)215 void JSTabs::SetIndex(int32_t index)
216 {
217 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
218 if (!component) {
219 LOGE("can not find tabs component");
220 return;
221 }
222 auto controller = component->GetTabsController();
223 if (controller) {
224 controller->SetPendingIndex(index);
225 } else {
226 LOGE("can not find controller");
227 }
228 }
229
SetAnimationDuration(float value)230 void JSTabs::SetAnimationDuration(float value)
231 {
232 auto component = AceType::DynamicCast<V2::TabsComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
233 if (!component) {
234 return;
235 }
236 auto tabContent = component->GetTabContentChild();
237 if (!tabContent) {
238 return;
239 }
240 tabContent->SetScrollDuration(value);
241 }
242
JSBind(BindingTarget globalObj)243 void JSTabs::JSBind(BindingTarget globalObj)
244 {
245 JSClass<JSTabs>::Declare("Tabs");
246 JSClass<JSTabs>::StaticMethod("create", &JSTabs::Create);
247 JSClass<JSTabs>::StaticMethod("pop", &JSTabs::Pop);
248 JSClass<JSTabs>::StaticMethod("vertical", &JSTabs::SetVertical);
249 JSClass<JSTabs>::StaticMethod("scrollable", &JSTabs::SetScrollable);
250 JSClass<JSTabs>::StaticMethod("barMode", &JSTabs::SetBarMode);
251 JSClass<JSTabs>::StaticMethod("barWidth", &JSTabs::SetBarWidth);
252 JSClass<JSTabs>::StaticMethod("barHeight", &JSTabs::SetBarHeight);
253 JSClass<JSTabs>::StaticMethod("index", &JSTabs::SetIndex);
254 JSClass<JSTabs>::StaticMethod("animationDuration", &JSTabs::SetAnimationDuration);
255 JSClass<JSTabs>::StaticMethod("onChange", &JSTabs::SetOnChange);
256 JSClass<JSTabs>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
257 JSClass<JSTabs>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
258 JSClass<JSTabs>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
259 JSClass<JSTabs>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
260 JSClass<JSTabs>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
261 JSClass<JSTabs>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
262 JSClass<JSTabs>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
263 JSClass<JSTabs>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
264 JSClass<JSTabs>::Inherit<JSContainerBase>();
265 JSClass<JSTabs>::Bind<>(globalObj);
266 }
267
268 } // namespace OHOS::Ace::Framework
269