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_lazy_foreach.h"
17
18 #include <functional>
19 #include <set>
20 #include <string>
21
22 #include "base/memory/ace_type.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/utils.h"
25 #include "bridge/common/utils/utils.h"
26 #include "bridge/declarative_frontend/engine/js_object_template.h"
27 #include "bridge/declarative_frontend/jsview/js_lazy_foreach_actuator.h"
28 #include "bridge/declarative_frontend/jsview/js_lazy_foreach_builder.h"
29 #ifndef NG_BUILD
30 #include "bridge/declarative_frontend/jsview/js_lazy_foreach_component.h"
31 #endif
32 #include "bridge/declarative_frontend/jsview/js_view.h"
33 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
34 #include "bridge/declarative_frontend/jsview/models/lazy_for_each_model_impl.h"
35 #include "bridge/declarative_frontend/view_stack_processor.h"
36 #include "core/common/container.h"
37 #include "core/common/container_scope.h"
38 #include "core/components_ng/base/view_stack_model.h"
39 #include "core/components_ng/syntax/lazy_for_each_model.h"
40 #include "core/components_ng/syntax/lazy_for_each_model_ng.h"
41 #include "uicast_interface/uicast_impl.h"
42
43 namespace OHOS::Ace {
44
45 std::unique_ptr<LazyForEachModel> LazyForEachModel::instance_ = nullptr;
46
GetInstance()47 LazyForEachModel* LazyForEachModel::GetInstance()
48 {
49 if (!instance_) {
50 #ifdef NG_BUILD
51 instance_.reset(new NG::LazyForEachModelNG());
52 #else
53 if (Container::IsCurrentUseNewPipeline()) {
54 instance_.reset(new NG::LazyForEachModelNG());
55 } else {
56 instance_.reset(new Framework::LazyForEachModelImpl());
57 }
58 #endif
59 }
60 return instance_.get();
61 }
62
63 } // namespace OHOS::Ace
64
65 namespace OHOS::Ace::Framework {
66
JSBind(BindingTarget globalObj)67 void JSDataChangeListener::JSBind(BindingTarget globalObj)
68 {
69 JSClass<JSDataChangeListener>::Declare("__ohos_ace_inner_JSDataChangeListener__");
70 // API7 onEditChanged deprecated
71 JSClass<JSDataChangeListener>::CustomMethod("onDataReloaded", &JSDataChangeListener::OnDataReloaded);
72 JSClass<JSDataChangeListener>::CustomMethod("onDataReload", &JSDataChangeListener::OnDataReloaded);
73 // API7 onDataAdded deprecated
74 JSClass<JSDataChangeListener>::CustomMethod("onDataAdded", &JSDataChangeListener::OnDataAdded);
75 JSClass<JSDataChangeListener>::CustomMethod("onDataAdd", &JSDataChangeListener::OnDataAdded);
76 // API7 onDataDeleted deprecated
77 JSClass<JSDataChangeListener>::CustomMethod("onDataDeleted", &JSDataChangeListener::OnDataDeleted);
78 JSClass<JSDataChangeListener>::CustomMethod("onDataDelete", &JSDataChangeListener::OnDataDeleted);
79 // API7 onDataChanged deprecated
80 JSClass<JSDataChangeListener>::CustomMethod("onDataChanged", &JSDataChangeListener::OnDataChanged);
81 JSClass<JSDataChangeListener>::CustomMethod("onDataChange", &JSDataChangeListener::OnDataChanged);
82 // API7 onDataMoved deprecated
83 JSClass<JSDataChangeListener>::CustomMethod("onDataMoved", &JSDataChangeListener::OnDataMoved);
84 JSClass<JSDataChangeListener>::CustomMethod("onDataMove", &JSDataChangeListener::OnDataMoved);
85 JSClass<JSDataChangeListener>::Bind(
86 globalObj, &JSDataChangeListener::Constructor, &JSDataChangeListener::Destructor);
87 }
88
CreateActuator(const std::string viewId)89 RefPtr<JSLazyForEachActuator> CreateActuator(const std::string viewId)
90 {
91 #ifdef NG_BUILD
92 return AceType::MakeRefPtr<JSLazyForEachBuilder>();
93 #else
94 if (Container::IsCurrentUseNewPipeline()) {
95 return AceType::MakeRefPtr<JSLazyForEachBuilder>();
96 } else {
97 return AceType::MakeRefPtr<JSLazyForEachComponent>(viewId);
98 }
99 #endif
100 }
101
102 namespace {
103
104 enum {
105 PARAM_VIEW_ID = 0,
106 PARAM_PARENT_VIEW,
107 PARAM_DATA_SOURCE,
108 PARAM_ITEM_GENERATOR,
109 PARAM_KEY_GENERATOR,
110
111 MIN_PARAM_SIZE = PARAM_KEY_GENERATOR,
112 MAX_PARAM_SIZE,
113 };
114
ParseAndVerifyParams(const JSCallbackInfo & info,JSRef<JSVal> (& params)[MAX_PARAM_SIZE])115 bool ParseAndVerifyParams(const JSCallbackInfo& info, JSRef<JSVal> (¶ms)[MAX_PARAM_SIZE])
116 {
117 if (info.Length() < MIN_PARAM_SIZE) {
118 return false;
119 }
120
121 if (!info[PARAM_VIEW_ID]->IsNumber() && !info[PARAM_VIEW_ID]->IsString()) {
122 return false;
123 }
124 if (!info[PARAM_PARENT_VIEW]->IsObject()) {
125 return false;
126 }
127 if (!info[PARAM_DATA_SOURCE]->IsObject()) {
128 return false;
129 }
130 if (!info[PARAM_ITEM_GENERATOR]->IsFunction()) {
131 return false;
132 }
133 if (info.Length() > MIN_PARAM_SIZE && !info[PARAM_KEY_GENERATOR]->IsFunction()) {
134 return false;
135 }
136
137 for (int32_t idx = PARAM_VIEW_ID; idx < std::min(info.Length(), static_cast<int32_t>(MAX_PARAM_SIZE)); ++idx) {
138 params[idx] = info[idx];
139 }
140 return true;
141 }
142
143 } // namespace
144
JSBind(BindingTarget globalObj)145 void JSLazyForEach::JSBind(BindingTarget globalObj)
146 {
147 JSClass<JSLazyForEach>::Declare("LazyForEach");
148 JSClass<JSLazyForEach>::StaticMethod("create", &JSLazyForEach::Create);
149 JSClass<JSLazyForEach>::StaticMethod("pop", &JSLazyForEach::Pop);
150 JSClass<JSLazyForEach>::Bind(globalObj);
151
152 JSDataChangeListener::JSBind(globalObj);
153 }
154
Create(const JSCallbackInfo & info)155 void JSLazyForEach::Create(const JSCallbackInfo& info)
156 {
157 JSRef<JSVal> params[MAX_PARAM_SIZE];
158 if (!ParseAndVerifyParams(info, params)) {
159 LOGE("Invalid arguments for LazyForEach");
160 return;
161 }
162 std::string viewId = ViewStackModel::GetInstance()->ProcessViewId(params[PARAM_VIEW_ID]->ToString());
163
164 JSRef<JSObject> parentViewObj = JSRef<JSObject>::Cast(params[PARAM_PARENT_VIEW]);
165 JSRef<JSObject> dataSourceObj = JSRef<JSObject>::Cast(params[PARAM_DATA_SOURCE]);
166 JSRef<JSFunc> itemGenerator = JSRef<JSFunc>::Cast(params[PARAM_ITEM_GENERATOR]);
167 ItemKeyGenerator keyGenFunc;
168 if (params[PARAM_KEY_GENERATOR]->IsUndefined()) {
169 keyGenFunc = [viewId](const JSRef<JSVal>&, size_t index) { return viewId + "-" + std::to_string(index); };
170 } else {
171 keyGenFunc = [viewId, keyGenerator = JSRef<JSFunc>::Cast(params[PARAM_KEY_GENERATOR])](
172 const JSRef<JSVal>& jsVal, size_t index) {
173 JSRef<JSVal> params[] = { jsVal, JSRef<JSVal>::Make(ToJSValue(index)) };
174 auto key = keyGenerator->Call(JSRef<JSObject>(), ArraySize(params), params);
175 return viewId + "-" + (key->IsString() || key->IsNumber() ? key->ToString() : std::to_string(index));
176 };
177 }
178
179 const auto& actuator = CreateActuator(viewId);
180 actuator->SetJSExecutionContext(info.GetExecutionContext());
181 actuator->SetParentViewObj(parentViewObj);
182 actuator->SetDataSourceObj(dataSourceObj);
183 actuator->SetItemGenerator(itemGenerator, std::move(keyGenFunc));
184 LazyForEachModel::GetInstance()->Create(actuator);
185
186 {
187 auto parentView = parentViewObj->Unwrap<JSView>();
188 std::string pviewID = parentView ? std::to_string(parentView->UICastGetUniqueId()) : "-1";
189 int totalCount = static_cast<int>(actuator->GetTotalIndexCount());
190 std::string para = R"({"viewId":")" + viewId + R"(","parentViewId":")" +
191 pviewID + R"(","totalCount":)" + std::to_string(totalCount) + R"(})";
192 UICastImpl::CreateLazyForEach(pviewID, totalCount, para);
193 }
194 }
195
Pop()196 void JSLazyForEach::Pop()
197 {
198 auto* stack = NG::ViewStackProcessor::GetInstance();
199 if (stack->GetMainFrameNode() && stack->GetMainFrameNode()->GetTag() == V2::TABS_ETS_TAG) {
200 return;
201 }
202 ViewStackModel::GetInstance()->PopContainer();
203 }
204
205 } // namespace OHOS::Ace::Framework
206