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>::Method("stopEditing", &JSTextEditableController::StopEditing);
34     JSClass<JSTextEditableController>::Bind(
35         globalObj, JSTextEditableController::Constructor, JSTextEditableController::Destructor);
36 }
37 
Constructor(const JSCallbackInfo & args)38 void JSTextEditableController::Constructor(const JSCallbackInfo& args)
39 {
40     auto controller = Referenced::MakeRefPtr<JSTextEditableController>();
41     controller->IncRefCount();
42     args.SetReturnValue(Referenced::RawPtr(controller));
43 }
44 
Destructor(JSTextEditableController * controller)45 void JSTextEditableController::Destructor(JSTextEditableController* controller)
46 {
47     if (controller != nullptr) {
48         controller->DecRefCount();
49     }
50 }
51 
CaretPosition(int32_t caretPosition)52 void JSTextEditableController::CaretPosition(int32_t caretPosition)
53 {
54     auto controller = controllerWeak_.Upgrade();
55     if (controller) {
56         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
57             caretPosition = caretPosition < 0 ? 0 : caretPosition;
58         } else {
59             // do nothing
60         }
61         controller->CaretPosition(caretPosition);
62     } else {
63         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "CaretPosition: The JSTextEditableController is NULL");
64     }
65 }
66 
ShowPassword(const JSCallbackInfo & info)67 void JSTextEditableController::ShowPassword(const JSCallbackInfo& info)
68 {
69     auto controller = controllerWeak_.Upgrade();
70     if (controller) {
71         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "begin to show password");
72         controller->SetPasswordState(false);
73     } else {
74         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "ShowPassword: The JSTextEditableController is NULL");
75     }
76 }
77 
HidePassword(const JSCallbackInfo & info)78 void JSTextEditableController::HidePassword(const JSCallbackInfo& info)
79 {
80     auto controller = controllerWeak_.Upgrade();
81     if (controller) {
82         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "begin to hide password");
83         controller->SetPasswordState(true);
84     } else {
85         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "HidePassword: The JSTextEditableController is NULL");
86     }
87 }
88 
SetTextSelection(const JSCallbackInfo & info)89 void JSTextEditableController::SetTextSelection(const JSCallbackInfo& info)
90 {
91     if (info.Length() < 2) { /* 2:args number */
92         return;
93     }
94     auto controller = controllerWeak_.Upgrade();
95     if (controller) {
96         const auto& start = info[0];
97         const auto& end = info[1];
98         std::optional<SelectionOptions> options = std::nullopt;
99         if (!start->IsNumber() || !end->IsNumber()) {
100             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The selectionStart or selectionEnd is NULL");
101         }
102         int32_t selectionStart = start->ToNumber<int32_t>();
103         int32_t selectionEnd = end->ToNumber<int32_t>();
104 
105         if (info.Length() == 3 && info[2]->IsObject()) { /* 2, 3:args number */
106             SelectionOptions optionTemp;
107             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The selectionOption is set");
108             JSRef<JSObject> optionsObj = JSRef<JSObject>::Cast(info[2]); /* 2:args number */
109             JSRef<JSVal> menuPolicy = optionsObj->GetProperty("menuPolicy");
110             int32_t tempPolicy = 0;
111             if (!menuPolicy->IsNull() && JSContainerBase::ParseJsInt32(menuPolicy, tempPolicy)) {
112                 optionTemp.menuPolicy = static_cast<MenuPolicy>(tempPolicy);
113                 options = optionTemp;
114             }
115         }
116         controller->SetTextSelection(selectionStart, selectionEnd, options);
117     } else {
118         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SetTextSelection: The JSTextEditableController is NULL");
119     }
120 }
121 
CreateRectangle(const Rect & info)122 JSRef<JSObject> JSTextEditableController::CreateRectangle(const Rect& info)
123 {
124     JSRef<JSObject> rectObj = JSRef<JSObject>::New();
125     rectObj->SetProperty<double>("x", info.Left());
126     rectObj->SetProperty<double>("y", info.Top());
127     rectObj->SetProperty<double>("width", info.Width());
128     rectObj->SetProperty<double>("height", info.Height());
129     return rectObj;
130 }
131 
GetTextContentRect(const JSCallbackInfo & info)132 void JSTextEditableController::GetTextContentRect(const JSCallbackInfo& info)
133 {
134     auto controller = controllerWeak_.Upgrade();
135     if (controller) {
136         auto rectObj = CreateRectangle(controller->GetTextContentRect());
137         JSRef<JSVal> rect = JSRef<JSObject>::Cast(rectObj);
138         info.SetReturnValue(rect);
139     } else {
140         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "GetTextContentRect: The JSTextEditableController is NULL");
141     }
142 }
143 
GetTextContentLinesNum(const JSCallbackInfo & info)144 void JSTextEditableController::GetTextContentLinesNum(const JSCallbackInfo& info)
145 {
146     auto controller = controllerWeak_.Upgrade();
147     if (controller) {
148         auto lines = controller->GetTextContentLinesNum();
149         auto linesNum = JSVal(ToJSValue(lines));
150         auto textLines = JSRef<JSVal>::Make(linesNum);
151         info.SetReturnValue(textLines);
152     } else {
153         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "GetTextContentLinesNum: The JSTextEditableController is NULL");
154     }
155 }
156 
GetCaretOffset(const JSCallbackInfo & info)157 void JSTextEditableController::GetCaretOffset(const JSCallbackInfo& info)
158 {
159     auto controller = controllerWeak_.Upgrade();
160     if (controller) {
161         JSRef<JSObject> caretObj = JSRef<JSObject>::New();
162         NG::OffsetF caretOffset = controller->GetCaretPosition();
163         caretObj->SetProperty<int32_t>("index", controller->GetCaretIndex());
164         caretObj->SetProperty<float>("x", caretOffset.GetX());
165         caretObj->SetProperty<float>("y", caretOffset.GetY());
166         JSRef<JSVal> ret = JSRef<JSObject>::Cast(caretObj);
167         info.SetReturnValue(ret);
168     } else {
169         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "GetCaretOffset: The JSTextEditableController is NULL");
170     }
171 }
172 
StopEditing()173 void JSTextEditableController::StopEditing()
174 {
175     auto controller = controllerWeak_.Upgrade();
176     if (controller) {
177         controller->StopEditing();
178     } else {
179         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "StopEditing: The JSTextEditableController is NULL");
180     }
181 }
182 } // namespace OHOS::Ace::Framework
183