• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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