1 /*
2 * Copyright (c) 2023 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 "bridge/declarative_frontend/jsview/js_richeditor.h"
17
18 #include <string>
19
20 #include "base/log/ace_scoring_log.h"
21 #include "bridge/declarative_frontend/jsview/js_textfield.h"
22 #include "core/components_ng/base/view_abstract.h"
23 #include "core/components_ng/pattern/rich_editor/rich_editor_selection.h"
24 #ifdef PIXEL_MAP_SUPPORTED
25 #include "pixel_map.h"
26 #include "pixel_map_napi.h"
27 #endif
28 #include "bridge/common/utils/utils.h"
29 #include "bridge/declarative_frontend/engine/functions/js_function.h"
30 #include "bridge/declarative_frontend/engine/js_converter.h"
31 #include "bridge/declarative_frontend/engine/js_types.h"
32 #include "bridge/declarative_frontend/jsview/js_container_base.h"
33 #include "bridge/declarative_frontend/jsview/js_image.h"
34 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
35 #include "bridge/declarative_frontend/jsview/js_utils.h"
36 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
37 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
38 #include "bridge/declarative_frontend/jsview/models/richeditor_model_impl.h"
39 #include "core/components_ng/pattern/rich_editor/rich_editor_model_ng.h"
40 #include "frameworks/bridge/common/utils/engine_helper.h"
41
42 namespace OHOS::Ace {
43 std::unique_ptr<RichEditorModel> RichEditorModel::instance_ = nullptr;
44 std::mutex RichEditorModel::mutex_;
GetInstance()45 RichEditorModel* RichEditorModel::GetInstance()
46 {
47 if (!instance_) {
48 std::lock_guard<std::mutex> lock(mutex_);
49 if (!instance_) {
50 #ifdef NG_BUILD
51 instance_.reset(new NG::RichEditorModelNG());
52 #else
53 if (Container::IsCurrentUseNewPipeline()) {
54 instance_.reset(new NG::RichEditorModelNG());
55 } else {
56 // empty implementation
57 instance_.reset(new Framework::RichEditorModelImpl());
58 }
59 #endif
60 }
61 }
62 return instance_.get();
63 }
64 } // namespace OHOS::Ace
65
66 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)67 void JSRichEditor::Create(const JSCallbackInfo& info)
68 {
69 JSRichEditorController* jsController = nullptr;
70 if (info[0]->IsObject()) {
71 auto paramObject = JSRef<JSObject>::Cast(info[0]);
72 auto controllerObj = paramObject->GetProperty("controller");
73 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
74 jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSRichEditorController>();
75 }
76 }
77 RichEditorModel::GetInstance()->Create();
78 RefPtr<RichEditorControllerBase> controller = RichEditorModel::GetInstance()->GetRichEditorController();
79 if (jsController) {
80 jsController->SetController(controller);
81 }
82 }
83
SetOnReady(const JSCallbackInfo & args)84 void JSRichEditor::SetOnReady(const JSCallbackInfo& args)
85 {
86 if (args.Length() < 1 || !args[0]->IsFunction()) {
87 LOGE("args not function");
88 return;
89 }
90 JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
91 RichEditorModel::GetInstance()->SetOnReady(callback);
92 }
93
CreateJSTextStyleResult(const TextStyleResult & textStyleResult)94 JSRef<JSObject> JSRichEditor::CreateJSTextStyleResult(const TextStyleResult& textStyleResult)
95 {
96 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
97 textStyleObj->SetProperty<std::string>("fontColor", textStyleResult.fontColor);
98 textStyleObj->SetProperty<double>("fontSize", textStyleResult.fontSize);
99 textStyleObj->SetProperty<int32_t>("fontStyle", textStyleResult.fontStyle);
100 textStyleObj->SetProperty<int32_t>("fontWeight", textStyleResult.fontWeight);
101 textStyleObj->SetProperty<std::string>("fontFamily", textStyleResult.fontFamily);
102 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
103 decorationObj->SetProperty<int32_t>("type", textStyleResult.decorationType);
104 decorationObj->SetProperty<std::string>("color", textStyleResult.decorationColor);
105 textStyleObj->SetPropertyObject("decoration", decorationObj);
106
107 return textStyleObj;
108 }
109
CreateJSImageStyleResult(const ImageStyleResult & imageStyleResult)110 JSRef<JSObject> JSRichEditor::CreateJSImageStyleResult(const ImageStyleResult& imageStyleResult)
111 {
112 JSRef<JSObject> imageSpanStyleObj = JSRef<JSObject>::New();
113
114 JSRef<JSArray> sizeArray = JSRef<JSArray>::New();
115 sizeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[0])));
116 sizeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[1])));
117 imageSpanStyleObj->SetPropertyObject("size", sizeArray);
118 imageSpanStyleObj->SetProperty<int32_t>("verticalAlign", imageStyleResult.verticalAlign);
119 imageSpanStyleObj->SetProperty<int32_t>("objectFit", imageStyleResult.objectFit);
120
121 return imageSpanStyleObj;
122 }
123
CreateJSSpanResultObject(const ResultObject & resultObject)124 JSRef<JSObject> JSRichEditor::CreateJSSpanResultObject(const ResultObject& resultObject)
125 {
126 JSRef<JSArray> offsetArray = JSRef<JSArray>::New();
127 JSRef<JSArray> spanRangeArray = JSRef<JSArray>::New();
128 JSRef<JSObject> spaneRsultObj = JSRef<JSObject>::New();
129 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
130 offsetArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[0])));
131 offsetArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[1])));
132 spanRangeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[0])));
133 spanRangeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[1])));
134 spanPositionObj->SetProperty<int32_t>("spanIndex", resultObject.spanPosition.spanIndex);
135 spanPositionObj->SetPropertyObject("spanRange", spanRangeArray);
136 spaneRsultObj->SetPropertyObject("offsetInSpan", offsetArray);
137 spaneRsultObj->SetPropertyObject("spanPosition", spanPositionObj);
138 if (resultObject.type == RichEditorSpanType::TYPESPAN) {
139 spaneRsultObj->SetProperty<std::string>("value", resultObject.valueString);
140 spaneRsultObj->SetPropertyObject("textStyle", CreateJSTextStyleResult(resultObject.textStyle));
141 } else if (resultObject.type == RichEditorSpanType::TYPEIMAGE) {
142 if (resultObject.valuePixelMap) {
143 #ifdef PIXEL_MAP_SUPPORTED
144 std::shared_ptr<Media::PixelMap> pixelMap = resultObject.valuePixelMap->GetPixelMapSharedPtr();
145 auto engine = EngineHelper::GetCurrentEngine();
146 if (engine) {
147 NativeEngine* nativeEngine = engine->GetNativeEngine();
148 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
149 napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
150 NativeValue* nativeValue = reinterpret_cast<NativeValue*>(napiValue);
151 auto jsPixelMap = JsConverter::ConvertNativeValueToJsVal(nativeValue);
152 spaneRsultObj->SetPropertyObject("valuePixelMap", jsPixelMap);
153 }
154 #endif
155 } else {
156 spaneRsultObj->SetProperty<std::string>("valueResourceStr", resultObject.valueString);
157 }
158 spaneRsultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(resultObject.imageStyle));
159 }
160
161 return spaneRsultObj;
162 }
163
CreateJSSelection(const RichEditorSelection & selectInfo)164 JSRef<JSVal> JSRichEditor::CreateJSSelection(const RichEditorSelection& selectInfo)
165 {
166 uint32_t idx = 0;
167
168 JSRef<JSArray> selectionArray = JSRef<JSArray>::New();
169 JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
170 JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
171
172 const std::list<ResultObject>& spanObjectList = selectInfo.GetSelection().resultObjects;
173 for (const ResultObject& spanObject : spanObjectList) {
174 spanObjectArray->SetValueAt(idx++, CreateJSSpanResultObject(spanObject));
175 }
176
177 selectionArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[0])));
178 selectionArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[1])));
179
180 selectionObject->SetPropertyObject("selection", selectionArray);
181 selectionObject->SetPropertyObject("spans", spanObjectArray);
182 return JSRef<JSVal>::Cast(selectionObject);
183 }
184
SetOnSelect(const JSCallbackInfo & args)185 void JSRichEditor::SetOnSelect(const JSCallbackInfo& args)
186 {
187 if (args.Length() < 1 || !args[0]->IsFunction()) {
188 LOGI("args not function");
189 return;
190 }
191 auto jsSelectFunc =
192 AceType::MakeRefPtr<JsEventFunction<RichEditorSelection, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJSSelection);
193 auto onSelect = [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
194 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
195 const auto* eventInfo = TypeInfoHelper::DynamicCast<RichEditorSelection>(info);
196 func->Execute(*eventInfo);
197 };
198 NG::RichEditorModelNG::GetInstance()->SetOnSelect(std::move(onSelect));
199 }
SetAboutToIMEInput(const JSCallbackInfo & args)200 void JSRichEditor::SetAboutToIMEInput(const JSCallbackInfo& args)
201 {
202 if (args.Length() < 1 || !args[0]->IsFunction()) {
203 LOGE("args not function");
204 return;
205 }
206 auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorInsertValue, 1>>(
207 JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToIMEInputObj);
208 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
209 const NG::RichEditorInsertValue& insertValue) -> bool {
210 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
211 auto ret = func->ExecuteWithValue(insertValue);
212 if (ret->IsBoolean()) {
213 return ret->ToBoolean();
214 }
215 return true;
216 };
217 RichEditorModel::GetInstance()->SetAboutToIMEInput(std::move(callback));
218 }
219
SetOnIMEInputComplete(const JSCallbackInfo & args)220 void JSRichEditor::SetOnIMEInputComplete(const JSCallbackInfo& args)
221 {
222 if (args.Length() < 1 || !args[0]->IsFunction()) {
223 LOGE("args not function");
224 return;
225 }
226 auto jsOnIMEInputCompleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorAbstractSpanResult, 1>>(
227 JSRef<JSFunc>::Cast(args[0]), CreateJsOnIMEInputComplete);
228 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnIMEInputCompleteFunc)](
229 const NG::RichEditorAbstractSpanResult& textSpanResult) {
230 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
231 func->Execute(textSpanResult);
232 };
233 RichEditorModel::GetInstance()->SetOnIMEInputComplete(std::move(callback));
234 }
SetAboutToDelete(const JSCallbackInfo & args)235 void JSRichEditor::SetAboutToDelete(const JSCallbackInfo& args)
236 {
237 if (args.Length() < 1 || !args[0]->IsFunction()) {
238 LOGE("args not function");
239 return;
240 }
241 auto jsAboutToDeleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorDeleteValue, 1>>(
242 JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToDelet);
243 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToDeleteFunc)](
244 const NG::RichEditorDeleteValue& deleteValue) -> bool {
245 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
246 auto ret = func->ExecuteWithValue(deleteValue);
247 if (ret->IsBoolean()) {
248 return ret->ToBoolean();
249 }
250 return true;
251 };
252 RichEditorModel::GetInstance()->SetAboutToDelete(std::move(callback));
253 }
254
SetOnDeleteComplete(const JSCallbackInfo & args)255 void JSRichEditor::SetOnDeleteComplete(const JSCallbackInfo& args)
256 {
257 if (args.Length() < 1 || !args[0]->IsFunction()) {
258 LOGE("args not function");
259 return;
260 }
261 JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
262 RichEditorModel::GetInstance()->SetOnDeleteComplete(callback);
263 }
264
SetCustomKeyboard(const JSCallbackInfo & args)265 void JSRichEditor::SetCustomKeyboard(const JSCallbackInfo& args)
266 {
267 if (args.Length() > 0 && (args[0]->IsUndefined() || args[0]->IsNull())) {
268 RichEditorModel::GetInstance()->SetCustomKeyboard(nullptr);
269 return;
270 }
271 if (args.Length() < 1 || !args[0]->IsObject()) {
272 return;
273 }
274 std::function<void()> buildFunc;
275 if (JSTextField::ParseJsCustomKeyboardBuilder(args, 0, buildFunc)) {
276 RichEditorModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc));
277 }
278 }
279
CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue & insertValue)280 JSRef<JSVal> JSRichEditor::CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue& insertValue)
281 {
282 JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
283 aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.GetInsertOffset());
284 aboutToIMEInputObj->SetProperty<std::string>("insertValue", insertValue.GetInsertValue());
285 return JSRef<JSVal>::Cast(aboutToIMEInputObj);
286 }
287
CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult & textSpanResult)288 JSRef<JSVal> JSRichEditor::CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult& textSpanResult)
289 {
290 JSRef<JSObject> onIMEInputCompleteObj = JSRef<JSObject>::New();
291 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
292 JSRef<JSArray> spanRange = JSRef<JSArray>::New();
293 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
294 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
295 JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
296 spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeStart())));
297 spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeEnd())));
298 offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan())));
299 offsetInSpan->SetValueAt(
300 1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan() + textSpanResult.GetEraseLength())));
301 spanPositionObj->SetPropertyObject("spanRange", spanRange);
302 spanPositionObj->SetProperty<int32_t>("spanIndex", textSpanResult.GetSpanIndex());
303 decorationObj->SetProperty<TextDecoration>("type", textSpanResult.GetTextDecoration());
304 decorationObj->SetProperty<std::string>("color", textSpanResult.GetColor());
305 textStyleObj->SetProperty<std::string>("fontColor", textSpanResult.GetFontColor());
306 textStyleObj->SetProperty<double>("fontSize", textSpanResult.GetFontSize());
307 textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(textSpanResult.GetFontStyle()));
308 textStyleObj->SetProperty<int32_t>("fontWeight", textSpanResult.GetFontWeight());
309 textStyleObj->SetProperty<std::string>("fontFamily", textSpanResult.GetFontFamily());
310 textStyleObj->SetPropertyObject("decoration", decorationObj);
311 onIMEInputCompleteObj->SetPropertyObject("spanPosition", spanPositionObj);
312 onIMEInputCompleteObj->SetProperty<std::string>("value", textSpanResult.GetValue());
313 onIMEInputCompleteObj->SetPropertyObject("textStyle", textStyleObj);
314 onIMEInputCompleteObj->SetPropertyObject("offsetInSpan", offsetInSpan);
315 return JSRef<JSVal>::Cast(onIMEInputCompleteObj);
316 }
317
CreateJsAboutToDelet(const NG::RichEditorDeleteValue & deleteValue)318 JSRef<JSVal> JSRichEditor::CreateJsAboutToDelet(const NG::RichEditorDeleteValue& deleteValue)
319 {
320 JSRef<JSObject> AboutToDeletObj = JSRef<JSObject>::New();
321 AboutToDeletObj->SetProperty<int32_t>("offset", deleteValue.GetOffset());
322 AboutToDeletObj->SetProperty<int32_t>(
323 "direction", static_cast<int32_t>(deleteValue.GetRichEditorDeleteDirection()));
324 AboutToDeletObj->SetProperty<int32_t>("length", deleteValue.GetLength());
325 JSRef<JSArray> richEditorDeleteSpans = JSRef<JSArray>::New();
326 auto list = deleteValue.GetRichEditorDeleteSpans();
327 int32_t index = 0;
328 for (const auto& it : list) {
329 JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
330 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
331 JSRef<JSArray> spanRange = JSRef<JSArray>::New();
332 JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
333 spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
334 spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
335 offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
336 offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
337 spanPositionObj->SetPropertyObject("spanRange", spanRange);
338 spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
339 spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
340 spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
341 switch (it.GetType()) {
342 case NG::SpanResultType::TEXT: {
343 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
344 CreateTextStyleObj(textStyleObj, it);
345 spanResultObj->SetProperty<std::string>("value", it.GetValue());
346 spanResultObj->SetPropertyObject("textStyle", textStyleObj);
347 break;
348 }
349 case NG::SpanResultType::IMAGE: {
350 JSRef<JSObject> imageStyleObj = JSRef<JSObject>::New();
351 CreateImageStyleObj(imageStyleObj, spanResultObj, it);
352 spanResultObj->SetPropertyObject("imageStyle", imageStyleObj);
353 break;
354 }
355 default:
356 break;
357 }
358 richEditorDeleteSpans->SetValueAt(index++, spanResultObj);
359 }
360 AboutToDeletObj->SetPropertyObject("richEditorDeleteSpans", richEditorDeleteSpans);
361 return JSRef<JSVal>::Cast(AboutToDeletObj);
362 }
363
CreateTextStyleObj(JSRef<JSObject> & textStyleObj,const NG::RichEditorAbstractSpanResult & spanResult)364 void JSRichEditor::CreateTextStyleObj(JSRef<JSObject>& textStyleObj, const NG::RichEditorAbstractSpanResult& spanResult)
365 {
366 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
367 decorationObj->SetProperty<TextDecoration>("type", spanResult.GetTextDecoration());
368 decorationObj->SetProperty<std::string>("color", spanResult.GetColor());
369 textStyleObj->SetProperty<std::string>("fontColor", spanResult.GetFontColor());
370 textStyleObj->SetProperty<double>("fontSize", spanResult.GetFontSize());
371 textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(spanResult.GetFontStyle()));
372 textStyleObj->SetProperty<int32_t>("fontWeight", spanResult.GetFontWeight());
373 textStyleObj->SetProperty<std::string>("fontFamily", spanResult.GetFontFamily());
374 textStyleObj->SetPropertyObject("decoration", decorationObj);
375 }
376
CreateImageStyleObj(JSRef<JSObject> & imageStyleObj,JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & spanResult)377 void JSRichEditor::CreateImageStyleObj(
378 JSRef<JSObject>& imageStyleObj, JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& spanResult)
379 {
380 JSRef<JSArray> imageSize = JSRef<JSArray>::New();
381 imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeWidth())));
382 imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeHeight())));
383 imageStyleObj->SetPropertyObject("size", imageSize);
384 imageStyleObj->SetProperty<int32_t>("verticalAlign", static_cast<int32_t>(spanResult.GetVerticalAlign()));
385 imageStyleObj->SetProperty<int32_t>("objectFit", static_cast<int32_t>(spanResult.GetObjectFit()));
386 if (spanResult.GetValuePixelMap()) {
387 #ifdef PIXEL_MAP_SUPPORTED
388 std::shared_ptr<Media::PixelMap> pixelMap = spanResult.GetValuePixelMap()->GetPixelMapSharedPtr();
389 auto engine = EngineHelper::GetCurrentEngine();
390 if (engine) {
391 NativeEngine* nativeEngine = engine->GetNativeEngine();
392 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
393 napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
394 NativeValue* nativeValue = reinterpret_cast<NativeValue*>(napiValue);
395 auto jsPixelMap = JsConverter::ConvertNativeValueToJsVal(nativeValue);
396 spanResultObj->SetPropertyObject("value", jsPixelMap);
397 }
398 #endif
399 } else {
400 spanResultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
401 }
402 }
403
JsFocusable(const JSCallbackInfo & info)404 void JSRichEditor::JsFocusable(const JSCallbackInfo& info)
405 {
406 if (info.Length() != 1 || !info[0]->IsBoolean()) {
407 LOGW("The info is wrong, it is supposed to be an boolean");
408 return;
409 }
410 JSInteractableView::SetFocusable(info[0]->ToBoolean());
411 JSInteractableView::SetFocusNode(false);
412 }
413
SetCopyOptions(const JSCallbackInfo & info)414 void JSRichEditor::SetCopyOptions(const JSCallbackInfo& info)
415 {
416 if (info.Length() == 0) {
417 return;
418 }
419 auto copyOptions = CopyOptions::Distributed;
420 auto tmpInfo = info[0];
421 if (tmpInfo->IsNumber()) {
422 auto emunNumber = tmpInfo->ToNumber<int>();
423 copyOptions = static_cast<CopyOptions>(emunNumber);
424 }
425 RichEditorModel::GetInstance()->SetCopyOption(copyOptions);
426 }
427
BindSelectionMenu(const JSCallbackInfo & info)428 void JSRichEditor::BindSelectionMenu(const JSCallbackInfo& info)
429 {
430 RichEditorType editorType = RichEditorType::TEXT;
431 if (info.Length() >= 1 && info[0]->IsNumber()) {
432 auto spanType = info[0]->ToNumber<int32_t>();
433 LOGI("Set the spanType is %{public}d.", spanType);
434 editorType = static_cast<RichEditorType>(spanType);
435 }
436
437 // Builder
438 if (info.Length() < 2 || !info[1]->IsObject()) {
439 return;
440 }
441
442 JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(info[1]);
443 auto builder = menuObj->GetProperty("builder");
444 if (!builder->IsFunction()) {
445 LOGE("builder param is not a function.");
446 return;
447 }
448 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
449 CHECK_NULL_VOID(builderFunc);
450
451 // responseType
452 ResponseType responseType = ResponseType::LONG_PRESS;
453 if (info.Length() >= 3 && info[2]->IsNumber()) {
454 auto response = info[2]->ToNumber<int32_t>();
455 LOGI("Set the responseType is %{public}d.", response);
456 responseType = static_cast<ResponseType>(response);
457 }
458 std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
459 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
460 ACE_SCORING_EVENT("BindSelectionMenu");
461 func->Execute();
462 };
463 SelectMenuParam menuParam;
464 if (info.Length() > 3 && info[3]->IsObject()) {
465 ParseMenuParam(info, info[3], menuParam);
466 }
467 RichEditorModel::GetInstance()->BindSelectionMenu(editorType, responseType, buildFunc, menuParam);
468 }
469
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,SelectMenuParam & menuParam)470 void JSRichEditor::ParseMenuParam(
471 const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, SelectMenuParam& menuParam)
472 {
473 auto onAppearValue = menuOptions->GetProperty("onAppear");
474 if (onAppearValue->IsFunction()) {
475 RefPtr<JsFunction> jsOnAppearFunc =
476 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
477 auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc)](
478 int32_t start, int32_t end) {
479 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
480 ACE_SCORING_EVENT("onAppear");
481
482 JSRef<JSVal> params[2];
483 params[0] = JSRef<JSVal>::Make(ToJSValue(start));
484 params[1] = JSRef<JSVal>::Make(ToJSValue(end));
485 func->ExecuteJS(2, params);
486 };
487 menuParam.onAppear = std::move(onAppear);
488 }
489
490 auto onDisappearValue = menuOptions->GetProperty("onDisappear");
491 if (onDisappearValue->IsFunction()) {
492 RefPtr<JsFunction> jsOnDisAppearFunc =
493 AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
494 auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc)]() {
495 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
496 LOGI("About to call onAppear method on js");
497 ACE_SCORING_EVENT("onDisappear");
498 func->Execute();
499 };
500 menuParam.onDisappear = std::move(onDisappear);
501 }
502 }
503
JSBind(BindingTarget globalObj)504 void JSRichEditor::JSBind(BindingTarget globalObj)
505 {
506 JSClass<JSRichEditor>::Declare("RichEditor");
507 JSClass<JSRichEditor>::StaticMethod("create", &JSRichEditor::Create);
508 JSClass<JSRichEditor>::StaticMethod("onReady", &JSRichEditor::SetOnReady);
509 JSClass<JSRichEditor>::StaticMethod("onSelect", &JSRichEditor::SetOnSelect);
510 JSClass<JSRichEditor>::StaticMethod("aboutToIMEInput", &JSRichEditor::SetAboutToIMEInput);
511 JSClass<JSRichEditor>::StaticMethod("onIMEInputComplete", &JSRichEditor::SetOnIMEInputComplete);
512 JSClass<JSRichEditor>::StaticMethod("aboutToDelete", &JSRichEditor::SetAboutToDelete);
513 JSClass<JSRichEditor>::StaticMethod("onDeleteComplete", &JSRichEditor::SetOnDeleteComplete);
514 JSClass<JSRichEditor>::StaticMethod("customKeyboard", &JSRichEditor::SetCustomKeyboard);
515 JSClass<JSRichEditor>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
516 JSClass<JSRichEditor>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
517 JSClass<JSRichEditor>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
518 JSClass<JSRichEditor>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
519 JSClass<JSRichEditor>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
520 JSClass<JSRichEditor>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
521 JSClass<JSRichEditor>::StaticMethod("focusable", &JSRichEditor::JsFocusable);
522 JSClass<JSRichEditor>::StaticMethod("copyOptions", &JSRichEditor::SetCopyOptions);
523 JSClass<JSRichEditor>::StaticMethod("bindSelectionMenu", &JSRichEditor::BindSelectionMenu);
524 JSClass<JSRichEditor>::InheritAndBind<JSViewAbstract>(globalObj);
525 }
526
ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)527 ImageSpanAttribute JSRichEditorController::ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)
528 {
529 ImageSpanAttribute imageStyle;
530 auto sizeObj = imageAttribute->GetProperty("size");
531 if (sizeObj->IsArray()) {
532 ImageSpanSize imageSize;
533 JSRef<JSArray> size = JSRef<JSArray>::Cast(sizeObj);
534 JSRef<JSVal> width = size->GetValueAt(0);
535 CalcDimension imageSpanWidth;
536 if (!width->IsNull() && JSContainerBase::ParseJsDimensionVp(width, imageSpanWidth)) {
537 imageSize.width = imageSpanWidth;
538 updateSpanStyle_.updateImageWidth = imageSpanWidth;
539 }
540 JSRef<JSVal> height = size->GetValueAt(1);
541 CalcDimension imageSpanHeight;
542 if (!height->IsNull() && JSContainerBase::ParseJsDimensionVp(height, imageSpanHeight)) {
543 imageSize.height = imageSpanHeight;
544 updateSpanStyle_.updateImageHeight = imageSpanHeight;
545 }
546 imageStyle.size = imageSize;
547 }
548 JSRef<JSVal> verticalAlign = imageAttribute->GetProperty("verticalAlign");
549 if (!verticalAlign->IsNull()) {
550 auto align = static_cast<VerticalAlign>(verticalAlign->ToNumber<int32_t>());
551 if (align < VerticalAlign::TOP || align > VerticalAlign::NONE) {
552 align = VerticalAlign::BOTTOM;
553 }
554 imageStyle.verticalAlign = align;
555 updateSpanStyle_.updateImageVerticalAlign = align;
556 }
557 JSRef<JSVal> objectFit = imageAttribute->GetProperty("objectFit");
558 if (!objectFit->IsNull() && objectFit->IsNumber()) {
559 auto fit = static_cast<ImageFit>(objectFit->ToNumber<int32_t>());
560 if (fit < ImageFit::FILL || fit > ImageFit::SCALE_DOWN) {
561 fit = ImageFit::COVER;
562 }
563 imageStyle.objectFit = fit;
564 updateSpanStyle_.updateImageFit = fit;
565 } else {
566 imageStyle.objectFit = ImageFit::COVER;
567 }
568 return imageStyle;
569 }
570
ParseJsTextStyle(JSRef<JSObject> styleObject,struct UpdateSpanStyle & updateSpanStyle)571 TextStyle JSRichEditorController::ParseJsTextStyle(JSRef<JSObject> styleObject, struct UpdateSpanStyle& updateSpanStyle)
572 {
573 TextStyle style;
574 JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
575 Color textColor;
576 if (!fontColor->IsNull() && JSContainerBase::ParseJsColor(fontColor, textColor)) {
577 updateSpanStyle.updateTextColor = textColor;
578 style.SetTextColor(textColor);
579 }
580 JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
581 CalcDimension size;
582 if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFp(fontSize, size)) {
583 updateSpanStyle.updateFontSize = size;
584 style.SetFontSize(size);
585 }
586 JSRef<JSVal> fontStyle = styleObject->GetProperty("fontStyle");
587 if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
588 updateSpanStyle.updateItalicFontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
589 style.SetFontStyle(static_cast<FontStyle>(fontStyle->ToNumber<int32_t>()));
590 }
591 JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
592 std::string weight;
593 if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
594 if (fontWeight->IsNumber()) {
595 weight = std::to_string(fontWeight->ToNumber<int32_t>());
596 }
597 updateSpanStyle.updateFontWeight = ConvertStrToFontWeight(weight);
598 style.SetFontWeight(ConvertStrToFontWeight(weight));
599 }
600 JSRef<JSVal> fontFamily = styleObject->GetProperty("fontFamily");
601 std::vector<std::string> family;
602 if (!fontFamily->IsNull() && JSContainerBase::ParseJsFontFamilies(fontFamily, family)) {
603 updateSpanStyle.updateFontFamily = family;
604 style.SetFontFamilies(family);
605 }
606 auto decorationObj = styleObject->GetProperty("decoration");
607 JSRef<JSObject> decorationObject = JSRef<JSObject>::Cast(decorationObj);
608 if (!decorationObject->IsUndefined()) {
609 JSRef<JSVal> type = decorationObject->GetProperty("type");
610 if (!type->IsNull() && !type->IsUndefined()) {
611 updateSpanStyle.updateTextDecoration = static_cast<TextDecoration>(type->ToNumber<int32_t>());
612 style.SetTextDecoration(static_cast<TextDecoration>(type->ToNumber<int32_t>()));
613 }
614 JSRef<JSVal> color = decorationObject->GetProperty("color");
615 Color decorationColor;
616 if (!color->IsNull() && JSContainerBase::ParseJsColor(color, decorationColor)) {
617 updateSpanStyle.updateTextDecorationColor = decorationColor;
618 style.SetTextDecorationColor(decorationColor);
619 }
620 }
621 return style;
622 }
623
AddImageSpan(const JSCallbackInfo & args)624 void JSRichEditorController::AddImageSpan(const JSCallbackInfo& args)
625 {
626 if (args.Length() < 1) {
627 return;
628 }
629 ImageSpanOptions options;
630 if (!args[0]->IsEmpty() && args[0]->ToString() != "") {
631 options = CreateJsImageOptions(args);
632 } else {
633 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
634 return;
635 }
636 if (options.image.has_value()) {
637 std::string assetSrc = options.image.value();
638 SrcType srcType = ImageSourceInfo::ResolveURIType(assetSrc);
639 if (assetSrc[0] == '/') {
640 assetSrc = assetSrc.substr(1); // get the asset src without '/'.
641 } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
642 assetSrc = assetSrc.substr(2); // get the asset src without './'.
643 }
644 if (srcType == SrcType::ASSET) {
645 auto pipelineContext = PipelineBase::GetCurrentContext();
646 CHECK_NULL_VOID(pipelineContext);
647 auto assetManager = pipelineContext->GetAssetManager();
648 CHECK_NULL_VOID(assetManager);
649 auto assetData = assetManager->GetAsset(assetSrc);
650 if (!assetData) {
651 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
652 return;
653 }
654 }
655 }
656 if (args.Length() > 1 && args[1]->IsObject()) {
657 JSRef<JSObject> imageObject = JSRef<JSObject>::Cast(args[1]);
658
659 JSRef<JSVal> offset = imageObject->GetProperty("offset");
660 int32_t imageOffset = 0;
661 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, imageOffset)) {
662 options.offset = imageOffset;
663 }
664 auto imageStyleObj = imageObject->GetProperty("imageStyle");
665 JSRef<JSObject> imageAttribute = JSRef<JSObject>::Cast(imageStyleObj);
666 if (!imageAttribute->IsUndefined()) {
667 ImageSpanAttribute imageStyle = ParseJsImageSpanAttribute(imageAttribute);
668 options.imageAttribute = imageStyle;
669 }
670 }
671 auto controller = controllerWeak_.Upgrade();
672 int32_t spanIndex = 0;
673 if (controller) {
674 spanIndex = controller->AddImageSpan(options);
675 }
676 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
677 }
678
CreateJsImageOptions(const JSCallbackInfo & args)679 ImageSpanOptions JSRichEditorController::CreateJsImageOptions(const JSCallbackInfo& args)
680 {
681 ImageSpanOptions options;
682 auto context = PipelineBase::GetCurrentContext();
683 CHECK_NULL_RETURN(context, options);
684 bool isCard = context->IsFormRender();
685 std::string image;
686 std::string bundleName;
687 std::string moduleName;
688 bool srcValid = JSContainerBase::ParseJsMedia(args[0], image);
689 if (isCard && args[0]->IsString()) {
690 SrcType srcType = ImageSourceInfo::ResolveURIType(image);
691 bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
692 if (notSupport) {
693 image.clear();
694 }
695 }
696 JSImage::GetJsMediaBundleInfo(args[0], bundleName, moduleName);
697 options.image = image;
698 options.bundleName = bundleName;
699 options.moduleName = moduleName;
700 if (!srcValid) {
701 #if defined(PIXEL_MAP_SUPPORTED)
702 if (!isCard) {
703 if (IsDrawable(args[0])) {
704 options.imagePixelMap = GetDrawablePixmap(args[0]);
705 } else {
706 options.imagePixelMap = CreatePixelMapFromNapiValue(args[0]);
707 }
708 }
709 #endif
710 }
711 return options;
712 }
713
IsDrawable(const JSRef<JSVal> & jsValue)714 bool JSRichEditorController::IsDrawable(const JSRef<JSVal>& jsValue)
715 {
716 if (!jsValue->IsObject()) {
717 return false;
718 }
719 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
720 if (jsObj->IsUndefined()) {
721 return false;
722 }
723 JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
724 return (!func->IsNull() && func->IsFunction());
725 }
726
AddTextSpan(const JSCallbackInfo & args)727 void JSRichEditorController::AddTextSpan(const JSCallbackInfo& args)
728 {
729 if (args.Length() < 1) {
730 return;
731 }
732 TextSpanOptions options;
733 std::string spanValue;
734 if (!args[0]->IsEmpty() && args[0]->ToString() != "" && JSContainerBase::ParseJsString(args[0], spanValue)) {
735 options.value = spanValue;
736 } else {
737 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
738 return;
739 }
740 if (args.Length() > 1 && args[1]->IsObject()) {
741 JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
742 JSRef<JSVal> offset = spanObject->GetProperty("offset");
743 int32_t spanOffset = 0;
744 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
745 options.offset = spanOffset;
746 }
747 auto styleObj = spanObject->GetProperty("style");
748 JSRef<JSObject> styleObject = JSRef<JSObject>::Cast(styleObj);
749 if (!styleObject->IsUndefined()) {
750 TextStyle style = ParseJsTextStyle(styleObject, updateSpanStyle_);
751 options.style = style;
752 }
753 }
754 auto controller = controllerWeak_.Upgrade();
755 int32_t spanIndex = 0;
756 if (controller) {
757 spanIndex = controller->AddTextSpan(options);
758 }
759 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
760 }
761
CreateCreateJSSpansInfo(const RichEditorSelection & info)762 JSRef<JSVal> JSRichEditorController::CreateCreateJSSpansInfo(const RichEditorSelection& info)
763 {
764 uint32_t idx = 0;
765
766 JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
767 JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
768
769 const std::list<ResultObject>& spanObjectList = info.GetSelection().resultObjects;
770 for (const ResultObject& spanObject : spanObjectList) {
771 spanObjectArray->SetValueAt(idx++, JSRichEditor::CreateJSSpanResultObject(spanObject));
772 }
773
774 return JSRef<JSVal>::Cast(spanObjectArray);
775 }
776
GetSpansInfo(const JSCallbackInfo & args)777 void JSRichEditorController::GetSpansInfo(const JSCallbackInfo& args)
778 {
779 int32_t end = -1;
780 int32_t start = -1;
781 if (args[0]->IsObject()) {
782 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
783 JSRef<JSVal> startVal = obj->GetProperty("start");
784 JSRef<JSVal> endVal = obj->GetProperty("end");
785
786 if (!startVal->IsNull() && startVal->IsNumber()) {
787 start = startVal->ToNumber<int32_t>();
788 }
789
790 if (!endVal->IsNull() && endVal->IsNumber()) {
791 end = endVal->ToNumber<int32_t>();
792 }
793 }
794 if (controllerWeak_.Upgrade()) {
795 RichEditorSelection value = controllerWeak_.Upgrade()->GetSpansInfo(start, end);
796 args.SetReturnValue(CreateCreateJSSpansInfo(value));
797 }
798 }
799
DeleteSpans(const JSCallbackInfo & args)800 void JSRichEditorController::DeleteSpans(const JSCallbackInfo& args)
801 {
802 auto controller = controllerWeak_.Upgrade();
803 CHECK_NULL_VOID(controller);
804 if (!args[0]->IsObject() || !controller) {
805 return;
806 }
807 JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[0]);
808 RangeOptions options;
809 JSRef<JSVal> startVal = spanObject->GetProperty("start");
810 int32_t start = 0;
811 if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(startVal, start)) {
812 options.start = start;
813 }
814 JSRef<JSVal> endVal = spanObject->GetProperty("end");
815 int32_t end = 0;
816 if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(endVal, end)) {
817 options.end = end;
818 }
819 controller->DeleteSpans(options);
820 }
821
CloseSelectionMenu()822 void JSRichEditorController::CloseSelectionMenu()
823 {
824 auto controller = controllerWeak_.Upgrade();
825 CHECK_NULL_VOID(controller);
826 controller->CloseSelectionMenu();
827 }
828
JSBind(BindingTarget globalObj)829 void JSRichEditorController::JSBind(BindingTarget globalObj)
830 {
831 JSClass<JSRichEditorController>::Declare("RichEditorController");
832 JSClass<JSRichEditorController>::CustomMethod("addImageSpan", &JSRichEditorController::AddImageSpan);
833 JSClass<JSRichEditorController>::CustomMethod("addTextSpan", &JSRichEditorController::AddTextSpan);
834 JSClass<JSRichEditorController>::CustomMethod("setCaretOffset", &JSRichEditorController::SetCaretOffset);
835 JSClass<JSRichEditorController>::CustomMethod("getCaretOffset", &JSRichEditorController::GetCaretOffset);
836 JSClass<JSRichEditorController>::CustomMethod("updateSpanStyle", &JSRichEditorController::UpdateSpanStyle);
837 JSClass<JSRichEditorController>::CustomMethod("setTypingStyle", &JSRichEditorController::SetTypingStyle);
838 JSClass<JSRichEditorController>::CustomMethod("getSpans", &JSRichEditorController::GetSpansInfo);
839 JSClass<JSRichEditorController>::CustomMethod("deleteSpans", &JSRichEditorController::DeleteSpans);
840 JSClass<JSRichEditorController>::Method("closeSelectionMenu", &JSRichEditorController::CloseSelectionMenu);
841 JSClass<JSRichEditorController>::Bind(
842 globalObj, JSRichEditorController::Constructor, JSRichEditorController::Destructor);
843 }
844
GetCaretOffset(const JSCallbackInfo & args)845 void JSRichEditorController::GetCaretOffset(const JSCallbackInfo& args)
846 {
847 auto controller = controllerWeak_.Upgrade();
848 int32_t caretOffset = -1;
849 if (controller) {
850 caretOffset = controller->GetCaretOffset();
851 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
852 } else {
853 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
854 }
855 }
856
SetCaretOffset(const JSCallbackInfo & args)857 void JSRichEditorController::SetCaretOffset(const JSCallbackInfo& args)
858 {
859 auto controller = controllerWeak_.Upgrade();
860 int32_t caretPosition = -1;
861 bool success = false;
862 JSViewAbstract::ParseJsInteger<int32_t>(args[0], caretPosition);
863 caretPosition = caretPosition < 0 ? -1 : caretPosition;
864 if (controller) {
865 success = controller->SetCaretOffset(caretPosition);
866 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
867 } else {
868 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
869 }
870 }
871
UpdateSpanStyle(const JSCallbackInfo & info)872 void JSRichEditorController::UpdateSpanStyle(const JSCallbackInfo& info)
873 {
874 if (info.Length() < 1) {
875 LOGW("The argv is wrong, it is supposed to have at least 1 argument");
876 return;
877 }
878 if (!info[0]->IsNumber() && !info[0]->IsObject()) {
879 LOGW("info[0] not is Object or Number");
880 return;
881 }
882 auto jsObject = JSRef<JSObject>::Cast(info[0]);
883
884 int32_t start = -1;
885 int32_t end = -1;
886 TextStyle textStyle;
887 ImageSpanAttribute imageStyle;
888 JSContainerBase::ParseJsInt32(jsObject->GetProperty("start"), start);
889 JSContainerBase::ParseJsInt32(jsObject->GetProperty("end"), end);
890 auto richEditorTextStyle = JSRef<JSObject>::Cast(jsObject->GetProperty("textStyle"));
891 auto richEditorImageStyle = JSRef<JSObject>::Cast(jsObject->GetProperty("imageStyle"));
892 updateSpanStyle_.ResetStyle();
893 if (!richEditorTextStyle->IsUndefined()) {
894 textStyle = ParseJsTextStyle(richEditorTextStyle, updateSpanStyle_);
895 }
896 if (!richEditorImageStyle->IsUndefined()) {
897 imageStyle = ParseJsImageSpanAttribute(richEditorImageStyle);
898 }
899
900 auto controller = controllerWeak_.Upgrade();
901 if (controller) {
902 controller->SetUpdateSpanStyle(updateSpanStyle_);
903 controller->UpdateSpanStyle(start, end, textStyle, imageStyle);
904 }
905 }
906
SetTypingStyle(const JSCallbackInfo & info)907 void JSRichEditorController::SetTypingStyle(const JSCallbackInfo& info)
908 {
909 auto controller = controllerWeak_.Upgrade();
910 CHECK_NULL_VOID(controller);
911 if (info.Length() < 1) {
912 LOGW("The argv is wrong, it is supposed to have at least 1 argument");
913 return;
914 }
915 if (!info[0]->IsObject()) {
916 LOGW("info[0] not is Object");
917 return;
918 }
919 TextStyle textStyle;
920 JSRef<JSObject> richEditorTextStyle = JSRef<JSObject>::Cast(info[0]);
921 typingStyle_.ResetStyle();
922 if (!richEditorTextStyle->IsUndefined()) {
923 textStyle = ParseJsTextStyle(richEditorTextStyle, typingStyle_);
924 }
925 controller->SetTypingStyle(typingStyle_, textStyle);
926 }
927 } // namespace OHOS::Ace::Framework
928