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 <optional>
19 #include <string>
20 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
21 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
22 #endif
23
24 #include "base/geometry/dimension.h"
25 #include "base/geometry/ng/size_t.h"
26 #include "base/log/ace_scoring_log.h"
27 #include "bridge/common/utils/utils.h"
28 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
29 #include "bridge/declarative_frontend/engine/functions/js_function.h"
30 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
31 #include "bridge/declarative_frontend/engine/js_types.h"
32 #include "bridge/declarative_frontend/engine/jsi/jsi_types.h"
33 #include "bridge/declarative_frontend/jsview/js_container_base.h"
34 #include "bridge/declarative_frontend/jsview/js_image.h"
35 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
36 #include "bridge/declarative_frontend/jsview/js_layout_manager.h"
37 #include "bridge/declarative_frontend/jsview/js_shape_abstract.h"
38 #include "bridge/declarative_frontend/jsview/js_textfield.h"
39 #include "bridge/declarative_frontend/jsview/js_utils.h"
40 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
41 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
42 #include "bridge/declarative_frontend/jsview/models/richeditor_model_impl.h"
43 #include "bridge/declarative_frontend/style_string/js_span_string.h"
44 #include "core/common/resource/resource_object.h"
45 #include "core/components/common/properties/text_style.h"
46 #include "core/components/common/properties/text_style_parser.h"
47 #include "core/components/text/text_theme.h"
48 #include "core/components_ng/base/view_stack_model.h"
49 #include "core/components_ng/pattern/rich_editor/rich_editor_base_controller.h"
50 #include "core/components_ng/pattern/rich_editor/rich_editor_model.h"
51 #include "core/components_ng/pattern/rich_editor/rich_editor_model_ng.h"
52 #include "core/components_ng/pattern/rich_editor/rich_editor_theme.h"
53 #include "core/components_ng/pattern/rich_editor/selection_info.h"
54 #include "core/components_v2/inspector/utils.h"
55 #include "frameworks/bridge/common/utils/engine_helper.h"
56 #include "frameworks/bridge/declarative_frontend/jsview/js_text.h"
57 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
58
59 namespace OHOS::Ace {
60 std::unique_ptr<RichEditorModel> RichEditorModel::instance_ = nullptr;
61 std::mutex RichEditorModel::mutex_;
GetInstance()62 RichEditorModel* RichEditorModel::GetInstance()
63 {
64 if (!instance_) {
65 std::lock_guard<std::mutex> lock(mutex_);
66 if (!instance_) {
67 #ifdef NG_BUILD
68 instance_.reset(new NG::RichEditorModelNG());
69 #else
70 if (Container::IsCurrentUseNewPipeline()) {
71 instance_.reset(new NG::RichEditorModelNG());
72 } else {
73 // empty implementation
74 instance_.reset(new Framework::RichEditorModelImpl());
75 }
76 #endif
77 }
78 }
79 return instance_.get();
80 }
81 } // namespace OHOS::Ace
82
83 namespace OHOS::Ace::Framework {
84 enum class RenderingStrategy {
85 SINGLE = 0,
86 MULTIPLE_COLOR,
87 MULTIPLE_OPACITY
88 };
89
ParseLengthMetrics(const JSRef<JSObject> & obj)90 CalcDimension JSRichEditor::ParseLengthMetrics(const JSRef<JSObject>& obj)
91 {
92 CalcDimension size;
93 auto value = 0.0;
94 auto valueObj = obj->GetProperty("value");
95 if (!valueObj->IsNull() && valueObj->IsNumber()) {
96 value = valueObj->ToNumber<float>();
97 }
98 auto unit = DimensionUnit::VP;
99 auto unitObj = obj->GetProperty("unit");
100 if (!unitObj->IsNull() && unitObj->IsNumber()) {
101 unit = static_cast<DimensionUnit>(unitObj->ToNumber<int32_t>());
102 }
103 if (value >= 0 && unit != DimensionUnit::PERCENT) {
104 size = CalcDimension(value, unit);
105 }
106 return size;
107 }
ParseMarginAttr(JsiRef<JSVal> marginAttr)108 std::optional<NG::MarginProperty> JSRichEditor::ParseMarginAttr(JsiRef<JSVal> marginAttr)
109 {
110 std::optional<NG::MarginProperty> marginProp = std::nullopt;
111 CalcDimension length;
112 if (!marginAttr->IsObject() && !marginAttr->IsNumber() && !marginAttr->IsString()) {
113 length.Reset();
114 marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
115 return marginProp;
116 }
117 if (JSViewAbstract::ParseJsDimensionVp(marginAttr, length)) {
118 marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
119 } else if (marginAttr->IsObject()) {
120 auto marginObj = JSRef<JSObject>::Cast(marginAttr);
121 if (marginObj->HasProperty("value")) {
122 length = ParseLengthMetrics(marginObj);
123 marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
124 return marginProp;
125 }
126 std::optional<CalcDimension> left;
127 std::optional<CalcDimension> right;
128 std::optional<CalcDimension> top;
129 std::optional<CalcDimension> bottom;
130 JSViewAbstract::ParseMarginOrPaddingCorner(marginObj, top, bottom, left, right);
131 marginProp = NG::ConvertToCalcPaddingProperty(top, bottom, left, right);
132 }
133 return marginProp;
134 }
135
ParseBorderRadiusAttr(JsiRef<JSVal> args)136 std::optional<NG::BorderRadiusProperty> JSRichEditor::ParseBorderRadiusAttr(JsiRef<JSVal> args)
137 {
138 std::optional<NG::BorderRadiusProperty> prop = std::nullopt;
139 CalcDimension radiusDim;
140 if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
141 radiusDim.Reset();
142 NG::BorderRadiusProperty borderRadius;
143 borderRadius.SetRadius(radiusDim);
144 borderRadius.multiValued = false;
145 prop = borderRadius;
146 return prop;
147 }
148 if (JSViewAbstract::ParseJsDimensionVp(args, radiusDim)) {
149 if (radiusDim.Unit() == DimensionUnit::PERCENT) {
150 radiusDim.Reset();
151 }
152 NG::BorderRadiusProperty borderRadius;
153 borderRadius.SetRadius(radiusDim);
154 borderRadius.multiValued = false;
155 prop = borderRadius;
156 } else if (args->IsObject()) {
157 JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
158 if (object->HasProperty("value")) {
159 NG::BorderRadiusProperty borderRadius;
160 borderRadius.SetRadius(ParseLengthMetrics(object));
161 borderRadius.multiValued = false;
162 prop = borderRadius;
163 return prop;
164 }
165 CalcDimension topLeft;
166 CalcDimension topRight;
167 CalcDimension bottomLeft;
168 CalcDimension bottomRight;
169 JSViewAbstract::ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight);
170 NG::BorderRadiusProperty borderRadius;
171 borderRadius.radiusTopLeft = topLeft;
172 borderRadius.radiusTopRight = topRight;
173 borderRadius.radiusBottomLeft = bottomLeft;
174 borderRadius.radiusBottomRight = bottomRight;
175 borderRadius.multiValued = true;
176 prop = borderRadius;
177 }
178 return prop;
179 }
180
Create(const JSCallbackInfo & info)181 void JSRichEditor::Create(const JSCallbackInfo& info)
182 {
183 JSRichEditorBaseController* jsBaseController = nullptr;
184 if (info[0]->IsObject()) {
185 auto paramObject = JSRef<JSObject>::Cast(info[0]);
186 auto controllerObj = paramObject->GetProperty("controller");
187 if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
188 jsBaseController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSRichEditorBaseController>();
189 }
190 }
191 bool isStyledStringMode = jsBaseController && jsBaseController->IsStyledStringMode();
192 RichEditorModel::GetInstance()->Create(isStyledStringMode);
193 RefPtr<RichEditorBaseControllerBase> controller = RichEditorModel::GetInstance()->GetRichEditorController();
194 if (jsBaseController) {
195 jsBaseController->SetInstanceId(Container::CurrentId());
196 jsBaseController->SetController(controller);
197 }
198 }
199
SetOnReady(const JSCallbackInfo & args)200 void JSRichEditor::SetOnReady(const JSCallbackInfo& args)
201 {
202 if (!args[0]->IsFunction()) {
203 return;
204 }
205 JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
206 RichEditorModel::GetInstance()->SetOnReady(callback);
207 }
208
CreateJSTextStyleResult(const TextStyleResult & textStyleResult)209 JSRef<JSObject> JSRichEditor::CreateJSTextStyleResult(const TextStyleResult& textStyleResult)
210 {
211 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
212 textStyleObj->SetProperty<std::string>("fontColor", textStyleResult.fontColor);
213 textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(textStyleResult.fontFeature));
214 textStyleObj->SetProperty<double>("fontSize", textStyleResult.fontSize);
215 textStyleObj->SetProperty<int32_t>("fontStyle", textStyleResult.fontStyle);
216 textStyleObj->SetProperty<double>("lineHeight", textStyleResult.lineHeight);
217 textStyleObj->SetProperty<double>("letterSpacing", textStyleResult.letterSpacing);
218 textStyleObj->SetProperty<int32_t>("fontWeight", textStyleResult.fontWeight);
219 textStyleObj->SetProperty<std::string>("fontFamily", textStyleResult.fontFamily);
220 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
221 decorationObj->SetProperty<int32_t>("type", textStyleResult.decorationType);
222 decorationObj->SetProperty<std::string>("color", textStyleResult.decorationColor);
223 decorationObj->SetProperty<int32_t>("style", textStyleResult.decorationStyle);
224 textStyleObj->SetPropertyObject("decoration", decorationObj);
225 textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(textStyleResult));
226 return textStyleObj;
227 }
228
CreateJsTextShadowObjectArray(const TextStyleResult & textSpanResult)229 JSRef<JSArray> JSRichEditor::CreateJsTextShadowObjectArray(const TextStyleResult& textSpanResult)
230 {
231 return CreateJsTextShadowObjectArray(textSpanResult.textShadows);
232 }
233
CreateJsTextShadowObjectArray(const std::vector<Shadow> & textShadows)234 JSRef<JSArray> JSRichEditor::CreateJsTextShadowObjectArray(const std::vector<Shadow>& textShadows)
235 {
236 JSRef<JSArray> textShadowArray = JSRef<JSArray>::New();
237 int32_t index = 0;
238 for (const auto& it : textShadows) {
239 JSRef<JSObject> textShadowObj = JSRef<JSObject>::New();
240 textShadowObj->SetProperty<double>("radius", it.GetBlurRadius());
241 textShadowObj->SetProperty<std::string>("color", it.GetColor().ToString());
242 textShadowObj->SetProperty<double>("offsetX", it.GetOffset().GetX());
243 textShadowObj->SetProperty<double>("offsetY", it.GetOffset().GetY());
244 textShadowArray->SetValueAt(index, textShadowObj);
245 index++;
246 }
247 return textShadowArray;
248 }
249
CreateJSParagraphStyle(const TextStyleResult & textStyleResult)250 JSRef<JSObject> JSRichEditor::CreateJSParagraphStyle(const TextStyleResult& textStyleResult)
251 {
252 JSRef<JSObject> paragraphStyleObj = JSRef<JSObject>::New();
253 paragraphStyleObj->SetProperty<int32_t>("textAlign", textStyleResult.textAlign);
254 JSRef<JSArray> leadingMarginArray = JSRef<JSArray>::New();
255 leadingMarginArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textStyleResult.leadingMarginSize[0])));
256 leadingMarginArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textStyleResult.leadingMarginSize[1])));
257 paragraphStyleObj->SetPropertyObject("leadingMargin", leadingMarginArray);
258 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
259 paragraphStyleObj->SetProperty<int32_t>("wordBreak", textStyleResult.wordBreak);
260 paragraphStyleObj->SetProperty<int32_t>("lineBreakStrategy", textStyleResult.lineBreakStrategy);
261 }
262 return paragraphStyleObj;
263 }
264
CreateJSSymbolSpanStyleResult(const SymbolSpanStyle & symbolSpanStyle)265 JSRef<JSObject> JSRichEditor::CreateJSSymbolSpanStyleResult(const SymbolSpanStyle& symbolSpanStyle)
266 {
267 JSRef<JSObject> symbolSpanStyleObj = JSRef<JSObject>::New();
268 symbolSpanStyleObj->SetProperty<std::string>("fontColor", symbolSpanStyle.symbolColor);
269 symbolSpanStyleObj->SetProperty<NG::FONT_FEATURES_LIST>("fontFeature", symbolSpanStyle.fontFeature);
270 symbolSpanStyleObj->SetProperty<double>("fontSize", symbolSpanStyle.fontSize);
271 symbolSpanStyleObj->SetProperty<double>("lineHeight", symbolSpanStyle.lineHeight);
272 symbolSpanStyleObj->SetProperty<double>("letterSpacing", symbolSpanStyle.letterSpacing);
273 symbolSpanStyleObj->SetProperty<int32_t>("fontWeight", symbolSpanStyle.fontWeight);
274 symbolSpanStyleObj->SetProperty<uint32_t>("renderingStrategy", symbolSpanStyle.renderingStrategy);
275 symbolSpanStyleObj->SetProperty<uint32_t>("effectStrategy", symbolSpanStyle.effectStrategy);
276
277 return symbolSpanStyleObj;
278 }
279
CreateJSValueResource(const RefPtr<ResourceObject> & valueResource)280 JSRef<JSObject> JSRichEditor::CreateJSValueResource(const RefPtr<ResourceObject>& valueResource)
281 {
282 JSRef<JSObject> valueResourceObj = JSRef<JSObject>::New();
283 valueResourceObj->SetProperty<std::string>("bundleName", valueResource->GetBundleName());
284 valueResourceObj->SetProperty<std::string>("moduleName", valueResource->GetModuleName());
285 valueResourceObj->SetProperty<uint32_t>("id", valueResource->GetId());
286 valueResourceObj->SetProperty<std::vector<ResourceObjectParams>>("params", valueResource->GetParams());
287 valueResourceObj->SetProperty<uint32_t>("type", valueResource->GetType());
288
289 return valueResourceObj;
290 }
291
CreateJSLayoutStyle(const ImageStyleResult & imageStyleResult)292 JSRef<JSObject> JSRichEditor::CreateJSLayoutStyle(const ImageStyleResult& imageStyleResult)
293 {
294 JSRef<JSObject> layoutStyleObj = JSRef<JSObject>::New();
295
296 layoutStyleObj->SetProperty<std::string>("borderRadius", imageStyleResult.borderRadius);
297 layoutStyleObj->SetProperty<std::string>("margin", imageStyleResult.margin);
298
299 return layoutStyleObj;
300 }
301
CreateJSImageStyleResult(const ImageStyleResult & imageStyleResult)302 JSRef<JSObject> JSRichEditor::CreateJSImageStyleResult(const ImageStyleResult& imageStyleResult)
303 {
304 JSRef<JSObject> imageSpanStyleObj = JSRef<JSObject>::New();
305
306 JSRef<JSArray> sizeArray = JSRef<JSArray>::New();
307 sizeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[0])));
308 sizeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[1])));
309 imageSpanStyleObj->SetPropertyObject("size", sizeArray);
310 imageSpanStyleObj->SetProperty<int32_t>("verticalAlign", imageStyleResult.verticalAlign);
311 imageSpanStyleObj->SetProperty<int32_t>("objectFit", imageStyleResult.objectFit);
312 imageSpanStyleObj->SetPropertyObject("layoutStyle", CreateJSLayoutStyle(imageStyleResult));
313
314 return imageSpanStyleObj;
315 }
316
CreateParagraphStyleResult(const ParagraphInfo & info)317 JSRef<JSObject> JSRichEditor::CreateParagraphStyleResult(const ParagraphInfo& info)
318 {
319 auto obj = JSRef<JSObject>::New();
320 obj->SetProperty<int32_t>("textAlign", info.textAlign);
321
322 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
323 obj->SetProperty<int32_t>("wordBreak", info.wordBreak);
324 obj->SetProperty<int32_t>("lineBreakStrategy", info.lineBreakStrategy);
325 }
326 auto lmObj = JSRef<JSObject>::New();
327 auto size = JSRef<JSArray>::New();
328 size->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(info.leadingMarginSize[0])));
329 size->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(info.leadingMarginSize[1])));
330 lmObj->SetPropertyObject("size", size);
331 #ifdef PIXEL_MAP_SUPPORTED
332 if (info.leadingMarginPixmap) {
333 lmObj->SetPropertyObject("pixelMap", ConvertPixmap(info.leadingMarginPixmap));
334 }
335 #endif
336 obj->SetPropertyObject("leadingMargin", lmObj);
337 return obj;
338 }
339
CreateJSSpanResultObject(const ResultObject & resultObject)340 JSRef<JSObject> JSRichEditor::CreateJSSpanResultObject(const ResultObject& resultObject)
341 {
342 JSRef<JSArray> offsetArray = JSRef<JSArray>::New();
343 JSRef<JSArray> spanRangeArray = JSRef<JSArray>::New();
344 JSRef<JSObject> resultObj = JSRef<JSObject>::New();
345 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
346 offsetArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[0])));
347 offsetArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[1])));
348 spanRangeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[0])));
349 spanRangeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[1])));
350 spanPositionObj->SetProperty<int32_t>("spanIndex", resultObject.spanPosition.spanIndex);
351 spanPositionObj->SetPropertyObject("spanRange", spanRangeArray);
352 resultObj->SetPropertyObject("offsetInSpan", offsetArray);
353 resultObj->SetPropertyObject("spanPosition", spanPositionObj);
354 SetJSSpanResultObject(resultObj, resultObject);
355 return resultObj;
356 }
357
SetJSSpanResultObject(JSRef<JSObject> & resultObj,const ResultObject & resultObject)358 void JSRichEditor::SetJSSpanResultObject(JSRef<JSObject>& resultObj, const ResultObject& resultObject)
359 {
360 if (resultObject.type == SelectSpanType::TYPESPAN) {
361 resultObj->SetProperty<std::string>("value", resultObject.valueString);
362 resultObj->SetProperty<std::string>("previewText", resultObject.previewText);
363 resultObj->SetPropertyObject("textStyle", CreateJSTextStyleResult(resultObject.textStyle));
364 resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(resultObject.textStyle));
365 } else if (resultObject.type == SelectSpanType::TYPESYMBOLSPAN) {
366 resultObj->SetProperty<std::string>("value", resultObject.valueString);
367 resultObj->SetPropertyObject("symbolSpanStyle", CreateJSSymbolSpanStyleResult(resultObject.symbolSpanStyle));
368 resultObj->SetPropertyObject("valueResource", CreateJSValueResource(resultObject.valueResource));
369 } else if (resultObject.type == SelectSpanType::TYPEIMAGE) {
370 if (resultObject.valuePixelMap) {
371 #ifdef PIXEL_MAP_SUPPORTED
372 auto jsPixmap = ConvertPixmap(resultObject.valuePixelMap);
373 if (!jsPixmap->IsUndefined()) {
374 resultObj->SetPropertyObject("valuePixelMap", jsPixmap);
375 }
376 #endif
377 } else {
378 resultObj->SetProperty<std::string>("valueResourceStr", resultObject.valueString);
379 }
380 resultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(resultObject.imageStyle));
381 }
382 }
383
CreateJSSelection(const SelectionInfo & selectInfo)384 JSRef<JSVal> JSRichEditor::CreateJSSelection(const SelectionInfo& selectInfo)
385 {
386 uint32_t idx = 0;
387
388 JSRef<JSArray> selectionArray = JSRef<JSArray>::New();
389 JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
390 JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
391
392 const std::list<ResultObject>& spanObjectList = selectInfo.GetSelection().resultObjects;
393 for (const ResultObject& spanObject : spanObjectList) {
394 spanObjectArray->SetValueAt(idx++, CreateJSSpanResultObject(spanObject));
395 }
396
397 selectionArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[0])));
398 selectionArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[1])));
399
400 selectionObject->SetPropertyObject("selection", selectionArray);
401 selectionObject->SetPropertyObject("spans", spanObjectArray);
402 return JSRef<JSVal>::Cast(selectionObject);
403 }
404
SetOnSelect(const JSCallbackInfo & args)405 void JSRichEditor::SetOnSelect(const JSCallbackInfo& args)
406 {
407 if (!args[0]->IsFunction()) {
408 return;
409 }
410 auto jsSelectFunc =
411 AceType::MakeRefPtr<JsEventFunction<SelectionInfo, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJSSelection);
412 auto onSelect = [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
413 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
414 const auto* eventInfo = TypeInfoHelper::DynamicCast<SelectionInfo>(info);
415 func->Execute(*eventInfo);
416 };
417 NG::RichEditorModelNG::GetInstance()->SetOnSelect(std::move(onSelect));
418 }
419
SetOnEditingChange(const JSCallbackInfo & args)420 void JSRichEditor::SetOnEditingChange(const JSCallbackInfo& args)
421 {
422 if (!args[0]->IsFunction()) {
423 return;
424 }
425 JsEventCallback<void(bool)> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
426 NG::RichEditorModelNG::GetInstance()->SetOnEditingChange(std::move(callback));
427 }
428
CreateJSSelectionRange(const SelectionRangeInfo & selectRange)429 JSRef<JSVal> JSRichEditor::CreateJSSelectionRange(const SelectionRangeInfo& selectRange)
430 {
431 JSRef<JSObject> selectionRangeObject = JSRef<JSObject>::New();
432
433 JSRef<JSVal> start = JSRef<JSVal>::Make(ToJSValue(selectRange.start_));
434 JSRef<JSVal> end = JSRef<JSVal>::Make(ToJSValue(selectRange.end_));
435
436 selectionRangeObject->SetPropertyObject("start", start);
437 selectionRangeObject->SetPropertyObject("end", end);
438 return JSRef<JSVal>::Cast(selectionRangeObject);
439 }
440
SetOnSelectionChange(const JSCallbackInfo & args)441 void JSRichEditor::SetOnSelectionChange(const JSCallbackInfo& args)
442 {
443 if (args.Length() < 1 || !args[0]->IsFunction()) {
444 return;
445 }
446 auto jsSelectFunc =
447 AceType::MakeRefPtr<JsEventFunction<SelectionRangeInfo, 1>>(JSRef<JSFunc>::Cast(args[0]),
448 CreateJSSelectionRange);
449 auto onSelectionChange =
450 [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
451 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
452 const auto* eventInfo = TypeInfoHelper::DynamicCast<SelectionRangeInfo>(info);
453 func->Execute(*eventInfo);
454 };
455 NG::RichEditorModelNG::GetInstance()->SetOnSelectionChange(std::move(onSelectionChange));
456 }
457
SetAboutToIMEInput(const JSCallbackInfo & args)458 void JSRichEditor::SetAboutToIMEInput(const JSCallbackInfo& args)
459 {
460 if (!args[0]->IsFunction()) {
461 return;
462 }
463 auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorInsertValue, 1>>(
464 JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToIMEInputObj);
465 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
466 const NG::RichEditorInsertValue& insertValue) -> bool {
467 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
468 auto ret = func->ExecuteWithValue(insertValue);
469 if (ret->IsBoolean()) {
470 return ret->ToBoolean();
471 }
472 return true;
473 };
474 RichEditorModel::GetInstance()->SetAboutToIMEInput(std::move(callback));
475 }
476
SetOnIMEInputComplete(const JSCallbackInfo & args)477 void JSRichEditor::SetOnIMEInputComplete(const JSCallbackInfo& args)
478 {
479 if (!args[0]->IsFunction()) {
480 return;
481 }
482 auto jsOnIMEInputCompleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorAbstractSpanResult, 1>>(
483 JSRef<JSFunc>::Cast(args[0]), CreateJsOnIMEInputComplete);
484 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnIMEInputCompleteFunc)](
485 const NG::RichEditorAbstractSpanResult& textSpanResult) {
486 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
487 func->Execute(textSpanResult);
488 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
489 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onIMEInputComplete");
490 #endif
491 };
492 RichEditorModel::GetInstance()->SetOnIMEInputComplete(std::move(callback));
493 }
494
SetOnDidIMEInput(const JSCallbackInfo & args)495 void JSRichEditor::SetOnDidIMEInput(const JSCallbackInfo& args)
496 {
497 CHECK_NULL_VOID(args[0]->IsFunction());
498 auto jsOnDidIMEInputFunc =
499 AceType::MakeRefPtr<JsEventFunction<TextRange, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJsOnDidIMEInput);
500 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnDidIMEInputFunc)](
501 const TextRange& textRange) {
502 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
503 func->Execute(textRange);
504 };
505 RichEditorModel::GetInstance()->SetOnDidIMEInput(std::move(callback));
506 }
507
SetAboutToDelete(const JSCallbackInfo & args)508 void JSRichEditor::SetAboutToDelete(const JSCallbackInfo& args)
509 {
510 if (!args[0]->IsFunction()) {
511 return;
512 }
513 auto jsAboutToDeleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorDeleteValue, 1>>(
514 JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToDelet);
515 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToDeleteFunc)](
516 const NG::RichEditorDeleteValue& deleteValue) -> bool {
517 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
518 auto ret = func->ExecuteWithValue(deleteValue);
519 if (ret->IsBoolean()) {
520 return ret->ToBoolean();
521 }
522 return true;
523 };
524 RichEditorModel::GetInstance()->SetAboutToDelete(std::move(callback));
525 }
526
SetOnDeleteComplete(const JSCallbackInfo & args)527 void JSRichEditor::SetOnDeleteComplete(const JSCallbackInfo& args)
528 {
529 if (!args[0]->IsFunction()) {
530 return;
531 }
532 JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
533 RichEditorModel::GetInstance()->SetOnDeleteComplete(callback);
534 }
535
SetOnWillChange(const JSCallbackInfo & info)536 void JSRichEditor::SetOnWillChange(const JSCallbackInfo& info)
537 {
538 if (!info[0]->IsFunction()) {
539 return;
540 }
541 auto jsOnWillChangeFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorChangeValue, 1>>(
542 JSRef<JSFunc>::Cast(info[0]), CreateJsOnWillChange);
543 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsOnWillChangeFunc)](
544 const NG::RichEditorChangeValue& changeValue) -> bool {
545 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
546 auto ret = func->ExecuteWithValue(changeValue);
547 if (ret->IsBoolean()) {
548 return ret->ToBoolean();
549 }
550 return true;
551 };
552 RichEditorModel::GetInstance()->SetOnWillChange(std::move(callback));
553 }
554
SetOnDidChange(const JSCallbackInfo & info)555 void JSRichEditor::SetOnDidChange(const JSCallbackInfo& info)
556 {
557 if (!info[0]->IsFunction()) {
558 return;
559 }
560 auto JsEventCallback =
561 AceType::MakeRefPtr<JsCommonEventFunction<NG::RichEditorChangeValue, 2>>(JSRef<JSFunc>::Cast(info[0]));
562 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(JsEventCallback)](
563 const NG::RichEditorChangeValue& changeValue) {
564 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
565 const auto& rangeBefore = changeValue.GetRangeBefore();
566 JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
567 rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
568 rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
569
570 const auto& rangeAfter = changeValue.GetRangeAfter();
571 JSRef<JSObject> rangeAfterObj = JSRef<JSObject>::New();
572 rangeAfterObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeAfter.start)));
573 rangeAfterObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeAfter.end)));
574
575 JSRef<JSVal> param[2] = { JSRef<JSVal>::Cast(rangeBeforeObj), JSRef<JSVal>::Cast(rangeAfterObj) };
576 func->Execute(param);
577 };
578 RichEditorModel::GetInstance()->SetOnDidChange(std::move(callback));
579 }
580
SetOnCut(const JSCallbackInfo & info)581 void JSRichEditor::SetOnCut(const JSCallbackInfo& info)
582 {
583 CHECK_NULL_VOID(info[0]->IsFunction());
584 auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
585 JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
586 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
587 auto onCut = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
588 NG::TextCommonEvent& info) {
589 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
590 ACE_SCORING_EVENT("onCut");
591 PipelineContext::SetCallBackNode(node);
592 func->Execute(info);
593 };
594 RichEditorModel::GetInstance()->SetOnCut(std::move(onCut));
595 }
596
SetOnCopy(const JSCallbackInfo & info)597 void JSRichEditor::SetOnCopy(const JSCallbackInfo& info)
598 {
599 CHECK_NULL_VOID(info[0]->IsFunction());
600 auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
601 JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
602 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
603 auto onCopy = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
604 NG::TextCommonEvent& info) {
605 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
606 ACE_SCORING_EVENT("onCopy");
607 PipelineContext::SetCallBackNode(node);
608 func->Execute(info);
609 };
610 RichEditorModel::GetInstance()->SetOnCopy(std::move(onCopy));
611 }
612
EditMenuOptions(const JSCallbackInfo & info)613 void JSRichEditor::EditMenuOptions(const JSCallbackInfo& info)
614 {
615 NG::OnCreateMenuCallback onCreateMenuCallback;
616 NG::OnMenuItemClickCallback onMenuItemClick;
617 JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
618 RichEditorModel::GetInstance()->SetSelectionMenuOptions(
619 std::move(onCreateMenuCallback), std::move(onMenuItemClick));
620 }
621
SetCustomKeyboard(const JSCallbackInfo & args)622 void JSRichEditor::SetCustomKeyboard(const JSCallbackInfo& args)
623 {
624 if (args.Length() > 0 && (args[0]->IsUndefined() || args[0]->IsNull())) {
625 RichEditorModel::GetInstance()->SetCustomKeyboard(nullptr);
626 return;
627 }
628 if (!args[0]->IsObject()) {
629 return;
630 }
631 bool supportAvoidance = false;
632 if (args.Length() == 2 && args[1]->IsObject()) { // 2 here refers to the number of parameters
633 auto paramObject = JSRef<JSObject>::Cast(args[1]);
634 auto isSupportAvoidance = paramObject->GetProperty("supportAvoidance");
635 if (!isSupportAvoidance->IsNull() && isSupportAvoidance->IsBoolean()) {
636 supportAvoidance = isSupportAvoidance->ToBoolean();
637 }
638 }
639 std::function<void()> buildFunc;
640 if (JSTextField::ParseJsCustomKeyboardBuilder(args, 0, buildFunc)) {
641 RichEditorModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance);
642 }
643 }
644
CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue & insertValue)645 JSRef<JSVal> JSRichEditor::CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue& insertValue)
646 {
647 JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
648 aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.GetInsertOffset());
649 aboutToIMEInputObj->SetProperty<std::string>("insertValue", insertValue.GetInsertValue());
650 aboutToIMEInputObj->SetProperty<std::string>("previewText", insertValue.GetPreviewText());
651 return JSRef<JSVal>::Cast(aboutToIMEInputObj);
652 }
653
CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult & textSpanResult)654 JSRef<JSVal> JSRichEditor::CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult& textSpanResult)
655 {
656 JSRef<JSObject> onIMEInputCompleteObj = JSRef<JSObject>::New();
657 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
658 JSRef<JSArray> spanRange = JSRef<JSArray>::New();
659 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
660 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
661 JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
662 spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeStart())));
663 spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeEnd())));
664 offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan())));
665 offsetInSpan->SetValueAt(
666 1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan() + textSpanResult.GetEraseLength())));
667 spanPositionObj->SetPropertyObject("spanRange", spanRange);
668 spanPositionObj->SetProperty<int32_t>("spanIndex", textSpanResult.GetSpanIndex());
669 decorationObj->SetProperty<int32_t>("type", static_cast<int32_t>(textSpanResult.GetTextDecoration()));
670 decorationObj->SetProperty<std::string>("color", textSpanResult.GetColor());
671 decorationObj->SetProperty<int32_t>("style", static_cast<int32_t>(textSpanResult.GetTextDecorationStyle()));
672 textStyleObj->SetProperty<std::string>("fontColor", textSpanResult.GetFontColor());
673 textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(textSpanResult.GetFontFeatures()));
674 textStyleObj->SetProperty<double>("fontSize", textSpanResult.GetFontSize());
675 textStyleObj->SetProperty<double>("lineHeight", textSpanResult.GetTextStyle().lineHeight);
676 textStyleObj->SetProperty<double>("letterSpacing", textSpanResult.GetTextStyle().letterSpacing);
677 textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(textSpanResult.GetFontStyle()));
678 textStyleObj->SetProperty<int32_t>("fontWeight", textSpanResult.GetFontWeight());
679 textStyleObj->SetProperty<std::string>("fontFamily", textSpanResult.GetFontFamily());
680 textStyleObj->SetPropertyObject("decoration", decorationObj);
681 textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(textSpanResult.GetTextStyle()));
682 onIMEInputCompleteObj->SetPropertyObject("spanPosition", spanPositionObj);
683 onIMEInputCompleteObj->SetProperty<std::string>("value", textSpanResult.GetValue());
684 onIMEInputCompleteObj->SetProperty<std::string>("previewText", textSpanResult.GetPreviewText());
685 onIMEInputCompleteObj->SetPropertyObject("textStyle", textStyleObj);
686 onIMEInputCompleteObj->SetPropertyObject("offsetInSpan", offsetInSpan);
687 onIMEInputCompleteObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(textSpanResult.GetTextStyle()));
688 return JSRef<JSVal>::Cast(onIMEInputCompleteObj);
689 }
690
CreateJsOnDidIMEInput(const TextRange & range)691 JSRef<JSVal> JSRichEditor::CreateJsOnDidIMEInput(const TextRange& range)
692 {
693 JSRef<JSObject> rangeObj = JSRef<JSObject>::New();
694 rangeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(range.start)));
695 rangeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(range.end)));
696 return JSRef<JSVal>::Cast(rangeObj);
697 }
698
CreateJsAboutToDelet(const NG::RichEditorDeleteValue & deleteValue)699 JSRef<JSVal> JSRichEditor::CreateJsAboutToDelet(const NG::RichEditorDeleteValue& deleteValue)
700 {
701 JSRef<JSObject> AboutToDeletObj = JSRef<JSObject>::New();
702 AboutToDeletObj->SetProperty<int32_t>("offset", deleteValue.GetOffset());
703 AboutToDeletObj->SetProperty<int32_t>(
704 "direction", static_cast<int32_t>(deleteValue.GetRichEditorDeleteDirection()));
705 AboutToDeletObj->SetProperty<int32_t>("length", deleteValue.GetLength());
706 AboutToDeletObj->SetPropertyObject("richEditorDeleteSpans", CreateJSDeleteSpans(deleteValue));
707 return JSRef<JSVal>::Cast(AboutToDeletObj);
708 }
709
CreateJSDeleteSpans(const NG::RichEditorDeleteValue & deleteValue)710 JSRef<JSArray> JSRichEditor::CreateJSDeleteSpans(const NG::RichEditorDeleteValue& deleteValue)
711 {
712 JSRef<JSArray> richEditorDeleteSpans = JSRef<JSArray>::New();
713 int32_t index = 0;
714 auto list = deleteValue.GetRichEditorDeleteSpans();
715 for (const auto& it : list) {
716 JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
717 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
718 JSRef<JSArray> spanRange = JSRef<JSArray>::New();
719 JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
720 spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
721 spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
722 offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
723 offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
724 spanPositionObj->SetPropertyObject("spanRange", spanRange);
725 spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
726 spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
727 spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
728 SetJSDeleteSpan(spanResultObj, it);
729 richEditorDeleteSpans->SetValueAt(index++, spanResultObj);
730 }
731 return richEditorDeleteSpans;
732 }
733
SetJSDeleteSpan(JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & it)734 void JSRichEditor::SetJSDeleteSpan(JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& it)
735 {
736 switch (it.GetType()) {
737 case NG::SpanResultType::TEXT: {
738 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
739 CreateTextStyleObj(textStyleObj, it);
740 spanResultObj->SetProperty<std::string>("value", it.GetValue());
741 spanResultObj->SetProperty<std::string>("previewText", it.GetPreviewText());
742 spanResultObj->SetPropertyObject("textStyle", textStyleObj);
743 spanResultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(it.GetTextStyle()));
744 break;
745 }
746 case NG::SpanResultType::IMAGE: {
747 JSRef<JSObject> imageStyleObj = JSRef<JSObject>::New();
748 CreateImageStyleObj(imageStyleObj, spanResultObj, it);
749 JSRef<JSObject> layoutStyleObj = JSRef<JSObject>::New();
750 layoutStyleObj->SetProperty<std::string>("borderRadius", it.GetBorderRadius());
751 layoutStyleObj->SetProperty<std::string>("margin", it.GetMargin());
752 imageStyleObj->SetPropertyObject("layoutStyle", layoutStyleObj);
753 spanResultObj->SetPropertyObject("imageStyle", imageStyleObj);
754 break;
755 }
756 case NG::SpanResultType::SYMBOL: {
757 spanResultObj->SetProperty<std::string>("value", it.GetValueString());
758 spanResultObj->SetPropertyObject(
759 "symbolSpanStyle", CreateJSSymbolSpanStyleResult(it.GetSymbolSpanStyle()));
760 spanResultObj->SetPropertyObject("valueResource", CreateJSValueResource(it.GetValueResource()));
761 break;
762 }
763 default:
764 break;
765 }
766 }
767
SetChangeTextSpans(JSRef<JSArray> & jsArray,const std::vector<NG::RichEditorAbstractSpanResult> & spanList)768 void JSRichEditor::SetChangeTextSpans(
769 JSRef<JSArray>& jsArray, const std::vector<NG::RichEditorAbstractSpanResult>& spanList)
770 {
771 int32_t index = 0;
772 for (const auto& it : spanList) {
773 JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
774 JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
775 JSRef<JSArray> spanRange = JSRef<JSArray>::New();
776 JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
777 spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
778 spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
779 offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
780 offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
781 spanPositionObj->SetPropertyObject("spanRange", spanRange);
782 spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
783 spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
784 spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
785 switch (it.GetType()) {
786 case NG::SpanResultType::TEXT:
787 SetTextChangeSpanResult(spanResultObj, it);
788 break;
789 case NG::SpanResultType::IMAGE:
790 SetImageChangeSpanResult(spanResultObj, it);
791 break;
792 case NG::SpanResultType::SYMBOL:
793 SetSymbolChangeSpanResult(spanResultObj, it);
794 break;
795 default:
796 break;
797 }
798 jsArray->SetValueAt(index++, spanResultObj);
799 }
800 }
801
SetTextChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)802 void JSRichEditor::SetTextChangeSpanResult(JSRef<JSObject>& resultObj,
803 const NG::RichEditorAbstractSpanResult& spanResult)
804 {
805 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
806 CreateTextStyleObj(textStyleObj, spanResult);
807 resultObj->SetProperty<std::string>("value", spanResult.GetValue());
808 resultObj->SetProperty<std::string>("previewText", spanResult.GetPreviewText());
809 resultObj->SetPropertyObject("textStyle", textStyleObj);
810 resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(spanResult.GetTextStyle()));
811 }
812
SetSymbolChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)813 void JSRichEditor::SetSymbolChangeSpanResult(JSRef<JSObject>& resultObj,
814 const NG::RichEditorAbstractSpanResult& spanResult)
815 {
816 resultObj->SetProperty<std::string>("value", spanResult.GetValue());
817 resultObj->SetPropertyObject("symbolSpanStyle", CreateJSSymbolSpanStyleResult(spanResult.GetSymbolSpanStyle()));
818 resultObj->SetPropertyObject("valueResource", CreateJSValueResource(spanResult.GetValueResource()));
819 resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(spanResult.GetTextStyle()));
820 }
821
SetImageChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)822 void JSRichEditor::SetImageChangeSpanResult(JSRef<JSObject>& resultObj,
823 const NG::RichEditorAbstractSpanResult& spanResult)
824 {
825 auto valuePixelMap = spanResult.GetValuePixelMap();
826 auto returnWidth = spanResult.GetSizeWidth();
827 auto returnHeight = spanResult.GetSizeHeight();
828 if (valuePixelMap) {
829 #ifdef PIXEL_MAP_SUPPORTED
830 if (NearZero(returnWidth) || NearZero(returnHeight)) {
831 returnWidth = valuePixelMap->GetWidth();
832 returnHeight = valuePixelMap->GetHeight();
833 }
834 auto jsPixmap = ConvertPixmap(valuePixelMap);
835 if (!jsPixmap->IsUndefined()) {
836 resultObj->SetPropertyObject("valuePixelMap", jsPixmap);
837 }
838 #endif
839 } else {
840 resultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
841 }
842 ImageStyleResult imageStyleResult;
843 imageStyleResult.size[0] = static_cast<double>(returnWidth);
844 imageStyleResult.size[1] = static_cast<double>(returnHeight);
845 imageStyleResult.verticalAlign = static_cast<int32_t>(spanResult.GetVerticalAlign());
846 imageStyleResult.objectFit = static_cast<int32_t>(spanResult.GetObjectFit());
847 imageStyleResult.borderRadius = spanResult.GetBorderRadius();
848 imageStyleResult.margin = spanResult.GetMargin();
849 resultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(imageStyleResult));
850 }
851
CreateJsOnWillChange(const NG::RichEditorChangeValue & changeValue)852 JSRef<JSVal> JSRichEditor::CreateJsOnWillChange(const NG::RichEditorChangeValue& changeValue)
853 {
854 JSRef<JSObject> OnWillChangeObj = JSRef<JSObject>::New();
855
856 const auto& rangeBefore = changeValue.GetRangeBefore();
857 JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
858 rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
859 rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
860 OnWillChangeObj->SetPropertyObject("rangeBefore", rangeBeforeObj);
861
862 JSRef<JSArray> replacedSpans = JSRef<JSArray>::New();
863 SetChangeTextSpans(replacedSpans, changeValue.GetRichEditorReplacedSpans());
864 OnWillChangeObj->SetPropertyObject("replacedSpans", replacedSpans);
865
866 JSRef<JSArray> replacedImageSpans = JSRef<JSArray>::New();
867 SetChangeTextSpans(replacedImageSpans, changeValue.GetRichEditorReplacedImageSpans());
868 OnWillChangeObj->SetPropertyObject("replacedImageSpans", replacedImageSpans);
869
870 JSRef<JSArray> replacedSymbolSpans = JSRef<JSArray>::New();
871 SetChangeTextSpans(replacedSymbolSpans, changeValue.GetRichEditorReplacedSymbolSpans());
872 OnWillChangeObj->SetPropertyObject("replacedSymbolSpans", replacedSymbolSpans);
873
874 return JSRef<JSVal>::Cast(OnWillChangeObj);
875 }
876
CreateJsOnDidChange(const std::vector<NG::RichEditorAbstractSpanResult> & spanList)877 JSRef<JSVal> JSRichEditor::CreateJsOnDidChange(const std::vector<NG::RichEditorAbstractSpanResult>& spanList)
878 {
879 JSRef<JSArray> richEditorReplacedSpans = JSRef<JSArray>::New();
880 SetChangeTextSpans(richEditorReplacedSpans, spanList);
881 return JSRef<JSVal>::Cast(richEditorReplacedSpans);
882 }
883
CreateTextStyleObj(JSRef<JSObject> & textStyleObj,const NG::RichEditorAbstractSpanResult & spanResult)884 void JSRichEditor::CreateTextStyleObj(JSRef<JSObject>& textStyleObj, const NG::RichEditorAbstractSpanResult& spanResult)
885 {
886 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
887 decorationObj->SetProperty<int32_t>("type", (int32_t)(spanResult.GetTextDecoration()));
888 decorationObj->SetProperty<std::string>("color", spanResult.GetColor());
889 decorationObj->SetProperty<int32_t>("style", (int32_t)(spanResult.GetTextDecorationStyle()));
890 textStyleObj->SetProperty<std::string>("fontColor", spanResult.GetFontColor());
891 textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(spanResult.GetFontFeatures()));
892 textStyleObj->SetProperty<double>("fontSize", spanResult.GetFontSize());
893 textStyleObj->SetProperty<double>("lineHeight", spanResult.GetTextStyle().lineHeight);
894 textStyleObj->SetProperty<double>("letterSpacing", spanResult.GetTextStyle().letterSpacing);
895 textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(spanResult.GetFontStyle()));
896 textStyleObj->SetProperty<int32_t>("fontWeight", spanResult.GetFontWeight());
897 textStyleObj->SetProperty<std::string>("fontFamily", spanResult.GetFontFamily());
898 textStyleObj->SetPropertyObject("decoration", decorationObj);
899 textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(spanResult.GetTextStyle()));
900 }
901
CreateImageStyleObj(JSRef<JSObject> & imageStyleObj,JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & spanResult)902 void JSRichEditor::CreateImageStyleObj(
903 JSRef<JSObject>& imageStyleObj, JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& spanResult)
904 {
905 JSRef<JSArray> imageSize = JSRef<JSArray>::New();
906 imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeWidth())));
907 imageSize->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeHeight())));
908 imageStyleObj->SetPropertyObject("size", imageSize);
909 imageStyleObj->SetProperty<int32_t>("verticalAlign", static_cast<int32_t>(spanResult.GetVerticalAlign()));
910 imageStyleObj->SetProperty<int32_t>("objectFit", static_cast<int32_t>(spanResult.GetObjectFit()));
911 if (spanResult.GetValuePixelMap()) {
912 #ifdef PIXEL_MAP_SUPPORTED
913 auto jsPixmap = ConvertPixmap(spanResult.GetValuePixelMap());
914 if (!jsPixmap->IsUndefined()) {
915 spanResultObj->SetPropertyObject("value", jsPixmap);
916 }
917 #endif
918 } else {
919 spanResultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
920 }
921 }
922
JsClip(const JSCallbackInfo & info)923 void JSRichEditor::JsClip(const JSCallbackInfo& info)
924 {
925 if (info[0]->IsUndefined()) {
926 ViewAbstractModel::GetInstance()->SetClipEdge(true);
927 return;
928 }
929 if (info[0]->IsObject()) {
930 JSShapeAbstract* clipShape = JSRef<JSObject>::Cast(info[0])->Unwrap<JSShapeAbstract>();
931 if (clipShape == nullptr) {
932 return;
933 }
934 ViewAbstractModel::GetInstance()->SetClipShape(clipShape->GetBasicShape());
935 } else if (info[0]->IsBoolean()) {
936 ViewAbstractModel::GetInstance()->SetClipEdge(info[0]->ToBoolean());
937 }
938 }
939
JsFocusable(const JSCallbackInfo & info)940 void JSRichEditor::JsFocusable(const JSCallbackInfo& info)
941 {
942 if (info.Length() != 1 || !info[0]->IsBoolean()) {
943 return;
944 }
945 JSInteractableView::SetFocusable(info[0]->ToBoolean());
946 JSInteractableView::SetFocusNode(false);
947 }
948
SetCopyOptions(const JSCallbackInfo & info)949 void JSRichEditor::SetCopyOptions(const JSCallbackInfo& info)
950 {
951 if (info.Length() == 0) {
952 return;
953 }
954 auto copyOptions = CopyOptions::Distributed;
955 auto tmpInfo = info[0];
956 if (tmpInfo->IsNumber()) {
957 auto emunNumber = tmpInfo->ToNumber<int>();
958 copyOptions = static_cast<CopyOptions>(emunNumber);
959 }
960 RichEditorModel::GetInstance()->SetCopyOption(copyOptions);
961 }
962
BindSelectionMenu(const JSCallbackInfo & info)963 void JSRichEditor::BindSelectionMenu(const JSCallbackInfo& info)
964 {
965 NG::TextSpanType editorType = NG::TextSpanType::NONE;
966 if (info.Length() >= 1 && info[0]->IsUndefined()) {
967 editorType = NG::TextSpanType::TEXT;
968 }
969 if (info.Length() >= 1 && info[0]->IsNumber()) {
970 auto spanType = info[0]->ToNumber<int32_t>();
971 editorType = static_cast<NG::TextSpanType>(spanType);
972 }
973
974 // Builder
975 if (info.Length() < 2 || !info[1]->IsObject()) {
976 return;
977 }
978
979 JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(info[1]);
980 auto builder = menuObj->GetProperty("builder");
981 if (!builder->IsFunction()) {
982 return;
983 }
984 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
985 CHECK_NULL_VOID(builderFunc);
986
987 // responseType
988 NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
989 if (info.Length() >= 3 && info[2]->IsNumber()) {
990 auto response = info[2]->ToNumber<int32_t>();
991 responseType = static_cast<NG::TextResponseType>(response);
992 }
993 std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
994 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
995 ACE_SCORING_EVENT("BindSelectionMenu");
996 func->Execute();
997 };
998 NG::SelectMenuParam menuParam;
999 int32_t requiredParamCount = 3;
1000 if (info.Length() > requiredParamCount && info[requiredParamCount]->IsObject()) {
1001 JSRef<JSObject> menuOptions = info[requiredParamCount];
1002 JSText::ParseMenuParam(info, menuOptions, menuParam);
1003 auto menuType = menuOptions->GetProperty("menuType");
1004 bool isPreviewMenu = menuType->IsNumber() && menuType->ToNumber<int32_t>() == 1;
1005 bool bindImagePreviewMenu = isPreviewMenu
1006 && responseType == NG::TextResponseType::LONG_PRESS
1007 && editorType == NG::TextSpanType::IMAGE;
1008 if (bindImagePreviewMenu) {
1009 RichEditorModel::GetInstance()->SetImagePreviewMenuParam(buildFunc, menuParam);
1010 return;
1011 }
1012 }
1013 RichEditorModel::GetInstance()->BindSelectionMenu(editorType, responseType, buildFunc, menuParam);
1014 }
1015
CreateJSTextCommonEvent(NG::TextCommonEvent & event)1016 JSRef<JSVal> JSRichEditor::CreateJSTextCommonEvent(NG::TextCommonEvent& event)
1017 {
1018 JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1019 objectTemplate->SetInternalFieldCount(1);
1020 JSRef<JSObject> object = objectTemplate->NewInstance();
1021 object->SetPropertyObject("preventDefault", JSRef<JSFunc>::New<FunctionCallback>(JsPreventDefault));
1022 object->Wrap<NG::TextCommonEvent>(&event);
1023 return JSRef<JSVal>::Cast(object);
1024 }
1025
SetOnPaste(const JSCallbackInfo & info)1026 void JSRichEditor::SetOnPaste(const JSCallbackInfo& info)
1027 {
1028 CHECK_NULL_VOID(info[0]->IsFunction());
1029 auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
1030 JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
1031 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1032 auto onPaste = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
1033 NG::TextCommonEvent& info) {
1034 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1035 ACE_SCORING_EVENT("onPaste");
1036 PipelineContext::SetCallBackNode(node);
1037 func->Execute(info);
1038 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
1039 UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onPaste");
1040 #endif
1041 };
1042 RichEditorModel::GetInstance()->SetOnPaste(std::move(onPaste));
1043 }
1044
JsEnableDataDetector(const JSCallbackInfo & info)1045 void JSRichEditor::JsEnableDataDetector(const JSCallbackInfo& info)
1046 {
1047 if (info.Length() < 1) {
1048 return;
1049 }
1050 auto tmpInfo = info[0];
1051 if (!tmpInfo->IsBoolean()) {
1052 RichEditorModel::GetInstance()->SetTextDetectEnable(false);
1053 return;
1054 }
1055 auto enable = tmpInfo->ToBoolean();
1056 RichEditorModel::GetInstance()->SetTextDetectEnable(enable);
1057 }
1058
JsEnablePreviewText(const JSCallbackInfo & info)1059 void JSRichEditor::JsEnablePreviewText(const JSCallbackInfo& info)
1060 {
1061 if (info.Length() < 1) {
1062 return;
1063 }
1064 auto tmpInfo = info[0];
1065 if (!tmpInfo->IsBoolean()) {
1066 RichEditorModel::GetInstance()->SetSupportPreviewText(true);
1067 return;
1068 }
1069 auto enable = tmpInfo->ToBoolean();
1070 RichEditorModel::GetInstance()->SetSupportPreviewText(enable);
1071 }
1072
SetPlaceholder(const JSCallbackInfo & info)1073 void JSRichEditor::SetPlaceholder(const JSCallbackInfo& info)
1074 {
1075 if (info.Length() < 1) {
1076 return;
1077 }
1078 auto pipelineContext = PipelineBase::GetCurrentContext();
1079 if (!pipelineContext) {
1080 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1081 return;
1082 }
1083 std::string placeholderValue;
1084 PlaceholderOptions options;
1085 JSContainerBase::ParseJsString(info[0], placeholderValue);
1086 options.value = placeholderValue;
1087 Font font;
1088 if (info.Length() > 1 && info[1]->IsObject()) {
1089 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[1]);
1090 auto fontObject = object->GetProperty("font");
1091 if (fontObject->IsObject()) {
1092 ParseJsFont(fontObject, font);
1093 }
1094 JSRef<JSVal> colorVal = object->GetProperty("fontColor");
1095 Color fontColor;
1096 if (!colorVal->IsNull() && JSContainerBase::ParseJsColor(colorVal, fontColor)) {
1097 options.fontColor = fontColor;
1098 }
1099 }
1100 auto textTheme = pipelineContext->GetTheme<TextTheme>();
1101 TextStyle textStyle = textTheme ? textTheme->GetTextStyle() : TextStyle();
1102 options.fontSize = font.fontSize.value_or(textStyle.GetFontSize());
1103 options.fontFamilies = !font.fontFamilies.empty() ? font.fontFamilies : textStyle.GetFontFamilies();
1104 options.fontWeight = font.fontWeight.value_or(textStyle.GetFontWeight());
1105 options.fontStyle = font.fontStyle.value_or(textStyle.GetFontStyle());
1106 if (!options.fontColor.has_value()) {
1107 Color fontColor;
1108 auto richEditorTheme = pipelineContext->GetTheme<NG::RichEditorTheme>();
1109 options.fontColor = richEditorTheme ? richEditorTheme->GetPlaceholderColor() : fontColor;
1110 }
1111 RichEditorModel::GetInstance()->SetPlaceholder(options);
1112 }
1113
ParseJsFont(const JSRef<JSObject> & fontObject,Font & font)1114 void JSRichEditor::ParseJsFont(const JSRef<JSObject>& fontObject, Font& font)
1115 {
1116 if (fontObject->IsUndefined()) {
1117 return;
1118 }
1119 JSRef<JSVal> fontSize = fontObject->GetProperty("size");
1120 CalcDimension size;
1121 if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size) && !size.IsNegative() &&
1122 size.Unit() != DimensionUnit::PERCENT) {
1123 font.fontSize = size;
1124 } else if (size.IsNegative() || size.Unit() == DimensionUnit::PERCENT) {
1125 auto theme = JSContainerBase::GetTheme<TextTheme>();
1126 CHECK_NULL_VOID(theme);
1127 size = theme->GetTextStyle().GetFontSize();
1128 font.fontSize = size;
1129 }
1130
1131 JSRef<JSVal> fontStyle = fontObject->GetProperty("style");
1132 if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
1133 font.fontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
1134 }
1135
1136 JSRef<JSVal> fontWeight = fontObject->GetProperty("weight");
1137 if (!fontWeight->IsNull()) {
1138 std::string weight;
1139 if (fontWeight->IsNumber()) {
1140 weight = std::to_string(fontWeight->ToNumber<int32_t>());
1141 } else {
1142 JSContainerBase::ParseJsString(fontWeight, weight);
1143 }
1144 font.fontWeight = ConvertStrToFontWeight(weight);
1145 }
1146
1147 JSRef<JSVal> fontFamily = fontObject->GetProperty("family");
1148 if (!fontFamily->IsNull()) {
1149 std::vector<std::string> fontFamilies;
1150 if (JSContainerBase::ParseJsFontFamilies(fontFamily, fontFamilies)) {
1151 font.fontFamilies = fontFamilies;
1152 }
1153 }
1154 }
1155
JsDataDetectorConfig(const JSCallbackInfo & info)1156 void JSRichEditor::JsDataDetectorConfig(const JSCallbackInfo& info)
1157 {
1158 if (info.Length() < 1) {
1159 return;
1160 }
1161 if (!info[0]->IsObject()) {
1162 return;
1163 }
1164
1165 TextDetectConfig textDetectConfig;
1166 if (!ParseDataDetectorConfig(info, textDetectConfig)) {
1167 return;
1168 }
1169 RichEditorModel::GetInstance()->SetTextDetectConfig(textDetectConfig);
1170 }
1171
SetCaretColor(const JSCallbackInfo & info)1172 void JSRichEditor::SetCaretColor(const JSCallbackInfo& info)
1173 {
1174 if (info.Length() < 1) {
1175 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error");
1176 return;
1177 }
1178 Color color;
1179 JSRef<JSVal> colorVal = info[0];
1180 if (!ParseJsColor(colorVal, color)) {
1181 auto pipeline = PipelineBase::GetCurrentContext();
1182 CHECK_NULL_VOID(pipeline);
1183 auto theme = pipeline->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1184 CHECK_NULL_VOID(theme);
1185 color = theme->GetCaretColor();
1186 }
1187 RichEditorModel::GetInstance()->SetCaretColor(color);
1188 }
1189
SetSelectedBackgroundColor(const JSCallbackInfo & info)1190 void JSRichEditor::SetSelectedBackgroundColor(const JSCallbackInfo& info)
1191 {
1192 if (info.Length() < 1) {
1193 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error");
1194 return;
1195 }
1196 Color selectedColor;
1197 JSRef<JSVal> colorVal = info[0];
1198 if (!ParseJsColor(colorVal, selectedColor)) {
1199 auto pipeline = PipelineBase::GetCurrentContext();
1200 CHECK_NULL_VOID(pipeline);
1201 auto theme = pipeline->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1202 CHECK_NULL_VOID(theme);
1203 selectedColor = theme->GetSelectedBackgroundColor();
1204 }
1205 RichEditorModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
1206 }
1207
SetEnterKeyType(const JSCallbackInfo & info)1208 void JSRichEditor::SetEnterKeyType(const JSCallbackInfo& info)
1209 {
1210 if (info.Length() < 1) {
1211 return;
1212 }
1213 auto action = info[0];
1214 if (action->IsUndefined()) {
1215 RichEditorModel::GetInstance()->SetEnterKeyType(TextInputAction::UNSPECIFIED);
1216 return;
1217 }
1218 if (!action->IsNumber()) {
1219 return;
1220 }
1221 TextInputAction textInputAction = CastToTextInputAction(action->ToNumber<int32_t>());
1222 RichEditorModel::GetInstance()->SetEnterKeyType(textInputAction);
1223 }
1224
JsKeepEditableState(panda::JsiRuntimeCallInfo * info)1225 Local<JSValueRef> JSRichEditor::JsKeepEditableState(panda::JsiRuntimeCallInfo* info)
1226 {
1227 Local<JSValueRef> thisObj = info->GetThisRef();
1228 auto eventInfo =
1229 static_cast<NG::TextFieldCommonEvent*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(
1230 info->GetVM(), 0));
1231 if (eventInfo) {
1232 eventInfo->SetKeepEditable(true);
1233 }
1234 return JSValueRef::Undefined(info->GetVM());
1235 }
1236
CreateJsRichEditorCommonEvent(const JSCallbackInfo & info)1237 void JSRichEditor::CreateJsRichEditorCommonEvent(const JSCallbackInfo& info)
1238 {
1239 if (!info[0]->IsFunction()) {
1240 return;
1241 }
1242 auto jsTextFunc =
1243 AceType::MakeRefPtr<JsCommonEventFunction<NG::TextFieldCommonEvent, 2>>(JSRef<JSFunc>::Cast(info[0]));
1244 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1245 auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
1246 int32_t key, NG::TextFieldCommonEvent& event) {
1247 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1248 ACE_SCORING_EVENT("onSubmit");
1249 PipelineContext::SetCallBackNode(node);
1250 JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1251 objectTemplate->SetInternalFieldCount(2);
1252 JSRef<JSObject> object = objectTemplate->NewInstance();
1253 object->SetProperty<std::string>("text", event.GetText());
1254 object->SetPropertyObject("keepEditableState", JSRef<JSFunc>::New<FunctionCallback>(JsKeepEditableState));
1255 object->Wrap<NG::TextFieldCommonEvent>(&event);
1256 JSRef<JSVal> keyEvent = JSRef<JSVal>::Make(ToJSValue(key));
1257 JSRef<JSVal> dataObject = JSRef<JSVal>::Cast(object);
1258 JSRef<JSVal> param[2] = { keyEvent, dataObject };
1259 func->Execute(param);
1260 };
1261 RichEditorModel::GetInstance()->SetOnSubmit(std::move(callback));
1262 }
1263
SetOnSubmit(const JSCallbackInfo & info)1264 void JSRichEditor::SetOnSubmit(const JSCallbackInfo& info)
1265 {
1266 CHECK_NULL_VOID(info[0]->IsFunction());
1267 CreateJsRichEditorCommonEvent(info);
1268 }
1269
SetEnableKeyboardOnFocus(const JSCallbackInfo & info)1270 void JSRichEditor::SetEnableKeyboardOnFocus(const JSCallbackInfo& info)
1271 {
1272 CHECK_NULL_VOID(info.Length() > 0);
1273 auto jsValue = info[0];
1274 if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1275 RichEditorModel::GetInstance()->SetRequestKeyboardOnFocus(true);
1276 return;
1277 }
1278 RichEditorModel::GetInstance()->SetRequestKeyboardOnFocus(jsValue->ToBoolean());
1279 }
1280
SetEnableHapticFeedback(const JSCallbackInfo & info)1281 void JSRichEditor::SetEnableHapticFeedback(const JSCallbackInfo& info)
1282 {
1283 CHECK_NULL_VOID(info.Length() > 0);
1284 auto jsValue = info[0];
1285 if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1286 RichEditorModel::GetInstance()->SetEnableHapticFeedback(true);
1287 return;
1288 }
1289 RichEditorModel::GetInstance()->SetEnableHapticFeedback(jsValue->ToBoolean());
1290 }
1291
SetBarState(const JSCallbackInfo & info)1292 void JSRichEditor::SetBarState(const JSCallbackInfo& info)
1293 {
1294 CHECK_NULL_VOID(info.Length() > 0);
1295 auto jsValue = info[0];
1296 CHECK_NULL_VOID(!jsValue->IsUndefined() && jsValue->IsNumber());
1297 int32_t barState = jsValue->ToNumber<int32_t>();
1298 CHECK_NULL_VOID(barState >= static_cast<int32_t>(DisplayMode::OFF));
1299 CHECK_NULL_VOID(barState <= static_cast<int32_t>(DisplayMode::ON));
1300 RichEditorModel::GetInstance()->SetBarState(static_cast<DisplayMode>(barState));
1301 }
1302
JSBind(BindingTarget globalObj)1303 void JSRichEditor::JSBind(BindingTarget globalObj)
1304 {
1305 JSClass<JSRichEditor>::Declare("RichEditor");
1306 JSClass<JSRichEditor>::StaticMethod("create", &JSRichEditor::Create);
1307 JSClass<JSRichEditor>::StaticMethod("onReady", &JSRichEditor::SetOnReady);
1308 JSClass<JSRichEditor>::StaticMethod("onSelect", &JSRichEditor::SetOnSelect);
1309 JSClass<JSRichEditor>::StaticMethod("onSelectionChange", &JSRichEditor::SetOnSelectionChange);
1310 JSClass<JSRichEditor>::StaticMethod("aboutToIMEInput", &JSRichEditor::SetAboutToIMEInput);
1311 JSClass<JSRichEditor>::StaticMethod("onIMEInputComplete", &JSRichEditor::SetOnIMEInputComplete);
1312 JSClass<JSRichEditor>::StaticMethod("onDidIMEInput", &JSRichEditor::SetOnDidIMEInput);
1313 JSClass<JSRichEditor>::StaticMethod("aboutToDelete", &JSRichEditor::SetAboutToDelete);
1314 JSClass<JSRichEditor>::StaticMethod("onDeleteComplete", &JSRichEditor::SetOnDeleteComplete);
1315 JSClass<JSRichEditor>::StaticMethod("customKeyboard", &JSRichEditor::SetCustomKeyboard);
1316 JSClass<JSRichEditor>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1317 JSClass<JSRichEditor>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
1318 JSClass<JSRichEditor>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1319 JSClass<JSRichEditor>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1320 JSClass<JSRichEditor>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
1321 JSClass<JSRichEditor>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1322 JSClass<JSRichEditor>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
1323 JSClass<JSRichEditor>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1324 JSClass<JSRichEditor>::StaticMethod("clip", &JSRichEditor::JsClip);
1325 JSClass<JSRichEditor>::StaticMethod("focusable", &JSRichEditor::JsFocusable);
1326 JSClass<JSRichEditor>::StaticMethod("copyOptions", &JSRichEditor::SetCopyOptions);
1327 JSClass<JSRichEditor>::StaticMethod("bindSelectionMenu", &JSRichEditor::BindSelectionMenu);
1328 JSClass<JSRichEditor>::StaticMethod("onPaste", &JSRichEditor::SetOnPaste);
1329 JSClass<JSRichEditor>::StaticMethod("enableDataDetector", &JSRichEditor::JsEnableDataDetector);
1330 JSClass<JSRichEditor>::StaticMethod("enablePreviewText", &JSRichEditor::JsEnablePreviewText);
1331 JSClass<JSRichEditor>::StaticMethod("dataDetectorConfig", &JSRichEditor::JsDataDetectorConfig);
1332 JSClass<JSRichEditor>::StaticMethod("placeholder", &JSRichEditor::SetPlaceholder);
1333 JSClass<JSRichEditor>::StaticMethod("caretColor", &JSRichEditor::SetCaretColor);
1334 JSClass<JSRichEditor>::StaticMethod("selectedBackgroundColor", &JSRichEditor::SetSelectedBackgroundColor);
1335 JSClass<JSRichEditor>::StaticMethod("onEditingChange", &JSRichEditor::SetOnEditingChange);
1336 JSClass<JSRichEditor>::StaticMethod("enterKeyType", &JSRichEditor::SetEnterKeyType);
1337 JSClass<JSRichEditor>::StaticMethod("onSubmit", &JSRichEditor::SetOnSubmit);
1338 JSClass<JSRichEditor>::StaticMethod("onWillChange", &JSRichEditor::SetOnWillChange);
1339 JSClass<JSRichEditor>::StaticMethod("onDidChange", &JSRichEditor::SetOnDidChange);
1340 JSClass<JSRichEditor>::StaticMethod("onCut", &JSRichEditor::SetOnCut);
1341 JSClass<JSRichEditor>::StaticMethod("onCopy", &JSRichEditor::SetOnCopy);
1342 JSClass<JSRichEditor>::StaticMethod("editMenuOptions", &JSRichEditor::EditMenuOptions);
1343 JSClass<JSRichEditor>::StaticMethod("enableKeyboardOnFocus", &JSRichEditor::SetEnableKeyboardOnFocus);
1344 JSClass<JSRichEditor>::StaticMethod("enableHapticFeedback", &JSRichEditor::SetEnableHapticFeedback);
1345 JSClass<JSRichEditor>::StaticMethod("barState", &JSRichEditor::SetBarState);
1346 JSClass<JSRichEditor>::InheritAndBind<JSViewAbstract>(globalObj);
1347 }
1348
ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)1349 ImageSpanAttribute JSRichEditorController::ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)
1350 {
1351 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1352 ImageSpanAttribute imageStyle;
1353 auto sizeObj = imageAttribute->GetProperty("size");
1354 if (sizeObj->IsArray()) {
1355 ImageSpanSize imageSize;
1356 JSRef<JSArray> size = JSRef<JSArray>::Cast(sizeObj);
1357 JSRef<JSVal> width = size->GetValueAt(0);
1358 CalcDimension imageSpanWidth;
1359 if (!width->IsNull() && JSContainerBase::ParseJsDimensionVp(width, imageSpanWidth)) {
1360 imageSize.width = imageSpanWidth;
1361 updateSpanStyle_.updateImageWidth = imageSpanWidth;
1362 }
1363 JSRef<JSVal> height = size->GetValueAt(1);
1364 CalcDimension imageSpanHeight;
1365 if (!height->IsNull() && JSContainerBase::ParseJsDimensionVp(height, imageSpanHeight)) {
1366 imageSize.height = imageSpanHeight;
1367 updateSpanStyle_.updateImageHeight = imageSpanHeight;
1368 }
1369 imageStyle.size = imageSize;
1370 }
1371 JSRef<JSVal> verticalAlign = imageAttribute->GetProperty("verticalAlign");
1372 if (!verticalAlign->IsNull()) {
1373 auto align = static_cast<VerticalAlign>(verticalAlign->ToNumber<int32_t>());
1374 if (align < VerticalAlign::TOP || align > VerticalAlign::NONE) {
1375 align = VerticalAlign::BOTTOM;
1376 }
1377 imageStyle.verticalAlign = align;
1378 updateSpanStyle_.updateImageVerticalAlign = align;
1379 }
1380 JSRef<JSVal> objectFit = imageAttribute->GetProperty("objectFit");
1381 if (!objectFit->IsNull() && objectFit->IsNumber()) {
1382 auto fit = static_cast<ImageFit>(objectFit->ToNumber<int32_t>());
1383 if (fit < ImageFit::FILL || fit > ImageFit::SCALE_DOWN) {
1384 fit = ImageFit::COVER;
1385 }
1386 imageStyle.objectFit = fit;
1387 updateSpanStyle_.updateImageFit = fit;
1388 } else {
1389 imageStyle.objectFit = ImageFit::COVER;
1390 }
1391 auto layoutStyleObject = JSObjectCast(imageAttribute->GetProperty("layoutStyle"));
1392 if (!layoutStyleObject->IsUndefined()) {
1393 auto marginAttr = layoutStyleObject->GetProperty("margin");
1394 imageStyle.marginProp = JSRichEditor::ParseMarginAttr(marginAttr);
1395 updateSpanStyle_.marginProp = imageStyle.marginProp;
1396 auto borderRadiusAttr = layoutStyleObject->GetProperty("borderRadius");
1397 imageStyle.borderRadius = JSRichEditor::ParseBorderRadiusAttr(borderRadiusAttr);
1398 updateSpanStyle_.borderRadius = imageStyle.borderRadius;
1399 }
1400 return imageStyle;
1401 }
1402
ParseJsSymbolSpanStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)1403 void JSRichEditorController::ParseJsSymbolSpanStyle(
1404 const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
1405 {
1406 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1407 JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
1408 std::vector<Color> symbolColor;
1409 if (!fontColor->IsNull() && JSContainerBase::ParseJsSymbolColor(fontColor, symbolColor)) {
1410 updateSpanStyle.updateSymbolColor = symbolColor;
1411 style.SetSymbolColorList(symbolColor);
1412 }
1413 JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
1414 CalcDimension size;
1415 if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size, false) &&
1416 !FontSizeRangeIsNegative(size) && size.Unit() != DimensionUnit::PERCENT) {
1417 updateSpanStyle.updateSymbolFontSize = size;
1418 style.SetFontSize(size);
1419 } else if (FontSizeRangeIsNegative(size) || size.Unit() == DimensionUnit::PERCENT) {
1420 auto theme = JSContainerBase::GetTheme<TextTheme>();
1421 CHECK_NULL_VOID(theme);
1422 size = theme->GetTextStyle().GetFontSize();
1423 style.SetFontSize(size);
1424 }
1425 JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
1426 std::string weight;
1427 if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
1428 if (fontWeight->IsNumber()) {
1429 weight = std::to_string(fontWeight->ToNumber<int32_t>());
1430 }
1431 updateSpanStyle.updateSymbolFontWeight = ConvertStrToFontWeight(weight);
1432 style.SetFontWeight(ConvertStrToFontWeight(weight));
1433 }
1434 JSRef<JSVal> renderingStrategy = styleObject->GetProperty("renderingStrategy");
1435 uint32_t symbolRenderStrategy;
1436 if (!renderingStrategy->IsNull() && JSContainerBase::ParseJsInteger(renderingStrategy, symbolRenderStrategy)) {
1437 if (symbolRenderStrategy < 0 ||
1438 symbolRenderStrategy > static_cast<uint32_t>(RenderingStrategy::MULTIPLE_OPACITY)) {
1439 symbolRenderStrategy = static_cast<uint32_t>(RenderingStrategy::SINGLE);
1440 }
1441 updateSpanStyle.updateSymbolRenderingStrategy = symbolRenderStrategy;
1442 style.SetRenderStrategy(symbolRenderStrategy);
1443 }
1444 JSRef<JSVal> effectStrategy = styleObject->GetProperty("effectStrategy");
1445 uint32_t symbolEffectStrategy;
1446 if (!effectStrategy->IsNull() && JSContainerBase::ParseJsInteger(effectStrategy, symbolEffectStrategy)) {
1447 updateSpanStyle.updateSymbolEffectStrategy = 0;
1448 style.SetEffectStrategy(0);
1449 }
1450 }
1451
ParseUserGesture(const JSCallbackInfo & args,UserGestureOptions & gestureOption,const std::string & spanType)1452 void ParseUserGesture(
1453 const JSCallbackInfo& args, UserGestureOptions& gestureOption, const std::string& spanType)
1454 {
1455 if (args.Length() < 2) {
1456 return;
1457 }
1458 if (!args[1]->IsObject()) {
1459 return;
1460 }
1461 JSRef<JSObject> object = JSRef<JSObject>::Cast(args[1]);
1462 auto gesture = object->GetProperty("gesture");
1463 if (!gesture->IsUndefined() && gesture->IsObject()) {
1464 auto gestureObj = JSRef<JSObject>::Cast(gesture);
1465 auto clickFunc = gestureObj->GetProperty("onClick");
1466 if (clickFunc->IsUndefined() && IsDisableEventVersion()) {
1467 gestureOption.onClick = nullptr;
1468 } else if (!clickFunc->IsFunction()) {
1469 gestureOption.onClick = nullptr;
1470 } else {
1471 auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(clickFunc));
1472 auto* targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1473 auto onClick = [execCtx = args.GetExecutionContext(), func = jsOnClickFunc, spanTypeInner = spanType,
1474 node = AceType::WeakClaim(targetNode)](BaseEventInfo* info) {
1475 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1476 auto* clickInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
1477 ACE_SCORING_EVENT(spanTypeInner + ".onClick");
1478 PipelineContext::SetCallBackNode(node);
1479 func->Execute(*clickInfo);
1480 };
1481 auto tmpClickFunc = [func = std::move(onClick)](GestureEvent& info) { func(&info); };
1482 gestureOption.onClick = std::move(tmpClickFunc);
1483 }
1484 auto onLongPressFunc = gestureObj->GetProperty("onLongPress");
1485 if (onLongPressFunc->IsUndefined() && IsDisableEventVersion()) {
1486 gestureOption.onLongPress = nullptr;
1487 } else if (!onLongPressFunc->IsFunction()) {
1488 gestureOption.onLongPress = nullptr;
1489 } else {
1490 auto jsLongPressFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(onLongPressFunc));
1491 auto* targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1492 auto onLongPress = [execCtx = args.GetExecutionContext(), func = jsLongPressFunc, spanTypeInner = spanType,
1493 node = AceType::WeakClaim(targetNode)](BaseEventInfo* info) {
1494 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1495 auto* longPressInfo = TypeInfoHelper::DynamicCast<GestureEvent>(info);
1496 ACE_SCORING_EVENT(spanTypeInner + ".onLongPress");
1497 func->Execute(*longPressInfo);
1498 };
1499 auto tmpOnLongPressFunc = [func = std::move(onLongPress)](GestureEvent& info) { func(&info); };
1500 gestureOption.onLongPress = std::move(tmpOnLongPressFunc);
1501 }
1502 }
1503 }
1504
AddImageSpan(const JSCallbackInfo & args)1505 void JSRichEditorController::AddImageSpan(const JSCallbackInfo& args)
1506 {
1507 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1508 if (args.Length() < 1) {
1509 return;
1510 }
1511 ImageSpanOptions options;
1512 if (!args[0]->IsEmpty() && args[0]->ToString() != "") {
1513 options = CreateJsImageOptions(args);
1514 } else {
1515 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1516 return;
1517 }
1518 if (options.image.has_value()) {
1519 std::string assetSrc = options.image.value();
1520 if (!CheckImageSource(assetSrc)) {
1521 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "CheckImageSource failed");
1522 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1523 return;
1524 }
1525 }
1526 if (args.Length() > 1 && args[1]->IsObject()) {
1527 JSRef<JSObject> imageObject = JSRef<JSObject>::Cast(args[1]);
1528
1529 JSRef<JSVal> offset = imageObject->GetProperty("offset");
1530 int32_t imageOffset = 0;
1531 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, imageOffset)) {
1532 options.offset = imageOffset > 0 ? imageOffset : 0;
1533 }
1534 auto imageAttribute = JSObjectCast(imageObject->GetProperty("imageStyle"));
1535 if (!imageAttribute->IsUndefined()) {
1536 ImageSpanAttribute imageStyle = ParseJsImageSpanAttribute(imageAttribute);
1537 options.imageAttribute = imageStyle;
1538 }
1539 UserGestureOptions gestureOption;
1540 ParseUserGesture(args, gestureOption, "ImageSpan");
1541 options.userGestureOption = std::move(gestureOption);
1542 }
1543 auto controller = controllerWeak_.Upgrade();
1544 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1545 int32_t spanIndex = 0;
1546 if (richEditorController) {
1547 spanIndex = richEditorController->AddImageSpan(options);
1548 }
1549 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1550 }
1551
CheckImageSource(std::string assetSrc)1552 bool JSRichEditorController::CheckImageSource(std::string assetSrc)
1553 {
1554 SrcType srcType = ImageSourceInfo::ResolveURIType(assetSrc);
1555 if (assetSrc[0] == '/') {
1556 assetSrc = assetSrc.substr(1); // get the asset src without '/'.
1557 } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
1558 assetSrc = assetSrc.substr(2); // get the asset src without './'.
1559 }
1560 if (srcType == SrcType::ASSET) {
1561 auto pipelineContext = PipelineBase::GetCurrentContext();
1562 if (!pipelineContext) {
1563 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1564 return false;
1565 }
1566 auto assetManager = pipelineContext->GetAssetManager();
1567 if (!assetManager) {
1568 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "assetManager is null");
1569 return false;
1570 }
1571 auto assetData = assetManager->GetAsset(assetSrc);
1572 if (!assetData) {
1573 TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "assetData is null");
1574 return false;
1575 }
1576 }
1577 return true;
1578 }
1579
CreateJsImageOptions(const JSCallbackInfo & args)1580 ImageSpanOptions JSRichEditorController::CreateJsImageOptions(const JSCallbackInfo& args)
1581 {
1582 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1583 ImageSpanOptions options;
1584 auto context = PipelineBase::GetCurrentContext();
1585 CHECK_NULL_RETURN(context, options);
1586 bool isCard = context->IsFormRender();
1587 std::string image;
1588 std::string bundleName;
1589 std::string moduleName;
1590 bool srcValid = JSContainerBase::ParseJsMedia(args[0], image);
1591 if (isCard && args[0]->IsString()) {
1592 SrcType srcType = ImageSourceInfo::ResolveURIType(image);
1593 bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
1594 if (notSupport) {
1595 image.clear();
1596 }
1597 }
1598 JSImage::GetJsMediaBundleInfo(args[0], bundleName, moduleName);
1599 options.image = image;
1600 options.bundleName = bundleName;
1601 options.moduleName = moduleName;
1602 if (!srcValid) {
1603 #if defined(PIXEL_MAP_SUPPORTED)
1604 if (!isCard) {
1605 if (IsDrawable(args[0])) {
1606 options.imagePixelMap = GetDrawablePixmap(args[0]);
1607 } else {
1608 options.imagePixelMap = CreatePixelMapFromNapiValue(args[0]);
1609 }
1610 }
1611 #endif
1612 }
1613 return options;
1614 }
1615
IsDrawable(const JSRef<JSVal> & jsValue)1616 bool JSRichEditorController::IsDrawable(const JSRef<JSVal>& jsValue)
1617 {
1618 if (!jsValue->IsObject()) {
1619 return false;
1620 }
1621 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
1622 if (jsObj->IsUndefined()) {
1623 return false;
1624 }
1625 JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
1626 return (!func->IsNull() && func->IsFunction());
1627 }
1628
IsPixelMap(const JSRef<JSVal> & jsValue)1629 bool JSRichEditorController::IsPixelMap(const JSRef<JSVal>& jsValue)
1630 {
1631 if (!jsValue->IsObject()) {
1632 return false;
1633 }
1634 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
1635 if (jsObj->IsUndefined()) {
1636 return false;
1637 }
1638 JSRef<JSVal> func = jsObj->GetProperty("readPixelsToBuffer");
1639 return (!func->IsNull() && func->IsFunction());
1640 }
1641
AddTextSpan(const JSCallbackInfo & args)1642 void JSRichEditorController::AddTextSpan(const JSCallbackInfo& args)
1643 {
1644 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1645 if (args.Length() < 1) {
1646 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "args length invalid");
1647 return;
1648 }
1649 TextSpanOptions options;
1650 std::string spanValue;
1651 if (!args[0]->IsEmpty() && args[0]->IsString() && args[0]->ToString() != ""
1652 && JSContainerBase::ParseJsString(args[0], spanValue)) {
1653 options.value = spanValue;
1654 } else {
1655 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "args error");
1656 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1657 return;
1658 }
1659 if (args.Length() > 1 && args[1]->IsObject()) {
1660 JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
1661 JSRef<JSVal> offset = spanObject->GetProperty("offset");
1662 int32_t spanOffset = 0;
1663 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
1664 options.offset = spanOffset > 0 ? spanOffset : 0;
1665 }
1666 auto styleObject = JSObjectCast(spanObject->GetProperty("style"));
1667 updateSpanStyle_.ResetStyle();
1668 if (!styleObject->IsUndefined()) {
1669 auto pipelineContext = PipelineBase::GetCurrentContext();
1670 if (!pipelineContext) {
1671 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1672 return;
1673 }
1674 auto theme = pipelineContext->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1675 TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
1676 ParseJsTextStyle(styleObject, style, updateSpanStyle_);
1677 options.style = style;
1678 options.useThemeFontColor = updateSpanStyle_.useThemeFontColor;
1679 options.useThemeDecorationColor = updateSpanStyle_.useThemeDecorationColor;
1680 }
1681 auto paraStyleObj = JSObjectCast(spanObject->GetProperty("paragraphStyle"));
1682 if (!paraStyleObj->IsUndefined()) {
1683 struct UpdateParagraphStyle style;
1684 if (ParseParagraphStyle(paraStyleObj, style)) {
1685 options.paraStyle = style;
1686 }
1687 }
1688 UserGestureOptions gestureOption;
1689 ParseUserGesture(args, gestureOption, "TextSpan");
1690 options.userGestureOption = std::move(gestureOption);
1691 }
1692 auto controller = controllerWeak_.Upgrade();
1693 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1694 int32_t spanIndex = 0;
1695 if (richEditorController) {
1696 spanIndex = richEditorController->AddTextSpan(options);
1697 } else {
1698 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "rich editor controller error");
1699 }
1700 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1701 }
1702
AddSymbolSpan(const JSCallbackInfo & args)1703 void JSRichEditorController::AddSymbolSpan(const JSCallbackInfo& args)
1704 {
1705 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1706 if (args.Length() < 1) {
1707 return;
1708 }
1709 SymbolSpanOptions options;
1710 uint32_t symbolId;
1711 RefPtr<ResourceObject> resourceObject;
1712 if (!args[0]->IsEmpty() && JSContainerBase::ParseJsSymbolId(args[0], symbolId, resourceObject)) {
1713 options.symbolId = symbolId;
1714 options.resourceObject = resourceObject;
1715 } else {
1716 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1717 return;
1718 }
1719
1720 if (args.Length() > 1 && args[1]->IsObject()) {
1721 JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
1722 JSRef<JSVal> offset = spanObject->GetProperty("offset");
1723 int32_t spanOffset = 0;
1724 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
1725 options.offset = spanOffset > 0 ? spanOffset : 0;
1726 }
1727 auto styleObject = JSObjectCast(spanObject->GetProperty("style"));
1728 if (!styleObject->IsUndefined()) {
1729 auto pipelineContext = PipelineBase::GetCurrentContext();
1730 if (!pipelineContext) {
1731 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1732 return;
1733 }
1734 auto theme = pipelineContext->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1735 TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
1736 ParseJsSymbolSpanStyle(styleObject, style, updateSpanStyle_);
1737 options.style = style;
1738 }
1739 }
1740
1741 auto controller = controllerWeak_.Upgrade();
1742 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1743 int32_t spanIndex = 0;
1744 if (richEditorController) {
1745 spanIndex = richEditorController->AddSymbolSpan(options);
1746 }
1747 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1748 }
1749
CreateJSSpansInfo(const SelectionInfo & info)1750 JSRef<JSVal> JSRichEditorController::CreateJSSpansInfo(const SelectionInfo& info)
1751 {
1752 uint32_t idx = 0;
1753
1754 JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
1755 JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
1756
1757 const std::list<ResultObject>& spanObjectList = info.GetSelection().resultObjects;
1758 for (const ResultObject& spanObject : spanObjectList) {
1759 spanObjectArray->SetValueAt(idx++, JSRichEditor::CreateJSSpanResultObject(spanObject));
1760 }
1761
1762 return JSRef<JSVal>::Cast(spanObjectArray);
1763 }
1764
GetSpansInfo(const JSCallbackInfo & args)1765 void JSRichEditorController::GetSpansInfo(const JSCallbackInfo& args)
1766 {
1767 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1768 int32_t end = -1;
1769 int32_t start = -1;
1770 if (args[0]->IsObject()) {
1771 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
1772 JSRef<JSVal> startVal = obj->GetProperty("start");
1773 JSRef<JSVal> endVal = obj->GetProperty("end");
1774
1775 if (!startVal->IsNull() && startVal->IsNumber()) {
1776 start = startVal->ToNumber<int32_t>();
1777 }
1778
1779 if (!endVal->IsNull() && endVal->IsNumber()) {
1780 end = endVal->ToNumber<int32_t>();
1781 }
1782 }
1783 auto controller = controllerWeak_.Upgrade();
1784 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1785 CHECK_NULL_VOID(richEditorController);
1786 SelectionInfo value = richEditorController->GetSpansInfo(start, end);
1787 args.SetReturnValue(CreateJSSpansInfo(value));
1788 }
1789
GetPreviewTextInfo(const JSCallbackInfo & args)1790 void JSRichEditorBaseController::GetPreviewTextInfo(const JSCallbackInfo& args)
1791 {
1792 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1793 auto controller = controllerWeak_.Upgrade();
1794 CHECK_NULL_VOID(controller);
1795 auto info = controller->GetPreviewTextInfo();
1796 args.SetReturnValue(CreateJSPreviewTextInfo(info));
1797 }
1798
CreateJSPreviewTextInfo(const PreviewTextInfo & info)1799 JSRef<JSObject> JSRichEditorBaseController::CreateJSPreviewTextInfo(const PreviewTextInfo& info)
1800 {
1801 auto resultObj = JSRef<JSObject>::New();
1802 resultObj->SetProperty<std::string>("value", info.value.value_or(""));
1803 resultObj->SetProperty<int32_t>("offset", info.offset.value_or(0));
1804 return resultObj;
1805 }
1806
DeleteSpans(const JSCallbackInfo & args)1807 void JSRichEditorController::DeleteSpans(const JSCallbackInfo& args)
1808 {
1809 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1810 RangeOptions options;
1811 auto controller = controllerWeak_.Upgrade();
1812 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1813 CHECK_NULL_VOID(richEditorController);
1814
1815 if (args.Length() < 1) {
1816 richEditorController->DeleteSpans(options);
1817 return;
1818 }
1819
1820 if (!args[0]->IsObject() || !richEditorController) {
1821 return;
1822 }
1823 JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[0]);
1824 JSRef<JSVal> startVal = spanObject->GetProperty("start");
1825 int32_t start = 0;
1826 if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(startVal, start)) {
1827 options.start = start;
1828 }
1829 JSRef<JSVal> endVal = spanObject->GetProperty("end");
1830 int32_t end = 0;
1831 if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(endVal, end)) {
1832 options.end = end;
1833 }
1834 richEditorController->DeleteSpans(options);
1835 }
1836
AddPlaceholderSpan(const JSCallbackInfo & args)1837 void JSRichEditorController::AddPlaceholderSpan(const JSCallbackInfo& args)
1838 {
1839 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1840 if (args.Length() < 1) {
1841 return;
1842 }
1843 auto customVal = args[0];
1844 if (!customVal->IsFunction() && !customVal->IsObject()) {
1845 return;
1846 }
1847 JSRef<JSVal> funcValue;
1848 auto customObject = JSRef<JSObject>::Cast(customVal);
1849 auto builder = customObject->GetProperty("builder");
1850 // if failed to get builder, parse function directly
1851 if (builder->IsEmpty() || builder->IsNull() || !builder->IsFunction()) {
1852 funcValue = customVal;
1853 } else {
1854 funcValue = builder;
1855 }
1856 SpanOptionBase options;
1857 {
1858 if (!funcValue->IsFunction()) {
1859 return;
1860 }
1861 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(funcValue));
1862 CHECK_NULL_VOID(builderFunc);
1863 ViewStackModel::GetInstance()->NewScope();
1864 builderFunc->Execute();
1865 auto customNode = AceType::DynamicCast<NG::UINode>(ViewStackModel::GetInstance()->Finish());
1866 CHECK_NULL_VOID(customNode);
1867 auto controller = controllerWeak_.Upgrade();
1868 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1869 int32_t spanIndex = 0;
1870 if (richEditorController) {
1871 ParseOptions(args, options);
1872 spanIndex = richEditorController->AddPlaceholderSpan(customNode, options);
1873 }
1874 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1875 }
1876 }
1877
ParseOptions(const JSCallbackInfo & args,SpanOptionBase & placeholderSpan)1878 void JSRichEditorController::ParseOptions(const JSCallbackInfo& args, SpanOptionBase& placeholderSpan)
1879 {
1880 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1881 if (args.Length() < 2) {
1882 return;
1883 }
1884 if (!args[1]->IsObject()) {
1885 return;
1886 }
1887 JSRef<JSObject> placeholderOptionObject = JSRef<JSObject>::Cast(args[1]);
1888 JSRef<JSVal> offset = placeholderOptionObject->GetProperty("offset");
1889 int32_t placeholderOffset = 0;
1890 if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, placeholderOffset)) {
1891 if (placeholderOffset >= 0) {
1892 placeholderSpan.offset = placeholderOffset;
1893 }
1894 }
1895 }
1896
GetSelection(const JSCallbackInfo & args)1897 void JSRichEditorController::GetSelection(const JSCallbackInfo& args)
1898 {
1899 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1900 auto controller = controllerWeak_.Upgrade();
1901 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1902 CHECK_NULL_VOID(richEditorController);
1903 SelectionInfo value = richEditorController->GetSelectionSpansInfo();
1904 args.SetReturnValue(JSRichEditor::CreateJSSelection(value));
1905 }
1906
JSBind(BindingTarget globalObj)1907 void JSRichEditorController::JSBind(BindingTarget globalObj)
1908 {
1909 JSClass<JSRichEditorController>::Declare("RichEditorController");
1910 JSClass<JSRichEditorController>::CustomMethod("addImageSpan", &JSRichEditorController::AddImageSpan);
1911 JSClass<JSRichEditorController>::CustomMethod("addTextSpan", &JSRichEditorController::AddTextSpan);
1912 JSClass<JSRichEditorController>::CustomMethod("addSymbolSpan", &JSRichEditorController::AddSymbolSpan);
1913 JSClass<JSRichEditorController>::CustomMethod("addBuilderSpan", &JSRichEditorController::AddPlaceholderSpan);
1914 JSClass<JSRichEditorController>::CustomMethod("setCaretOffset", &JSRichEditorController::SetCaretOffset);
1915 JSClass<JSRichEditorController>::CustomMethod("getCaretOffset", &JSRichEditorController::GetCaretOffset);
1916 JSClass<JSRichEditorController>::CustomMethod("updateSpanStyle", &JSRichEditorController::UpdateSpanStyle);
1917 JSClass<JSRichEditorController>::CustomMethod("getTypingStyle", &JSRichEditorController::GetTypingStyle);
1918 JSClass<JSRichEditorController>::CustomMethod("setTypingStyle", &JSRichEditorController::SetTypingStyle);
1919 JSClass<JSRichEditorController>::CustomMethod(
1920 "updateParagraphStyle", &JSRichEditorController::UpdateParagraphStyle);
1921 JSClass<JSRichEditorController>::CustomMethod("getSpans", &JSRichEditorController::GetSpansInfo);
1922 JSClass<JSRichEditorController>::CustomMethod("getPreviewText", &JSRichEditorController::GetPreviewTextInfo);
1923 JSClass<JSRichEditorController>::CustomMethod("getParagraphs", &JSRichEditorController::GetParagraphsInfo);
1924 JSClass<JSRichEditorController>::CustomMethod("deleteSpans", &JSRichEditorController::DeleteSpans);
1925 JSClass<JSRichEditorController>::CustomMethod("setSelection", &JSRichEditorController::SetSelection);
1926 JSClass<JSRichEditorController>::CustomMethod("getSelection", &JSRichEditorController::GetSelection);
1927 JSClass<JSRichEditorController>::CustomMethod("getLayoutManager", &JSRichEditorController::GetLayoutManager);
1928 JSClass<JSRichEditorController>::CustomMethod("isEditing", &JSRichEditorController::IsEditing);
1929 JSClass<JSRichEditorController>::CustomMethod("toStyledString", &JSRichEditorController::ToStyledString);
1930 JSClass<JSRichEditorController>::CustomMethod("fromStyledString", &JSRichEditorController::FromStyledString);
1931 JSClass<JSRichEditorController>::Method("stopEditing", &JSRichEditorController::StopEditing);
1932 JSClass<JSRichEditorController>::Method("closeSelectionMenu", &JSRichEditorController::CloseSelectionMenu);
1933 JSClass<JSRichEditorController>::Bind(
1934 globalObj, JSRichEditorController::Constructor, JSRichEditorController::Destructor);
1935 }
1936
1937 namespace {
ValidationCheck(const JSCallbackInfo & info)1938 bool ValidationCheck(const JSCallbackInfo& info)
1939 {
1940 if (!info[0]->IsNumber() && !info[0]->IsObject()) {
1941 return false;
1942 }
1943 return true;
1944 }
1945
ParseRange(const JSRef<JSObject> & object)1946 std::pair<int32_t, int32_t> ParseRange(const JSRef<JSObject>& object)
1947 {
1948 int32_t start = -1;
1949 int32_t end = -1;
1950 if (!JSContainerBase::ParseJsInt32(object->GetProperty("start"), start)) {
1951 start = 0;
1952 }
1953 if (!JSContainerBase::ParseJsInt32(object->GetProperty("end"), end)) {
1954 end = INT_MAX;
1955 }
1956 if (start < 0) {
1957 start = 0;
1958 }
1959 if (end < 0) {
1960 end = INT_MAX;
1961 }
1962 if (start > end) {
1963 start = 0;
1964 end = INT_MAX;
1965 }
1966 return std::make_pair(start, end);
1967 }
1968 } // namespace
1969
ParseWordBreakParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)1970 void JSRichEditorController::ParseWordBreakParagraphStyle(const JSRef<JSObject>& styleObject,
1971 struct UpdateParagraphStyle& style)
1972 {
1973 auto wordBreakObj = styleObject->GetProperty("wordBreak");
1974 if (wordBreakObj->IsNull() || !wordBreakObj->IsNumber()) {
1975 return;
1976 }
1977 auto index = wordBreakObj->ToNumber<int32_t>();
1978 if (index < 0 || index >= static_cast<int32_t>(WORD_BREAK_TYPES.size())) {
1979 index = static_cast<int32_t>(WordBreak::BREAK_WORD);
1980 }
1981 style.wordBreak = WORD_BREAK_TYPES[index];
1982 }
1983
ParseLineBreakStrategyParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)1984 void JSRichEditorController::ParseLineBreakStrategyParagraphStyle(
1985 const JSRef<JSObject>& styleObject, struct UpdateParagraphStyle& style)
1986 {
1987 auto breakStrategyObj = styleObject->GetProperty("lineBreakStrategy");
1988 if (!breakStrategyObj->IsNull() && breakStrategyObj->IsNumber()) {
1989 auto breakStrategy = static_cast<LineBreakStrategy>(breakStrategyObj->ToNumber<int32_t>());
1990 if (breakStrategy < LineBreakStrategy::GREEDY || breakStrategy > LineBreakStrategy::BALANCED) {
1991 breakStrategy = LineBreakStrategy::GREEDY;
1992 }
1993 style.lineBreakStrategy = breakStrategy;
1994 }
1995 }
1996
ParseTextAlignParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)1997 void JSRichEditorController::ParseTextAlignParagraphStyle(const JSRef<JSObject>& styleObject,
1998 struct UpdateParagraphStyle& style)
1999 {
2000 auto textAlignObj = styleObject->GetProperty("textAlign");
2001 if (!textAlignObj->IsNull() && textAlignObj->IsNumber()) {
2002 auto align = static_cast<TextAlign>(textAlignObj->ToNumber<int32_t>());
2003 if (align < TextAlign::START || align > TextAlign::JUSTIFY) {
2004 align = TextAlign::START;
2005 }
2006 style.textAlign = align;
2007 }
2008 }
2009
ParseParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2010 bool JSRichEditorController::ParseParagraphStyle(const JSRef<JSObject>& styleObject, struct UpdateParagraphStyle& style)
2011 {
2012 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2013 ParseTextAlignParagraphStyle(styleObject, style);
2014 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2015 ParseLineBreakStrategyParagraphStyle(styleObject, style);
2016 ParseWordBreakParagraphStyle(styleObject, style);
2017 }
2018
2019 auto lm = styleObject->GetProperty("leadingMargin");
2020 if (lm->IsObject()) {
2021 // [LeadingMarginPlaceholder]
2022 JSRef<JSObject> leadingMarginObject = JSRef<JSObject>::Cast(lm);
2023 style.leadingMargin = std::make_optional<NG::LeadingMargin>();
2024 JSRef<JSVal> placeholder = leadingMarginObject->GetProperty("pixelMap");
2025 if (IsPixelMap(placeholder)) {
2026 #if defined(PIXEL_MAP_SUPPORTED)
2027 auto pixelMap = CreatePixelMapFromNapiValue(placeholder);
2028 style.leadingMargin->pixmap = pixelMap;
2029 #endif
2030 }
2031
2032 JSRef<JSVal> sizeVal = leadingMarginObject->GetProperty("size");
2033 if (!sizeVal->IsUndefined() && sizeVal->IsArray()) {
2034 auto rangeArray = JSRef<JSArray>::Cast(sizeVal);
2035 JSRef<JSVal> widthVal = rangeArray->GetValueAt(0);
2036 JSRef<JSVal> heightVal = rangeArray->GetValueAt(1);
2037
2038 CalcDimension width;
2039 CalcDimension height;
2040 JSContainerBase::ParseJsDimensionVp(widthVal, width);
2041 JSContainerBase::ParseJsDimensionVp(heightVal, height);
2042 style.leadingMargin->size = NG::LeadingMarginSize(width, height);
2043 } else if (sizeVal->IsUndefined()) {
2044 std::string resWidthStr;
2045 if (JSContainerBase::ParseJsString(lm, resWidthStr)) {
2046 CalcDimension width;
2047 JSContainerBase::ParseJsDimensionVp(lm, width);
2048 style.leadingMargin->size = NG::LeadingMarginSize(width, Dimension(0.0, width.Unit()));
2049 }
2050 }
2051 } else if (!lm->IsNull()) {
2052 // [Dimension]
2053 style.leadingMargin = std::make_optional<NG::LeadingMargin>();
2054 CalcDimension width;
2055 JSContainerBase::ParseJsDimensionVp(lm, width);
2056 style.leadingMargin->size = NG::LeadingMarginSize(width, Dimension(0.0, width.Unit()));
2057 }
2058 return true;
2059 }
2060
UpdateSpanStyle(const JSCallbackInfo & info)2061 void JSRichEditorController::UpdateSpanStyle(const JSCallbackInfo& info)
2062 {
2063 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2064 if (!ValidationCheck(info)) {
2065 return;
2066 }
2067 auto jsObject = JSRef<JSObject>::Cast(info[0]);
2068
2069 auto [start, end] = ParseRange(jsObject);
2070 auto pipelineContext = PipelineBase::GetCurrentContext();
2071 if (!pipelineContext) {
2072 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
2073 return;
2074 }
2075 auto theme = pipelineContext->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
2076 TextStyle textStyle = theme ? theme->GetTextStyle() : TextStyle();
2077 ImageSpanAttribute imageStyle;
2078 auto richEditorTextStyle = JSObjectCast(jsObject->GetProperty("textStyle"));
2079 auto richEditorImageStyle = JSObjectCast(jsObject->GetProperty("imageStyle"));
2080 auto richEditorSymbolSpanStyle = JSObjectCast(jsObject->GetProperty("symbolStyle"));
2081 updateSpanStyle_.ResetStyle();
2082 if (!richEditorTextStyle->IsUndefined()) {
2083 ParseJsTextStyle(richEditorTextStyle, textStyle, updateSpanStyle_);
2084 }
2085 if (!richEditorImageStyle->IsUndefined()) {
2086 imageStyle = ParseJsImageSpanAttribute(richEditorImageStyle);
2087 }
2088 if (!richEditorSymbolSpanStyle->IsUndefined()) {
2089 TextStyle symbolTextStyle;
2090 ParseJsSymbolSpanStyle(richEditorSymbolSpanStyle, symbolTextStyle, updateSpanStyle_);
2091 }
2092
2093 auto controller = controllerWeak_.Upgrade();
2094 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2095 CHECK_NULL_VOID(richEditorController);
2096 richEditorController->SetUpdateSpanStyle(updateSpanStyle_);
2097 richEditorController->UpdateSpanStyle(start, end, textStyle, imageStyle);
2098 }
2099
GetParagraphsInfo(const JSCallbackInfo & args)2100 void JSRichEditorController::GetParagraphsInfo(const JSCallbackInfo& args)
2101 {
2102 ContainerScope scope(instanceId_);
2103 if (!args[0]->IsObject()) {
2104 return;
2105 }
2106 auto [start, end] = ParseRange(JSRef<JSObject>::Cast(args[0]));
2107 if (start == end) {
2108 return;
2109 }
2110 auto controller = controllerWeak_.Upgrade();
2111 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2112 CHECK_NULL_VOID(richEditorController);
2113 auto info = richEditorController->GetParagraphsInfo(start, end);
2114 args.SetReturnValue(CreateJSParagraphsInfo(info));
2115 }
2116
UpdateParagraphStyle(const JSCallbackInfo & info)2117 void JSRichEditorController::UpdateParagraphStyle(const JSCallbackInfo& info)
2118 {
2119 ContainerScope scope(instanceId_);
2120 if (!ValidationCheck(info)) {
2121 return;
2122 }
2123 auto object = JSRef<JSObject>::Cast(info[0]);
2124 auto [start, end] = ParseRange(object);
2125 if (start == end) {
2126 return;
2127 }
2128 auto styleObj = JSObjectCast(object->GetProperty("style"));
2129
2130 if (styleObj->IsUndefined()) {
2131 return;
2132 }
2133
2134 struct UpdateParagraphStyle style;
2135 if (!ParseParagraphStyle(styleObj, style)) {
2136 return;
2137 }
2138 auto controller = controllerWeak_.Upgrade();
2139 CHECK_NULL_VOID(controller);
2140 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2141 CHECK_NULL_VOID(richEditorController);
2142 richEditorController->UpdateParagraphStyle(start, end, style);
2143 }
2144
CreateJSParagraphsInfo(const std::vector<ParagraphInfo> & info)2145 JSRef<JSVal> JSRichEditorController::CreateJSParagraphsInfo(const std::vector<ParagraphInfo>& info)
2146 {
2147 auto array = JSRef<JSArray>::New();
2148 for (size_t i = 0; i < info.size(); ++i) {
2149 auto obj = JSRef<JSObject>::New();
2150 obj->SetPropertyObject("style", JSRichEditor::CreateParagraphStyleResult(info[i]));
2151
2152 auto range = JSRef<JSArray>::New();
2153 range->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(info[i].range.first)));
2154 range->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(info[i].range.second)));
2155 obj->SetPropertyObject("range", range);
2156 array->SetValueAt(i, obj);
2157 }
2158 return JSRef<JSVal>::Cast(array);
2159 }
2160
GetCaretOffset(const JSCallbackInfo & args)2161 void JSRichEditorBaseController::GetCaretOffset(const JSCallbackInfo& args)
2162 {
2163 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2164 auto controller = controllerWeak_.Upgrade();
2165 int32_t caretOffset = -1;
2166 if (controller) {
2167 caretOffset = controller->GetCaretOffset();
2168 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
2169 } else {
2170 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
2171 }
2172 }
2173
SetCaretOffset(const JSCallbackInfo & args)2174 void JSRichEditorBaseController::SetCaretOffset(const JSCallbackInfo& args)
2175 {
2176 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2177 auto controller = controllerWeak_.Upgrade();
2178 int32_t caretPosition = -1;
2179 bool success = false;
2180 JSViewAbstract::ParseJsInteger<int32_t>(args[0], caretPosition);
2181 caretPosition = caretPosition < 0 ? -1 : caretPosition;
2182 if (controller) {
2183 success = controller->SetCaretOffset(caretPosition);
2184 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
2185 } else {
2186 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
2187 }
2188 }
2189
SetTypingStyle(const JSCallbackInfo & info)2190 void JSRichEditorBaseController::SetTypingStyle(const JSCallbackInfo& info)
2191 {
2192 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2193 auto controller = controllerWeak_.Upgrade();
2194 CHECK_NULL_VOID(controller);
2195 bool isBelowApi12 = !AceApplicationInfo::GetInstance().
2196 GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE);
2197 if (isBelowApi12 && !info[0]->IsObject()) {
2198 return;
2199 }
2200 auto pipelineContext = PipelineBase::GetCurrentContext();
2201 if (!pipelineContext) {
2202 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
2203 return;
2204 }
2205 auto theme = pipelineContext->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
2206 TextStyle textStyle = theme ? theme->GetTextStyle() : TextStyle();
2207 bool isUndefined = false;
2208 if (info[0]->IsObject()) {
2209 JSRef<JSObject> richEditorTextStyle = JSRef<JSObject>::Cast(info[0]);
2210 isUndefined = richEditorTextStyle->IsUndefined();
2211 typingStyle_.ResetStyle();
2212 if (isBelowApi12) {
2213 typingStyle_.updateTextColor = theme->GetTextStyle().GetTextColor();
2214 }
2215 if (!richEditorTextStyle->IsUndefined()) {
2216 ParseJsTextStyle(richEditorTextStyle, textStyle, typingStyle_);
2217 }
2218 }
2219 bool isNeedReset = !isBelowApi12 && (!info[0]->IsObject() || isUndefined);
2220 TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetTypingStyle %{public}d", isNeedReset);
2221 if (isNeedReset) {
2222 controller->SetTypingStyle(std::nullopt, std::nullopt);
2223 return;
2224 }
2225 controller->SetTypingStyle(typingStyle_, textStyle);
2226 }
2227
FontSizeRangeIsNegative(const CalcDimension & size)2228 bool JSRichEditorBaseController::FontSizeRangeIsNegative(const CalcDimension& size)
2229 {
2230 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2231 return size.IsNegative();
2232 }
2233 return size.IsNonPositive();
2234 }
2235
ParseJsTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2236 void JSRichEditorBaseController::ParseJsTextStyle(
2237 const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2238 {
2239 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2240 JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
2241 Color textColor;
2242 if (!fontColor->IsNull() && JSContainerBase::ParseJsColor(fontColor, textColor)) {
2243 style.SetTextColor(textColor);
2244 updateSpanStyle.updateTextColor = textColor;
2245 updateSpanStyle.useThemeFontColor = false;
2246 }
2247 JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
2248 CalcDimension size;
2249 if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size) &&
2250 !FontSizeRangeIsNegative(size) && size.Unit() != DimensionUnit::PERCENT) {
2251 updateSpanStyle.updateFontSize = size;
2252 style.SetFontSize(size);
2253 } else if (FontSizeRangeIsNegative(size) || size.Unit() == DimensionUnit::PERCENT) {
2254 auto theme = JSContainerBase::GetTheme<TextTheme>();
2255 CHECK_NULL_VOID(theme);
2256 size = theme->GetTextStyle().GetFontSize();
2257 style.SetFontSize(size);
2258 }
2259 ParseJsLineHeightLetterSpacingTextStyle(styleObject, style, updateSpanStyle);
2260 ParseJsFontFeatureTextStyle(styleObject, style, updateSpanStyle);
2261 JSRef<JSVal> fontStyle = styleObject->GetProperty("fontStyle");
2262 if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
2263 updateSpanStyle.updateItalicFontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
2264 style.SetFontStyle(static_cast<FontStyle>(fontStyle->ToNumber<int32_t>()));
2265 }
2266 JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
2267 std::string weight;
2268 if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
2269 if (fontWeight->IsNumber()) {
2270 weight = std::to_string(fontWeight->ToNumber<int32_t>());
2271 }
2272 updateSpanStyle.updateFontWeight = ConvertStrToFontWeight(weight);
2273 style.SetFontWeight(ConvertStrToFontWeight(weight));
2274 }
2275 JSRef<JSVal> fontFamily = styleObject->GetProperty("fontFamily");
2276 std::vector<std::string> family;
2277 if (!fontFamily->IsNull() && JSContainerBase::ParseJsFontFamilies(fontFamily, family)) {
2278 updateSpanStyle.updateFontFamily = family;
2279 style.SetFontFamilies(family);
2280 }
2281 ParseTextDecoration(styleObject, style, updateSpanStyle);
2282 ParseTextShadow(styleObject, style, updateSpanStyle);
2283 }
2284
ParseJsLineHeightLetterSpacingTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle,bool isSupportPercent)2285 void JSRichEditorBaseController::ParseJsLineHeightLetterSpacingTextStyle(const JSRef<JSObject>& styleObject,
2286 TextStyle& style, struct UpdateSpanStyle& updateSpanStyle, bool isSupportPercent)
2287 {
2288 JSRef<JSVal> lineHeight = styleObject->GetProperty("lineHeight");
2289 CalcDimension height;
2290 if (!lineHeight->IsNull() && JSContainerBase::ParseJsDimensionFpNG(lineHeight, height, isSupportPercent) &&
2291 !height.IsNegative() && height.Unit() != DimensionUnit::PERCENT) {
2292 updateSpanStyle.updateLineHeight = height;
2293 style.SetLineHeight(height);
2294 } else if (height.IsNegative() || height.Unit() == DimensionUnit::PERCENT) {
2295 auto theme = JSContainerBase::GetTheme<TextTheme>();
2296 CHECK_NULL_VOID(theme);
2297 height = theme->GetTextStyle().GetLineHeight();
2298 updateSpanStyle.updateLineHeight = height;
2299 style.SetLineHeight(height);
2300 } else if (!lineHeight->IsUndefined() &&
2301 !std::all_of(lineHeight->ToString().begin(), lineHeight->ToString().end(), ::isdigit)) {
2302 auto theme = JSContainerBase::GetTheme<TextTheme>();
2303 CHECK_NULL_VOID(theme);
2304 height = theme->GetTextStyle().GetLineHeight();
2305 updateSpanStyle.updateLineHeight = height;
2306 style.SetLineHeight(height);
2307 }
2308 JSRef<JSVal> letterSpacing = styleObject->GetProperty("letterSpacing");
2309 CalcDimension letters;
2310 if (JSContainerBase::ParseJsDimensionFpNG(letterSpacing, letters, isSupportPercent) &&
2311 letters.Unit() != DimensionUnit::PERCENT) {
2312 updateSpanStyle.updateLetterSpacing = letters;
2313 style.SetLetterSpacing(letters);
2314 } else if (letters.Unit() == DimensionUnit::PERCENT) {
2315 auto theme = JSContainerBase::GetTheme<TextTheme>();
2316 CHECK_NULL_VOID(theme);
2317 letters = theme->GetTextStyle().GetLetterSpacing();
2318 updateSpanStyle.updateLetterSpacing = letters;
2319 style.SetLetterSpacing(letters);
2320 } else if (!letterSpacing->IsUndefined() && !letterSpacing->IsNull() &&
2321 !std::all_of(letterSpacing->ToString().begin(), letterSpacing->ToString().end(), ::isdigit)) {
2322 auto theme = JSContainerBase::GetTheme<TextTheme>();
2323 CHECK_NULL_VOID(theme);
2324 letters = theme->GetTextStyle().GetLetterSpacing();
2325 updateSpanStyle.updateLetterSpacing = letters;
2326 style.SetLetterSpacing(letters);
2327 }
2328 }
2329
2330
ParseJsFontFeatureTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2331 void JSRichEditorBaseController::ParseJsFontFeatureTextStyle(const JSRef<JSObject>& styleObject,
2332 TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2333 {
2334 JSRef<JSVal> fontFeature = styleObject->GetProperty("fontFeature");
2335 std::string feature;
2336 if (!fontFeature->IsNull() && JSContainerBase::ParseJsString(fontFeature, feature)) {
2337 NG::FONT_FEATURES_LIST fontFeatures = ParseFontFeatureSettings(feature);
2338 updateSpanStyle.updateFontFeature = fontFeatures;
2339 style.SetFontFeatures(fontFeatures);
2340 } else {
2341 auto theme = JSContainerBase::GetTheme<TextTheme>();
2342 CHECK_NULL_VOID(theme);
2343 auto fontFeatures = theme->GetTextStyle().GetFontFeatures();
2344 updateSpanStyle.updateFontFeature = fontFeatures;
2345 style.SetFontFeatures(fontFeatures);
2346 }
2347 }
2348
ParseTextDecoration(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2349 void JSRichEditorBaseController::ParseTextDecoration(
2350 const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2351 {
2352 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2353 auto decorationObject = JSObjectCast(styleObject->GetProperty("decoration"));
2354 if (!decorationObject->IsUndefined()) {
2355 JSRef<JSVal> type = decorationObject->GetProperty("type");
2356 if (!type->IsNull() && !type->IsUndefined()) {
2357 updateSpanStyle.updateTextDecoration = static_cast<TextDecoration>(type->ToNumber<int32_t>());
2358 style.SetTextDecoration(static_cast<TextDecoration>(type->ToNumber<int32_t>()));
2359 }
2360 JSRef<JSVal> color = decorationObject->GetProperty("color");
2361 Color decorationColor;
2362 if (!color->IsNull() && JSContainerBase::ParseJsColor(color, decorationColor)) {
2363 updateSpanStyle.updateTextDecorationColor = decorationColor;
2364 style.SetTextDecorationColor(decorationColor);
2365 updateSpanStyle.useThemeDecorationColor = false;
2366 }
2367 JSRef<JSVal> textDecorationStyle = decorationObject->GetProperty("style");
2368 if (!textDecorationStyle->IsNull() && !textDecorationStyle->IsUndefined()) {
2369 updateSpanStyle.updateTextDecorationStyle =
2370 static_cast<TextDecorationStyle>(textDecorationStyle->ToNumber<int32_t>());
2371 style.SetTextDecorationStyle(static_cast<TextDecorationStyle>(textDecorationStyle->ToNumber<int32_t>()));
2372 }
2373 updateSpanStyle.isInitDecoration = true;
2374 }
2375 if (!updateSpanStyle.updateTextDecorationColor.has_value() && updateSpanStyle.updateTextColor.has_value()) {
2376 updateSpanStyle.updateTextDecorationColor = style.GetTextColor();
2377 style.SetTextDecorationColor(style.GetTextColor());
2378 }
2379 }
2380
ParseTextShadow(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2381 void JSRichEditorBaseController::ParseTextShadow(
2382 const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2383 {
2384 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2385 auto shadowObject = styleObject->GetProperty("textShadow");
2386 if (shadowObject->IsNull()) {
2387 return;
2388 }
2389 std::vector<Shadow> shadows;
2390 ParseTextShadowFromShadowObject(shadowObject, shadows);
2391 if (!shadows.empty()) {
2392 updateSpanStyle.updateTextShadows = shadows;
2393 style.SetTextShadows(shadows);
2394 }
2395 }
2396
GetTypingStyle(const JSCallbackInfo & info)2397 void JSRichEditorBaseController::GetTypingStyle(const JSCallbackInfo& info)
2398 {
2399 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2400 auto controller = controllerWeak_.Upgrade();
2401 CHECK_NULL_VOID(controller);
2402 auto typingStyle = controller->GetTypingStyle();
2403 auto style = CreateTypingStyleResult(typingStyle.value_or(UpdateSpanStyle()));
2404 info.SetReturnValue(JSRef<JSVal>::Cast(style));
2405 }
2406
CreateTypingStyleResult(const struct UpdateSpanStyle & typingStyle)2407 JSRef<JSObject> JSRichEditorBaseController::CreateTypingStyleResult(const struct UpdateSpanStyle& typingStyle)
2408 {
2409 auto tyingStyleObj = JSRef<JSObject>::New();
2410 if (typingStyle.updateFontFamily.has_value()) {
2411 std::string family = V2::ConvertFontFamily(typingStyle.updateFontFamily.value());
2412 tyingStyleObj->SetProperty<std::string>("fontFamily", family);
2413 }
2414 if (typingStyle.updateFontSize.has_value()) {
2415 tyingStyleObj->SetProperty<double>("fontSize", typingStyle.updateFontSize.value().ConvertToVp());
2416 }
2417 if (typingStyle.updateLineHeight.has_value()) {
2418 tyingStyleObj->SetProperty<double>("lineHeight", typingStyle.updateLineHeight.value().ConvertToVp());
2419 }
2420 if (typingStyle.updateLetterSpacing.has_value()) {
2421 tyingStyleObj->SetProperty<double>("letterSpacing", typingStyle.updateLetterSpacing.value().ConvertToVp());
2422 }
2423 if (typingStyle.updateTextColor.has_value()) {
2424 tyingStyleObj->SetProperty<std::string>("fontColor", typingStyle.updateTextColor.value().ColorToString());
2425 }
2426 if (typingStyle.updateFontFeature.has_value()) {
2427 tyingStyleObj->SetProperty<std::string>(
2428 "fontFeature", UnParseFontFeatureSetting(typingStyle.updateFontFeature.value()));
2429 }
2430 if (typingStyle.updateItalicFontStyle.has_value()) {
2431 tyingStyleObj->SetProperty<int32_t>(
2432 "fontStyle", static_cast<int32_t>(typingStyle.updateItalicFontStyle.value()));
2433 }
2434 if (typingStyle.updateFontWeight.has_value()) {
2435 tyingStyleObj->SetProperty<int32_t>("fontWeight", static_cast<int32_t>(typingStyle.updateFontWeight.value()));
2436 }
2437
2438 JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
2439 if (typingStyle.updateTextDecoration.has_value()) {
2440 decorationObj->SetProperty<int32_t>("type", static_cast<int32_t>(typingStyle.updateTextDecoration.value()));
2441 }
2442 if (typingStyle.updateTextDecorationColor.has_value()) {
2443 decorationObj->SetProperty<std::string>(
2444 "color", typingStyle.updateTextDecorationColor.value().ColorToString());
2445 }
2446 if (typingStyle.updateTextDecorationStyle.has_value()) {
2447 decorationObj->SetProperty<int32_t>("style",
2448 static_cast<int32_t>(typingStyle.updateTextDecorationStyle.value()));
2449 }
2450 if (typingStyle.isInitDecoration) {
2451 tyingStyleObj->SetPropertyObject("decoration", decorationObj);
2452 }
2453 if (typingStyle.updateTextShadows.has_value()) {
2454 tyingStyleObj->SetPropertyObject("textShadows",
2455 JSRichEditor::CreateJsTextShadowObjectArray(typingStyle.updateTextShadows.value()));
2456 }
2457 return tyingStyleObj;
2458 }
2459
CloseSelectionMenu()2460 void JSRichEditorBaseController::CloseSelectionMenu()
2461 {
2462 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2463 auto controller = controllerWeak_.Upgrade();
2464 CHECK_NULL_VOID(controller);
2465 controller->CloseSelectionMenu();
2466 }
2467
IsEditing(const JSCallbackInfo & args)2468 void JSRichEditorBaseController::IsEditing(const JSCallbackInfo& args)
2469 {
2470 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2471 auto controller = controllerWeak_.Upgrade();
2472 CHECK_NULL_VOID(controller);
2473 bool value = controller->IsEditing();
2474 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
2475 args.SetReturnValue(JsiRef<JsiValue>::Make(panda::BooleanRef::New(runtime->GetEcmaVm(), value)));
2476 }
2477
ToStyledString(const JSCallbackInfo & args)2478 void JSRichEditorController::ToStyledString(const JSCallbackInfo& args)
2479 {
2480 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2481 int32_t end = -1;
2482 int32_t start = -1;
2483 if (args[0]->IsObject()) {
2484 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
2485 JSRef<JSVal> startVal = obj->GetProperty("start");
2486 JSRef<JSVal> endVal = obj->GetProperty("end");
2487
2488 if (!startVal->IsNull() && startVal->IsNumber()) {
2489 start = startVal->ToNumber<int32_t>();
2490 }
2491
2492 if (!endVal->IsNull() && endVal->IsNumber()) {
2493 end = endVal->ToNumber<int32_t>();
2494 }
2495 }
2496 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controllerWeak_.Upgrade());
2497 CHECK_NULL_VOID(richEditorController);
2498 auto spanStringBase = richEditorController->ToStyledString(start, end);
2499 auto spanString = AceType::DynamicCast<SpanString>(spanStringBase);
2500 CHECK_NULL_VOID(spanString);
2501 JSRef<JSObject> obj = JSClass<JSSpanString>::NewInstance();
2502 auto jsSpanString = Referenced::Claim(obj->Unwrap<JSSpanString>());
2503 jsSpanString->SetController(spanString);
2504 args.SetReturnValue(obj);
2505 }
2506
FromStyledString(const JSCallbackInfo & args)2507 void JSRichEditorController::FromStyledString(const JSCallbackInfo& args)
2508 {
2509 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2510 if ((args.Length() != 1) || !args[0]->IsObject()) {
2511 return;
2512 }
2513 auto* spanString = JSRef<JSObject>::Cast(args[0])->Unwrap<JSSpanString>();
2514 CHECK_NULL_VOID(spanString);
2515 auto spanStringController = spanString->GetController();
2516 CHECK_NULL_VOID(spanStringController);
2517 auto controller = controllerWeak_.Upgrade();
2518 auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2519 CHECK_NULL_VOID(richEditorController);
2520 SelectionInfo value = richEditorController->FromStyledString(spanStringController);
2521 args.SetReturnValue(CreateJSSpansInfo(value));
2522 }
2523
StopEditing()2524 void JSRichEditorBaseController::StopEditing()
2525 {
2526 auto controller = controllerWeak_.Upgrade();
2527 CHECK_NULL_VOID(controller);
2528 controller->StopEditing();
2529 }
2530
JSObjectCast(JSRef<JSVal> jsValue)2531 JSRef<JSObject> JSRichEditorBaseController::JSObjectCast(JSRef<JSVal> jsValue)
2532 {
2533 JSRef<JSObject> jsObject;
2534 if (!jsValue->IsObject()) {
2535 return jsObject;
2536 }
2537 return JSRef<JSObject>::Cast(jsValue);
2538 }
2539
SetSelection(const JSCallbackInfo & args)2540 void JSRichEditorBaseController::SetSelection(const JSCallbackInfo& args)
2541 {
2542 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2543 if (args.Length() < 2) { // 2:At least two parameters
2544 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error.");
2545 return;
2546 }
2547 int32_t selectionStart = 0;
2548 int32_t selectionEnd = 0;
2549 JSContainerBase::ParseJsInt32(args[0], selectionStart);
2550 JSContainerBase::ParseJsInt32(args[1], selectionEnd);
2551 auto controller = controllerWeak_.Upgrade();
2552 CHECK_NULL_VOID(controller);
2553 std::optional<SelectionOptions> options = std::nullopt;
2554 ParseJsSelectionOptions(args, options);
2555 controller->SetSelection(selectionStart, selectionEnd, options);
2556 }
2557
GetLayoutManager(const JSCallbackInfo & args)2558 void JSRichEditorBaseController::GetLayoutManager(const JSCallbackInfo& args)
2559 {
2560 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2561 JSRef<JSObject> obj = JSClass<JSLayoutManager>::NewInstance();
2562 auto jsLayoutManager = Referenced::Claim(obj->Unwrap<JSLayoutManager>());
2563 CHECK_NULL_VOID(jsLayoutManager);
2564 jsLayoutManager->IncRefCount();
2565 auto controller = controllerWeak_.Upgrade();
2566 CHECK_NULL_VOID(controller);
2567 auto layoutInfoInterface = controller->GetLayoutInfoInterface();
2568 jsLayoutManager->SetLayoutInfoInterface(layoutInfoInterface);
2569 args.SetReturnValue(obj);
2570 }
2571
ParseJsSelectionOptions(const JSCallbackInfo & args,std::optional<SelectionOptions> & options)2572 void JSRichEditorBaseController::ParseJsSelectionOptions(
2573 const JSCallbackInfo& args, std::optional<SelectionOptions>& options)
2574 {
2575 if (args.Length() < 3) { // 3:Protect operations
2576 return;
2577 }
2578 auto temp = args[2]; // 2:Get the third parameter
2579 if (!temp->IsObject()) {
2580 return;
2581 }
2582 SelectionOptions optionTemp;
2583 JSRef<JSObject> placeholderOptionObject = JSRef<JSObject>::Cast(temp);
2584 JSRef<JSVal> menuPolicy = placeholderOptionObject->GetProperty("menuPolicy");
2585 double tempPolicy = 0.0;
2586 if (!menuPolicy->IsNull() && JSContainerBase::ParseJsDouble(menuPolicy, tempPolicy)) {
2587 if (0 == tempPolicy || 1 == tempPolicy || 2 == tempPolicy) { // 0:DEFAULT, 1:HIDE, 2:SHOW
2588 optionTemp.menuPolicy = static_cast<MenuPolicy>(tempPolicy);
2589 options = optionTemp;
2590 }
2591 }
2592 }
2593
GetSelection(const JSCallbackInfo & args)2594 void JSRichEditorStyledStringController::GetSelection(const JSCallbackInfo& args)
2595 {
2596 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2597 auto controller = controllerWeak_.Upgrade();
2598 auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2599 CHECK_NULL_VOID(styledStringController);
2600 SelectionRangeInfo value = styledStringController->GetSelection();
2601 args.SetReturnValue(JSRichEditor::CreateJSSelectionRange(value));
2602 }
2603
SetStyledString(const JSCallbackInfo & args)2604 void JSRichEditorStyledStringController::SetStyledString(const JSCallbackInfo& args)
2605 {
2606 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2607 if ((args.Length() != 1) || !args[0]->IsObject()) {
2608 return;
2609 }
2610 auto* spanString = JSRef<JSObject>::Cast(args[0])->Unwrap<JSSpanString>();
2611 CHECK_NULL_VOID(spanString);
2612 auto spanStringController = spanString->GetController();
2613 CHECK_NULL_VOID(spanStringController);
2614 auto controller = controllerWeak_.Upgrade();
2615 auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2616 CHECK_NULL_VOID(styledStringController);
2617 styledStringController->SetStyledString(spanStringController);
2618 }
2619
GetStyledString(const JSCallbackInfo & args)2620 void JSRichEditorStyledStringController::GetStyledString(const JSCallbackInfo& args)
2621 {
2622 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2623 auto controller = controllerWeak_.Upgrade();
2624 auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2625 CHECK_NULL_VOID(styledStringController);
2626 auto mutableSpanString = AceType::DynamicCast<MutableSpanString>(styledStringController->GetStyledString());
2627 CHECK_NULL_VOID(mutableSpanString);
2628 JSRef<JSObject> obj = JSClass<JSMutableSpanString>::NewInstance();
2629 auto jsMutableSpanString = Referenced::Claim(obj->Unwrap<JSMutableSpanString>());
2630 CHECK_NULL_VOID(jsMutableSpanString);
2631 jsMutableSpanString->IncRefCount();
2632 jsMutableSpanString->SetController(mutableSpanString);
2633 jsMutableSpanString->SetMutableController(mutableSpanString);
2634 args.SetReturnValue(obj);
2635 }
2636
OnContentChanged(const JSCallbackInfo & args)2637 void JSRichEditorStyledStringController::OnContentChanged(const JSCallbackInfo& args)
2638 {
2639 ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2640 CHECK_NULL_VOID(args[0]->IsObject());
2641 SetOnWillChange(args);
2642 SetOnDidChange(args);
2643 }
2644
SetOnWillChange(const JSCallbackInfo & args)2645 void JSRichEditorStyledStringController::SetOnWillChange(const JSCallbackInfo& args)
2646 {
2647 if (!args[0]->IsObject()) {
2648 return;
2649 }
2650 auto paramObject = JSRef<JSObject>::Cast(args[0]);
2651 auto onWillChangeFunc = paramObject->GetProperty("onWillChange");
2652 if (onWillChangeFunc->IsNull() || !onWillChangeFunc->IsFunction()) {
2653 return;
2654 }
2655 auto jsOnWillChangeFunc = AceType::MakeRefPtr<JsEventFunction<NG::StyledStringChangeValue, 1>>(
2656 JSRef<JSFunc>::Cast(onWillChangeFunc), CreateJsOnWillChange);
2657 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnWillChangeFunc)](
2658 const NG::StyledStringChangeValue& changeValue) -> bool {
2659 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
2660 auto ret = func->ExecuteWithValue(changeValue);
2661 if (ret->IsBoolean()) {
2662 return ret->ToBoolean();
2663 }
2664 return true;
2665 };
2666 auto controller = controllerWeak_.Upgrade();
2667 auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2668 CHECK_NULL_VOID(styledStringController);
2669 styledStringController->SetOnWillChange(std::move(callback));
2670 }
2671
SetOnDidChange(const JSCallbackInfo & args)2672 void JSRichEditorStyledStringController::SetOnDidChange(const JSCallbackInfo& args)
2673 {
2674 if (!args[0]->IsObject()) {
2675 return;
2676 }
2677 auto paramObject = JSRef<JSObject>::Cast(args[0]);
2678 auto onDidChangeFunc = paramObject->GetProperty("onDidChange");
2679 if (onDidChangeFunc->IsNull() || !onDidChangeFunc->IsFunction()) {
2680 return;
2681 }
2682 auto jsOnDidChangeFunc = AceType::MakeRefPtr<JsCommonEventFunction<NG::StyledStringChangeValue, 2>>(
2683 JSRef<JSFunc>::Cast(onDidChangeFunc));
2684 auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnDidChangeFunc)](
2685 const NG::StyledStringChangeValue& changeValue) {
2686 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2687 const auto& rangeBefore = changeValue.GetRangeBefore();
2688 JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
2689 rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
2690 rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
2691
2692 const auto& rangeAfter = changeValue.GetRangeAfter();
2693 JSRef<JSObject> rangeAfterObj = JSRef<JSObject>::New();
2694 rangeAfterObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeAfter.start)));
2695 rangeAfterObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeAfter.end)));
2696
2697 JSRef<JSVal> param[2] = { JSRef<JSVal>::Cast(rangeBeforeObj), JSRef<JSVal>::Cast(rangeAfterObj) };
2698 func->Execute(param);
2699 };
2700 auto controller = controllerWeak_.Upgrade();
2701 auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2702 CHECK_NULL_VOID(styledStringController);
2703 styledStringController->SetOnDidChange(std::move(callback));
2704 }
2705
CreateJsOnWillChange(const NG::StyledStringChangeValue & changeValue)2706 JSRef<JSVal> JSRichEditorStyledStringController::CreateJsOnWillChange(const NG::StyledStringChangeValue& changeValue)
2707 {
2708 JSRef<JSObject> onWillChangeObj = JSRef<JSObject>::New();
2709 JSRef<JSObject> rangeObj = JSRef<JSObject>::New();
2710 auto rangeBefore = changeValue.GetRangeBefore();
2711 rangeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
2712 rangeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
2713 auto spanString = AceType::DynamicCast<SpanString>(changeValue.GetReplacementString());
2714 CHECK_NULL_RETURN(spanString, JSRef<JSVal>::Cast(onWillChangeObj));
2715 JSRef<JSObject> replacementStringObj = JSClass<JSSpanString>::NewInstance();
2716 auto jsSpanString = Referenced::Claim(replacementStringObj->Unwrap<JSSpanString>());
2717 jsSpanString->SetController(spanString);
2718 onWillChangeObj->SetPropertyObject("range", rangeObj);
2719 onWillChangeObj->SetPropertyObject("replacementString", replacementStringObj);
2720 return JSRef<JSVal>::Cast(onWillChangeObj);
2721 }
2722
JSBind(BindingTarget globalObj)2723 void JSRichEditorStyledStringController::JSBind(BindingTarget globalObj)
2724 {
2725 JSClass<JSRichEditorStyledStringController>::Declare("RichEditorStyledStringController");
2726 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2727 "setCaretOffset", &JSRichEditorStyledStringController::SetCaretOffset);
2728 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2729 "getCaretOffset", &JSRichEditorStyledStringController::GetCaretOffset);
2730 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2731 "getTypingStyle", &JSRichEditorStyledStringController::GetTypingStyle);
2732 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2733 "setTypingStyle", &JSRichEditorStyledStringController::SetTypingStyle);
2734 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2735 "getSelection", &JSRichEditorStyledStringController::GetSelection);
2736 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2737 "getPreviewText", &JSRichEditorStyledStringController::GetPreviewTextInfo);
2738 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2739 "setSelection", &JSRichEditorStyledStringController::SetSelection);
2740 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2741 "isEditing", &JSRichEditorStyledStringController::IsEditing);
2742 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2743 "setStyledString", &JSRichEditorStyledStringController::SetStyledString);
2744 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2745 "getStyledString", &JSRichEditorStyledStringController::GetStyledString);
2746 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2747 "onContentChanged", &JSRichEditorStyledStringController::OnContentChanged);
2748 JSClass<JSRichEditorStyledStringController>::CustomMethod(
2749 "getLayoutManager", &JSRichEditorStyledStringController::GetLayoutManager);
2750 JSClass<JSRichEditorStyledStringController>::Method(
2751 "stopEditing", &JSRichEditorStyledStringController::StopEditing);
2752 JSClass<JSRichEditorStyledStringController>::Method(
2753 "closeSelectionMenu", &JSRichEditorStyledStringController::CloseSelectionMenu);
2754 JSClass<JSRichEditorStyledStringController>::Bind(
2755 globalObj, JSRichEditorStyledStringController::Constructor, JSRichEditorStyledStringController::Destructor);
2756 }
2757 } // namespace OHOS::Ace::Framework
2758