• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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> (&params)[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