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