• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "frameworks/bridge/declarative_frontend/jsview/js_container_base.h"
17 #include "frameworks/bridge/declarative_frontend/jsview/js_text_editable_controller.h"
18 #include "frameworks/core/components_ng/pattern/text_field/text_field_model.h"
19 
20 namespace OHOS::Ace::Framework {
21 
JSBind(BindingTarget globalObj)22 void JSTextEditableController::JSBind(BindingTarget globalObj)
23 {
24     JSClass<JSTextEditableController>::Method("caretPosition", &JSTextEditableController::CaretPosition);
25     JSClass<JSTextEditableController>::CustomMethod("getCaretOffset", &JSTextEditableController::GetCaretOffset);
26     JSClass<JSTextEditableController>::CustomMethod("setTextSelection", &JSTextEditableController::SetTextSelection);
27     JSClass<JSTextEditableController>::CustomMethod("showPassword", &JSTextEditableController::ShowPassword);
28     JSClass<JSTextEditableController>::CustomMethod("hidePassword", &JSTextEditableController::HidePassword);
29     JSClass<JSTextEditableController>::CustomMethod(
30         "getTextContentRect", &JSTextEditableController::GetTextContentRect);
31     JSClass<JSTextEditableController>::CustomMethod(
32         "getTextContentLineCount", &JSTextEditableController::GetTextContentLinesNum);
33     JSClass<JSTextEditableController>::CustomMethod("addText", &JSTextEditableController::AddText);
34     JSClass<JSTextEditableController>::CustomMethod("deleteText", &JSTextEditableController::DeleteText);
35     JSClass<JSTextEditableController>::CustomMethod("getSelection", &JSTextEditableController::GetSelection);
36     JSClass<JSTextEditableController>::CustomMethod("clearPreviewText", &JSTextEditableController::ClearPreviewText);
37     JSClass<JSTextEditableController>::CustomMethod("getText", &JSTextEditableController::GetText);
38     JSClass<JSTextEditableController>::Method("stopEditing", &JSTextEditableController::StopEditing);
39     JSClass<JSTextEditableController>::Bind(
40         globalObj, JSTextEditableController::Constructor, JSTextEditableController::Destructor);
41 }
42 
Constructor(const JSCallbackInfo & args)43 void JSTextEditableController::Constructor(const JSCallbackInfo& args)
44 {
45     auto controller = Referenced::MakeRefPtr<JSTextEditableController>();
46     controller->IncRefCount();
47     args.SetReturnValue(Referenced::RawPtr(controller));
48 }
49 
Destructor(JSTextEditableController * controller)50 void JSTextEditableController::Destructor(JSTextEditableController* controller)
51 {
52     if (controller != nullptr) {
53         controller->DecRefCount();
54     }
55 }
56 
CaretPosition(int32_t caretPosition)57 void JSTextEditableController::CaretPosition(int32_t caretPosition)
58 {
59     auto controller = controllerWeak_.Upgrade();
60     if (controller) {
61         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
62             caretPosition = caretPosition < 0 ? 0 : caretPosition;
63         } else {
64             // do nothing
65         }
66         controller->CaretPosition(caretPosition);
67     } else {
68         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "CaretPosition: The JSTextEditableController is NULL");
69     }
70 }
71 
ShowPassword(const JSCallbackInfo & info)72 void JSTextEditableController::ShowPassword(const JSCallbackInfo& info)
73 {
74     auto controller = controllerWeak_.Upgrade();
75     if (controller) {
76         controller->SetPasswordState(false);
77     } else {
78         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "ShowPassword: The JSTextEditableController is NULL");
79     }
80 }
81 
HidePassword(const JSCallbackInfo & info)82 void JSTextEditableController::HidePassword(const JSCallbackInfo& info)
83 {
84     auto controller = controllerWeak_.Upgrade();
85     if (controller) {
86         controller->SetPasswordState(true);
87     } else {
88         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "HidePassword: The JSTextEditableController is NULL");
89     }
90 }
91 
SetTextSelection(const JSCallbackInfo & info)92 void JSTextEditableController::SetTextSelection(const JSCallbackInfo& info)
93 {
94     if (info.Length() < 2) { /* 2:args number */
95         return;
96     }
97     auto controller = controllerWeak_.Upgrade();
98     if (controller) {
99         const auto& start = info[0];
100         const auto& end = info[1];
101         std::optional<SelectionOptions> options = std::nullopt;
102         if (!start->IsNumber() || !end->IsNumber()) {
103             TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The selectionStart or selectionEnd is NULL");
104         }
105         int32_t selectionStart = start->ToNumber<int32_t>();
106         int32_t selectionEnd = end->ToNumber<int32_t>();
107 
108         if (info.Length() == 3 && info[2]->IsObject()) { /* 2, 3:args number */
109             SelectionOptions optionTemp;
110             JSRef<JSObject> optionsObj = JSRef<JSObject>::Cast(info[2]); /* 2:args number */
111             JSRef<JSVal> menuPolicy = optionsObj->GetProperty("menuPolicy");
112             int32_t tempPolicy = 0;
113             if (!menuPolicy->IsNull() && JSContainerBase::ParseJsInt32(menuPolicy, tempPolicy)) {
114                 optionTemp.menuPolicy = static_cast<MenuPolicy>(tempPolicy);
115                 options = optionTemp;
116             }
117         } else {
118             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The selectionOption is null");
119         }
120         controller->SetTextSelection(selectionStart, selectionEnd, options);
121     } else {
122         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The JSTextEditableController is NULL");
123     }
124 }
125 
CreateRectangle(const Rect & info)126 JSRef<JSObject> JSTextEditableController::CreateRectangle(const Rect& info)
127 {
128     JSRef<JSObject> rectObj = JSRef<JSObject>::New();
129     rectObj->SetProperty<double>("x", info.Left());
130     rectObj->SetProperty<double>("y", info.Top());
131     rectObj->SetProperty<double>("width", info.Width());
132     rectObj->SetProperty<double>("height", info.Height());
133     return rectObj;
134 }
135 
GetTextContentRect(const JSCallbackInfo & info)136 void JSTextEditableController::GetTextContentRect(const JSCallbackInfo& info)
137 {
138     auto controller = controllerWeak_.Upgrade();
139     if (controller) {
140         auto rectObj = CreateRectangle(controller->GetTextContentRect());
141         JSRef<JSVal> rect = JSRef<JSObject>::Cast(rectObj);
142         info.SetReturnValue(rect);
143     } else {
144         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "GetTextContentRect: The JSTextEditableController is NULL");
145     }
146 }
147 
GetTextContentLinesNum(const JSCallbackInfo & info)148 void JSTextEditableController::GetTextContentLinesNum(const JSCallbackInfo& info)
149 {
150     auto controller = controllerWeak_.Upgrade();
151     if (controller) {
152         auto lines = controller->GetTextContentLinesNum();
153         auto linesNum = JSVal(ToJSValue(lines));
154         auto textLines = JSRef<JSVal>::Make(linesNum);
155         info.SetReturnValue(textLines);
156     } else {
157         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "GetTextContentLinesNum: The JSTextEditableController is NULL");
158     }
159 }
160 
AddText(const JSCallbackInfo & info)161 void JSTextEditableController::AddText(const JSCallbackInfo& info)
162 {
163     auto controller = controllerWeak_.Upgrade();
164     if (controller) {
165         const auto& text = info[0];
166         const auto& options = info[1];
167         std::u16string textValue;
168         if (text->IsString()) {
169             textValue = text->ToU16String();
170         } else {
171             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "AddText: The text is null");
172             auto returnValue = JSVal(ToJSValue(controller->GetCaretIndex()));
173             info.SetReturnValue(JSRef<JSVal>::Make(returnValue));
174             return;
175         }
176         int32_t offsetIndex = -1;
177         if (options->IsObject()) {
178             JSRef<JSObject> optionObj = JSRef<JSObject>::Cast(options);
179             JSRef<JSVal> offset = optionObj->GetProperty("offset");
180             if (offset->IsNumber()) {
181                 offsetIndex = offset->ToNumber<int32_t>();
182                 offsetIndex = std::max(0, offsetIndex);
183             }
184         }
185         // add text
186         int32_t result = controller->AddText(textValue, offsetIndex);
187         auto returnValue = JSVal(ToJSValue(result));
188         info.SetReturnValue(JSRef<JSVal>::Make(returnValue));
189     } else {
190         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "AddText: The JSTextEditableController is NULL");
191     }
192 }
193 
DeleteText(const JSCallbackInfo & info)194 void JSTextEditableController::DeleteText(const JSCallbackInfo& info)
195 {
196     auto controller = controllerWeak_.Upgrade();
197     if (controller) {
198         const auto& textRange = info[0];
199         if (!textRange->IsObject()) {
200             controller->DeleteText(-1, -1);
201             return;
202         }
203         JSRef<JSObject> rangeObj = JSRef<JSObject>::Cast(textRange);
204 
205         int32_t startIndex = -1;
206         int32_t endIndex = -1;
207         JSRef<JSVal> start = rangeObj->GetProperty("start");
208         if (start->IsNumber()) {
209             startIndex = start->ToNumber<int32_t>();
210             startIndex = startIndex < 0 ? 0 : startIndex;
211         }
212         JSRef<JSVal> end = rangeObj->GetProperty("end");
213         if (end->IsNumber()) {
214             endIndex = end->ToNumber<int32_t>();
215             endIndex = endIndex < 0 ? -1 : endIndex;
216         }
217         controller->DeleteText(startIndex, endIndex);
218     } else {
219         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "DeleteText: The JSTextEditableController is NULL");
220     }
221 }
222 
GetSelection(const JSCallbackInfo & info)223 void JSTextEditableController::GetSelection(const JSCallbackInfo& info)
224 {
225     auto controller = controllerWeak_.Upgrade();
226     if (controller) {
227         SelectionInfo selectInfo = controller->GetSelection();
228         JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
229         selectionObject->SetPropertyObject("start",
230             JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[0])));
231         selectionObject->SetPropertyObject("end",
232             JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[1])));
233         info.SetReturnValue(JSRef<JSVal>::Cast(selectionObject));
234     } else {
235         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "GetSelection: The JSTextEditableController is NULL");
236     }
237 }
238 
GetCaretOffset(const JSCallbackInfo & info)239 void JSTextEditableController::GetCaretOffset(const JSCallbackInfo& info)
240 {
241     auto controller = controllerWeak_.Upgrade();
242     if (controller) {
243         JSRef<JSObject> caretObj = JSRef<JSObject>::New();
244         NG::OffsetF caretOffset = controller->GetCaretPosition();
245         caretObj->SetProperty<int32_t>("index", controller->GetCaretIndex());
246         caretObj->SetProperty<float>("x", caretOffset.GetX());
247         caretObj->SetProperty<float>("y", caretOffset.GetY());
248         JSRef<JSVal> ret = JSRef<JSObject>::Cast(caretObj);
249         info.SetReturnValue(ret);
250     } else {
251         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "GetCaretOffset: The JSTextEditableController is NULL");
252     }
253 }
254 
ClearPreviewText(const JSCallbackInfo & info)255 void JSTextEditableController::ClearPreviewText(const JSCallbackInfo& info)
256 {
257     auto controller = controllerWeak_.Upgrade();
258     if (controller) {
259         controller->ClearPreviewText();
260     } else {
261         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "ClearPreviewText: The JSTextEditableController is NULL");
262     }
263 }
264 
GetText(const JSCallbackInfo & info)265 void JSTextEditableController::GetText(const JSCallbackInfo& info)
266 {
267     auto controller = controllerWeak_.Upgrade();
268     if (controller) {
269         std::u16string content = controller->GetText();
270         const auto& textRange = info[0];
271         int32_t startIndex = 0;
272         int32_t endIndex = static_cast<int32_t>(content.length());
273         if (textRange->IsObject()) {
274             JSRef<JSObject> rangeObj = JSRef<JSObject>::Cast(textRange);
275             JSRef<JSVal> start = rangeObj->GetProperty("start");
276             if (start->IsNumber()) {
277                 startIndex = start->ToNumber<int32_t>();
278                 startIndex = startIndex < 0 ? 0 : startIndex;
279                 startIndex = std::clamp(startIndex, 0, static_cast<int32_t>(content.length()));
280             }
281             JSRef<JSVal> end = rangeObj->GetProperty("end");
282             if (end->IsNumber()) {
283                 endIndex = end->ToNumber<int32_t>();
284                 endIndex = endIndex < 0 ? static_cast<int32_t>(content.length()) : endIndex;
285                 endIndex = std::clamp(endIndex, 0, static_cast<int32_t>(content.length()));
286             }
287             if (startIndex > endIndex) {
288                 std::swap(startIndex, endIndex);
289             }
290         }
291         std::u16string result = content.substr(startIndex, endIndex - startIndex);
292         auto returnValue = JSVal(ToJSValue(result));
293         info.SetReturnValue(JSRef<JSVal>::Make(returnValue));
294     } else {
295         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "GetText: The JSTextEditableController is NULL");
296     }
297 }
298 
StopEditing()299 void JSTextEditableController::StopEditing()
300 {
301     auto controller = controllerWeak_.Upgrade();
302     if (controller) {
303         controller->StopEditing();
304     } else {
305         TAG_LOGW(AceLogTag::ACE_TEXT_FIELD, "StopEditing: The JSTextEditableController is NULL");
306     }
307 }
308 } // namespace OHOS::Ace::Framework
309