1 /*
2 * Copyright (c) 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 #ifndef FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_ACTUATOR_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_ACTUATOR_H
18
19 #include <functional>
20 #include <set>
21 #include <string>
22
23 #include "base/memory/ace_type.h"
24 #include "bridge/declarative_frontend/engine/bindings.h"
25 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
26 #include "bridge/declarative_frontend/jsview/js_data_change_listener.h"
27 #include "bridge/declarative_frontend/jsview/js_view.h"
28 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
29 #include "core/components_ng/syntax/lazy_for_each_model.h"
30
31 namespace OHOS::Ace::Framework {
32
33 using ItemKeyGenerator = std::function<std::string(const JSRef<JSVal>&, size_t)>;
34
35 template<class... T>
CallJSFunction(const JSRef<JSFunc> & func,const JSRef<JSObject> & obj,T &&...args)36 JSRef<JSVal> CallJSFunction(const JSRef<JSFunc>& func, const JSRef<JSObject>& obj, T&&... args)
37 {
38 JSRef<JSVal> params[] = { ConvertToJSValue(std::forward<T>(args))... };
39 return func->Call(obj, ArraySize(params), params);
40 }
41
42 class JSLazyForEachActuator : public LazyForEachActuator {
43 DECLARE_ACE_TYPE(JSLazyForEachActuator, LazyForEachActuator);
44
45 public:
46 JSLazyForEachActuator() = default;
~JSLazyForEachActuator()47 ~JSLazyForEachActuator() override
48 {
49 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
50 JSRef<JSObject> listenerObj = listenerProxyObj_.Lock();
51 if (listenerObj.IsEmpty() || unregisterListenerFunc_.IsEmpty()) {
52 return;
53 }
54
55 JSRef<JSVal> args[] = { listenerObj };
56 unregisterListenerFunc_->Call(dataSourceObj_, ArraySize(args), args);
57 }
58
GetTotalIndexCount()59 int32_t GetTotalIndexCount()
60 {
61 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, 0);
62 if (totalCountFunc_.IsEmpty()) {
63 return 0;
64 }
65
66 int32_t value = 0;
67 if (!ConvertFromJSValue(totalCountFunc_->Call(dataSourceObj_), value)) {
68 return 0;
69 }
70 if (value < 0) {
71 return 0;
72 }
73 return value;
74 }
75
RegisterListener(const RefPtr<V2::DataChangeListener> & listener)76 void RegisterListener(const RefPtr<V2::DataChangeListener>& listener)
77 {
78 if (!listener) {
79 return;
80 }
81
82 auto listenerProxy = listenerProxy_.Upgrade();
83 if (listenerProxy) {
84 listenerProxy->AddListener(listener);
85 return;
86 }
87
88 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_);
89 if (registerListenerFunc_.IsEmpty()) {
90 return;
91 }
92
93 JSRef<JSObject> listenerObj = JSClass<JSDataChangeListener>::NewInstance();
94 auto* unwrapObj = listenerObj->Unwrap<JSDataChangeListener>();
95 if (unwrapObj == nullptr) {
96 return;
97 }
98 listenerProxy = Referenced::Claim(unwrapObj);
99 listenerProxy->AddListener(listener);
100 listenerProxyObj_ = listenerObj;
101 listenerProxy_ = listenerProxy;
102
103 JSRef<JSVal> args[] = { listenerObj };
104 registerListenerFunc_->Call(dataSourceObj_, ArraySize(args), args);
105 }
106
UnregisterListener(V2::DataChangeListener * listener)107 void UnregisterListener(V2::DataChangeListener* listener)
108 {
109 if (!listener) {
110 return;
111 }
112
113 auto listenerProxy = listenerProxy_.Upgrade();
114 if (listenerProxy) {
115 listenerProxy->RemoveListener(Referenced::WeakClaim(listener));
116 }
117 }
118
SetJSExecutionContext(const JSExecutionContext & context)119 void SetJSExecutionContext(const JSExecutionContext& context)
120 {
121 executionContext_ = context;
122 }
123
SetParentViewObj(const JSRef<JSObject> & parentViewObj)124 void SetParentViewObj(const JSRef<JSObject>& parentViewObj)
125 {
126 AceType* aceType = parentViewObj->Unwrap<AceType>();
127 CHECK_NULL_VOID(aceType);
128 std::string typeName = AceType::TypeName(aceType);
129 if (typeName != "JSBaseNode") {
130 parentView_ = JSView::GetNativeView(parentViewObj);
131 }
132 }
133
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)134 void SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
135 {
136 dataSourceObj_ = dataSourceObj;
137 totalCountFunc_ = GetFunctionFromObject(dataSourceObj, "totalCount");
138 getDataFunc_ = GetFunctionFromObject(dataSourceObj, "getData");
139 registerListenerFunc_ = GetFunctionFromObject(dataSourceObj, "registerDataChangeListener");
140 unregisterListenerFunc_ = GetFunctionFromObject(dataSourceObj, "unregisterDataChangeListener");
141 }
142
SetItemGenerator(const JSRef<JSFunc> & itemGenFunc,ItemKeyGenerator && keyGenFunc)143 void SetItemGenerator(const JSRef<JSFunc>& itemGenFunc, ItemKeyGenerator&& keyGenFunc)
144 {
145 itemGenFunc_ = itemGenFunc;
146 keyGenFunc_ = std::move(keyGenFunc);
147 }
148
SetUpdateChangedNodeFlag(const bool updateChangedNodeFlag)149 void SetUpdateChangedNodeFlag(const bool updateChangedNodeFlag)
150 {
151 updateChangedNodeFlag_ = updateChangedNodeFlag;
152 }
153
ReleaseChildGroupByComposedId(const std::string & composedId)154 void ReleaseChildGroupByComposedId(const std::string& composedId)
155 {
156 if (parentView_ != nullptr) {
157 parentView_->RemoveChildGroupById(composedId);
158 }
159 }
160
161 private:
GetFunctionFromObject(const JSRef<JSObject> & obj,const char * funcName)162 inline JSRef<JSFunc> GetFunctionFromObject(const JSRef<JSObject>& obj, const char* funcName)
163 {
164 JSRef<JSVal> jsVal = obj->GetProperty(funcName);
165 if (jsVal->IsFunction()) {
166 return JSRef<JSFunc>::Cast(jsVal);
167 }
168 return JSRef<JSFunc>();
169 }
170
171 protected:
172 JSExecutionContext executionContext_;
173 JSView* parentView_ = nullptr;
174 JSRef<JSObject> dataSourceObj_;
175 JSRef<JSFunc> totalCountFunc_;
176 JSRef<JSFunc> getDataFunc_;
177 JSRef<JSFunc> registerListenerFunc_;
178 JSRef<JSFunc> unregisterListenerFunc_;
179 JSRef<JSFunc> itemGenFunc_;
180 ItemKeyGenerator keyGenFunc_;
181 bool updateChangedNodeFlag_ = false;
182
183 JSWeak<JSObject> listenerProxyObj_;
184 WeakPtr<JSDataChangeListener> listenerProxy_;
185 RefPtr<V2::DataChangeListener> defaultListener_;
186 };
187
188 } // namespace OHOS::Ace::Framework
189
190 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_ACTUATOR_H
191