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