1 /*
2 * Copyright (c) 2024 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 #include <string>
17
18 #include "base/memory/referenced.h"
19 #include "core/components_ng/syntax/repeat_model_ng.h"
20 #include "bridge/declarative_frontend/jsview/js_repeat.h"
21 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
22
23
24 namespace OHOS::Ace {
GetInstance()25 RepeatModel* RepeatModel::GetInstance()
26 {
27 static NG::RepeatModelNG instance;
28 return &instance;
29 }
30 } // namespace OHOS::Ace
31
32
33 namespace OHOS::Ace::Framework {
34
StartRender()35 void JSRepeat::StartRender()
36 {
37 RepeatModel::GetInstance()->StartRender();
38 }
39
FinishRender(const JSCallbackInfo & info)40 void JSRepeat::FinishRender(const JSCallbackInfo& info)
41 {
42 std::list<int32_t> removedElmtIds;
43
44 if ((info.Length() != 1) || !info[0]->IsArray()) {
45 TAG_LOGW(AceLogTag::ACE_REPEAT, "Invalid arguments for Repeat.FinishRender");
46 return;
47 }
48 RepeatModel::GetInstance()->FinishRender(removedElmtIds);
49
50 if (!removedElmtIds.size()) {
51 return;
52 }
53
54 // convert list of removed elmtIds: std::list to JSArray<number>
55 JSRef<JSArray> jsArr = JSRef<JSArray>::Cast(info[0]);
56 size_t index = jsArr->Length();
57 for (const auto& rmElmtId : removedElmtIds) {
58 jsArr->SetValueAt(index++, JSRef<JSVal>::Make(ToJSValue(rmElmtId)));
59 }
60 }
61
62 // signature is
63 // fromIndex: number
MoveChild(const JSCallbackInfo & info)64 void JSRepeat::MoveChild(const JSCallbackInfo& info)
65 {
66 if ((info.Length() != 1) || !info[0]->IsNumber()) {
67 TAG_LOGW(AceLogTag::ACE_REPEAT, "Invalid arguments for Repeat.MoveChild");
68 return;
69 }
70
71 const auto fromIndex = info[0]->ToNumber<uint32_t>();
72 RepeatModel::GetInstance()->MoveChild(fromIndex);
73 }
74
75 // signature is
76 // id: string
77 // parentView? : JSView
CreateNewChildStart(const JSCallbackInfo & info)78 void JSRepeat::CreateNewChildStart(const JSCallbackInfo& info)
79 {
80 if ((info.Length() < 1) || !info[0]->IsString()) {
81 TAG_LOGW(AceLogTag::ACE_REPEAT, "Invalid arguments for Repeat.CreateNewChildStart");
82 return;
83 }
84
85 const auto key = info[0]->ToString();
86 RepeatModel::GetInstance()->CreateNewChildStart(key);
87 }
88
89 // signature is
90 // id: string
91 // parentView? : JSView
CreateNewChildFinish(const JSCallbackInfo & info)92 void JSRepeat::CreateNewChildFinish(const JSCallbackInfo& info)
93 {
94 if ((info.Length() < 1) || !info[0]->IsString()) {
95 TAG_LOGW(AceLogTag::ACE_REPEAT, "Invalid arguments for Repeat.CreateNewChildFinish");
96 return;
97 }
98
99 const auto key = info[0]->ToString();
100 RepeatModel::GetInstance()->CreateNewChildFinish(key);
101 }
102
OnMove(const JSCallbackInfo & info)103 void JSRepeat::OnMove(const JSCallbackInfo& info)
104 {
105 if (info[0]->IsFunction()) {
106 auto context = info.GetExecutionContext();
107 auto onMove = [execCtx = context, func = JSRef<JSFunc>::Cast(info[0])](int32_t from, int32_t to) {
108 auto params = ConvertToJSValues(from, to);
109 func->Call(JSRef<JSObject>(), params.size(), params.data());
110 };
111 RepeatModel::GetInstance()->OnMove(std::move(onMove));
112 if (info.Length() > 1 && info[1]->IsObject()) {
113 JsParseItemDragEventHandler(context, info[1]);
114 } else {
115 RepeatModel::GetInstance()->SetItemDragHandler(nullptr, nullptr, nullptr, nullptr);
116 }
117 } else {
118 RepeatModel::GetInstance()->OnMove(nullptr);
119 RepeatModel::GetInstance()->SetItemDragHandler(nullptr, nullptr, nullptr, nullptr);
120 }
121 }
122
AfterAddChild()123 void JSRepeat::AfterAddChild()
124 {
125 RepeatModel::GetInstance()->AfterAddChild();
126 }
127
JsParseItemDragEventHandler(const JsiExecutionContext & context,const JSRef<JSObject> & itemDragEventObj)128 void JSRepeat::JsParseItemDragEventHandler(
129 const JsiExecutionContext& context, const JSRef<JSObject>& itemDragEventObj)
130 {
131 auto onLongPress = itemDragEventObj->GetProperty("onLongPress");
132 std::function<void(int32_t)> onLongPressCallback;
133 if (onLongPress->IsFunction()) {
134 onLongPressCallback = [execCtx = context, func = JSRef<JSFunc>::Cast(onLongPress)](int32_t index) {
135 auto params = ConvertToJSValues(index);
136 func->Call(JSRef<JSObject>(), params.size(), params.data());
137 };
138 }
139
140 auto onDragStart = itemDragEventObj->GetProperty("onDragStart");
141 std::function<void(int32_t)> onDragStartCallback;
142 if (onDragStart->IsFunction()) {
143 onDragStartCallback = [execCtx = context, func = JSRef<JSFunc>::Cast(onDragStart)](int32_t index) {
144 auto params = ConvertToJSValues(index);
145 func->Call(JSRef<JSObject>(), params.size(), params.data());
146 };
147 }
148
149 auto onMoveThrough = itemDragEventObj->GetProperty("onMoveThrough");
150 std::function<void(int32_t, int32_t)> onMoveThroughCallback;
151 if (onMoveThrough->IsFunction()) {
152 onMoveThroughCallback = [execCtx = context, func = JSRef<JSFunc>::Cast(onMoveThrough)](
153 int32_t from, int32_t to) {
154 auto params = ConvertToJSValues(from, to);
155 func->Call(JSRef<JSObject>(), params.size(), params.data());
156 };
157 }
158
159 auto onDrop = itemDragEventObj->GetProperty("onDrop");
160 std::function<void(int32_t)> onDropCallback;
161 if (onDrop->IsFunction()) {
162 onDropCallback = [execCtx = context, func = JSRef<JSFunc>::Cast(onDrop)](int32_t index) {
163 auto params = ConvertToJSValues(index);
164 func->Call(JSRef<JSObject>(), params.size(), params.data());
165 };
166 }
167 RepeatModel::GetInstance()->SetItemDragHandler(std::move(onLongPressCallback), std::move(onDragStartCallback),
168 std::move(onMoveThroughCallback), std::move(onDropCallback));
169 }
170
JSBind(BindingTarget globalObj)171 void JSRepeat::JSBind(BindingTarget globalObj)
172 {
173 JSClass<JSRepeat>::Declare("RepeatNative");
174 JSClass<JSRepeat>::StaticMethod("startRender", &JSRepeat::StartRender);
175 JSClass<JSRepeat>::StaticMethod("finishRender", &JSRepeat::FinishRender);
176 JSClass<JSRepeat>::StaticMethod("moveChild", &JSRepeat::MoveChild);
177 JSClass<JSRepeat>::StaticMethod("createNewChildStart", &JSRepeat::CreateNewChildStart);
178 JSClass<JSRepeat>::StaticMethod("createNewChildFinish", &JSRepeat::CreateNewChildFinish);
179 JSClass<JSRepeat>::StaticMethod("afterAddChild", &JSRepeat::AfterAddChild);
180 JSClass<JSRepeat>::StaticMethod("onMove", &JSRepeat::OnMove);
181 JSClass<JSRepeat>::Bind<>(globalObj);
182 }
183
184 } // namespace OHOS::Ace::Framework
185