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(const RefPtr<V2::DataChangeListener> & listener)106 void UnregisterListener(const RefPtr<V2::DataChangeListener>& listener)
107 {
108 if (!listener) {
109 return;
110 }
111
112 auto listenerProxy = listenerProxy_.Upgrade();
113 if (listenerProxy) {
114 listenerProxy->RemoveListener(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 parentView_ = parentViewObj->Unwrap<JSView>();
126 }
127
SetDataSourceObj(const JSRef<JSObject> & dataSourceObj)128 void SetDataSourceObj(const JSRef<JSObject>& dataSourceObj)
129 {
130 dataSourceObj_ = dataSourceObj;
131 totalCountFunc_ = GetFunctionFromObject(dataSourceObj, "totalCount");
132 getDataFunc_ = GetFunctionFromObject(dataSourceObj, "getData");
133 registerListenerFunc_ = GetFunctionFromObject(dataSourceObj, "registerDataChangeListener");
134 unregisterListenerFunc_ = GetFunctionFromObject(dataSourceObj, "unregisterDataChangeListener");
135 }
136
SetItemGenerator(const JSRef<JSFunc> & itemGenFunc,ItemKeyGenerator && keyGenFunc)137 void SetItemGenerator(const JSRef<JSFunc>& itemGenFunc, ItemKeyGenerator&& keyGenFunc)
138 {
139 itemGenFunc_ = itemGenFunc;
140 keyGenFunc_ = std::move(keyGenFunc);
141 }
142
ReleaseChildGroupByComposedId(const std::string & composedId)143 void ReleaseChildGroupByComposedId(const std::string& composedId)
144 {
145 if (parentView_ != nullptr) {
146 parentView_->RemoveChildGroupById(composedId);
147 }
148 }
149
150 private:
GetFunctionFromObject(const JSRef<JSObject> & obj,const char * funcName)151 inline JSRef<JSFunc> GetFunctionFromObject(const JSRef<JSObject>& obj, const char* funcName)
152 {
153 JSRef<JSVal> jsVal = obj->GetProperty(funcName);
154 if (jsVal->IsFunction()) {
155 return JSRef<JSFunc>::Cast(jsVal);
156 }
157 return JSRef<JSFunc>();
158 }
159
160 protected:
161 JSExecutionContext executionContext_;
162 JSView* parentView_ = nullptr;
163 JSRef<JSObject> dataSourceObj_;
164 JSRef<JSFunc> totalCountFunc_;
165 JSRef<JSFunc> getDataFunc_;
166 JSRef<JSFunc> registerListenerFunc_;
167 JSRef<JSFunc> unregisterListenerFunc_;
168 JSRef<JSFunc> itemGenFunc_;
169 ItemKeyGenerator keyGenFunc_;
170
171 JSWeak<JSObject> listenerProxyObj_;
172 WeakPtr<JSDataChangeListener> listenerProxy_;
173 RefPtr<V2::DataChangeListener> defaultListener_;
174 };
175
176 } // namespace OHOS::Ace::Framework
177
178 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_ACTUATOR_H
179