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