roosterjs-content-model-plugins 9.26.0 → 9.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/autoFormat/AutoFormatPlugin.d.ts +4 -1
- package/lib/autoFormat/AutoFormatPlugin.js +94 -96
- package/lib/autoFormat/AutoFormatPlugin.js.map +1 -1
- package/lib/autoFormat/horizontalLine/checkAndInsertHorizontalLine.d.ts +3 -3
- package/lib/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js +14 -21
- package/lib/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js.map +1 -1
- package/lib/edit/EditPlugin.d.ts +9 -0
- package/lib/edit/EditPlugin.js +19 -3
- package/lib/edit/EditPlugin.js.map +1 -1
- package/lib/edit/utils/splitParagraph.d.ts +3 -2
- package/lib/edit/utils/splitParagraph.js +41 -2
- package/lib/edit/utils/splitParagraph.js.map +1 -1
- package/lib/imageEdit/ImageEditPlugin.js +9 -9
- package/lib/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib/imageEdit/utils/findEditingImage.d.ts +4 -0
- package/lib/imageEdit/utils/findEditingImage.js +7 -2
- package/lib/imageEdit/utils/findEditingImage.js.map +1 -1
- package/lib/paste/PastePlugin.js +3 -3
- package/lib/paste/PastePlugin.js.map +1 -1
- package/lib/paste/PowerPoint/processPastedContentFromPowerPoint.js +132 -1
- package/lib/paste/PowerPoint/processPastedContentFromPowerPoint.js.map +1 -1
- package/lib/paste/WordDesktop/getStyleMetadata.d.ts +2 -2
- package/lib/paste/WordDesktop/getStyleMetadata.js +22 -5
- package/lib/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -2
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js +5 -5
- package/lib/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib/paste/WordDesktop/processWordLists.js +25 -60
- package/lib/paste/WordDesktop/processWordLists.js.map +1 -1
- package/lib/paste/parsers/deprecatedColorParser.js.map +1 -0
- package/lib/paste/parsers/linkParser.js.map +1 -0
- package/lib/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.js +1 -1
- package/lib/paste/parsers/removeNegativeTextIndentParser.js.map +1 -0
- package/lib/paste/utils/customListUtils.d.ts +9 -0
- package/lib/paste/utils/customListUtils.js +63 -0
- package/lib/paste/utils/customListUtils.js.map +1 -0
- package/lib/watermark/WatermarkPlugin.js +1 -1
- package/lib/watermark/WatermarkPlugin.js.map +1 -1
- package/lib-amd/autoFormat/AutoFormatPlugin.d.ts +4 -1
- package/lib-amd/autoFormat/AutoFormatPlugin.js +94 -96
- package/lib-amd/autoFormat/AutoFormatPlugin.js.map +1 -1
- package/lib-amd/autoFormat/horizontalLine/checkAndInsertHorizontalLine.d.ts +3 -3
- package/lib-amd/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js +15 -21
- package/lib-amd/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js.map +1 -1
- package/lib-amd/edit/EditPlugin.d.ts +9 -0
- package/lib-amd/edit/EditPlugin.js +19 -3
- package/lib-amd/edit/EditPlugin.js.map +1 -1
- package/lib-amd/edit/utils/splitParagraph.d.ts +3 -2
- package/lib-amd/edit/utils/splitParagraph.js +41 -2
- package/lib-amd/edit/utils/splitParagraph.js.map +1 -1
- package/lib-amd/imageEdit/ImageEditPlugin.js +9 -9
- package/lib-amd/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib-amd/imageEdit/utils/findEditingImage.d.ts +4 -0
- package/lib-amd/imageEdit/utils/findEditingImage.js +7 -2
- package/lib-amd/imageEdit/utils/findEditingImage.js.map +1 -1
- package/lib-amd/paste/PastePlugin.js +2 -2
- package/lib-amd/paste/PastePlugin.js.map +1 -1
- package/lib-amd/paste/PowerPoint/processPastedContentFromPowerPoint.js +128 -2
- package/lib-amd/paste/PowerPoint/processPastedContentFromPowerPoint.js.map +1 -1
- package/lib-amd/paste/WordDesktop/getStyleMetadata.d.ts +2 -2
- package/lib-amd/paste/WordDesktop/getStyleMetadata.js +22 -5
- package/lib-amd/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -2
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js +5 -5
- package/lib-amd/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib-amd/paste/WordDesktop/processWordLists.js +25 -60
- package/lib-amd/paste/WordDesktop/processWordLists.js.map +1 -1
- package/lib-amd/paste/parsers/deprecatedColorParser.js.map +1 -0
- package/lib-amd/paste/parsers/linkParser.js.map +1 -0
- package/lib-amd/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.js +1 -1
- package/lib-amd/paste/parsers/removeNegativeTextIndentParser.js.map +1 -0
- package/lib-amd/paste/utils/customListUtils.d.ts +9 -0
- package/lib-amd/paste/utils/customListUtils.js +63 -0
- package/lib-amd/paste/utils/customListUtils.js.map +1 -0
- package/lib-amd/watermark/WatermarkPlugin.js +1 -1
- package/lib-amd/watermark/WatermarkPlugin.js.map +1 -1
- package/lib-mjs/autoFormat/AutoFormatPlugin.d.ts +4 -1
- package/lib-mjs/autoFormat/AutoFormatPlugin.js +95 -97
- package/lib-mjs/autoFormat/AutoFormatPlugin.js.map +1 -1
- package/lib-mjs/autoFormat/horizontalLine/checkAndInsertHorizontalLine.d.ts +3 -3
- package/lib-mjs/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js +15 -22
- package/lib-mjs/autoFormat/horizontalLine/checkAndInsertHorizontalLine.js.map +1 -1
- package/lib-mjs/edit/EditPlugin.d.ts +9 -0
- package/lib-mjs/edit/EditPlugin.js +19 -3
- package/lib-mjs/edit/EditPlugin.js.map +1 -1
- package/lib-mjs/edit/utils/splitParagraph.d.ts +3 -2
- package/lib-mjs/edit/utils/splitParagraph.js +42 -3
- package/lib-mjs/edit/utils/splitParagraph.js.map +1 -1
- package/lib-mjs/imageEdit/ImageEditPlugin.js +11 -11
- package/lib-mjs/imageEdit/ImageEditPlugin.js.map +1 -1
- package/lib-mjs/imageEdit/utils/findEditingImage.d.ts +4 -0
- package/lib-mjs/imageEdit/utils/findEditingImage.js +6 -1
- package/lib-mjs/imageEdit/utils/findEditingImage.js.map +1 -1
- package/lib-mjs/paste/PastePlugin.js +3 -3
- package/lib-mjs/paste/PastePlugin.js.map +1 -1
- package/lib-mjs/paste/PowerPoint/processPastedContentFromPowerPoint.js +133 -2
- package/lib-mjs/paste/PowerPoint/processPastedContentFromPowerPoint.js.map +1 -1
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.d.ts +2 -2
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.js +22 -5
- package/lib-mjs/paste/WordDesktop/getStyleMetadata.js.map +1 -1
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.d.ts +2 -2
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js +5 -5
- package/lib-mjs/paste/WordDesktop/processPastedContentFromWordDesktop.js.map +1 -1
- package/lib-mjs/paste/WordDesktop/processWordLists.js +26 -61
- package/lib-mjs/paste/WordDesktop/processWordLists.js.map +1 -1
- package/lib-mjs/paste/parsers/deprecatedColorParser.js.map +1 -0
- package/lib-mjs/paste/parsers/linkParser.js.map +1 -0
- package/lib-mjs/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.js +1 -1
- package/lib-mjs/paste/parsers/removeNegativeTextIndentParser.js.map +1 -0
- package/lib-mjs/paste/utils/customListUtils.d.ts +9 -0
- package/lib-mjs/paste/utils/customListUtils.js +58 -0
- package/lib-mjs/paste/utils/customListUtils.js.map +1 -0
- package/lib-mjs/watermark/WatermarkPlugin.js +1 -1
- package/lib-mjs/watermark/WatermarkPlugin.js.map +1 -1
- package/package.json +5 -5
- package/lib/paste/WordDesktop/removeNegativeTextIndentParser.js.map +0 -1
- package/lib/paste/utils/deprecatedColorParser.js.map +0 -1
- package/lib/paste/utils/linkParser.js.map +0 -1
- package/lib-amd/paste/WordDesktop/removeNegativeTextIndentParser.js.map +0 -1
- package/lib-amd/paste/utils/deprecatedColorParser.js.map +0 -1
- package/lib-amd/paste/utils/linkParser.js.map +0 -1
- package/lib-mjs/paste/WordDesktop/removeNegativeTextIndentParser.js.map +0 -1
- package/lib-mjs/paste/utils/deprecatedColorParser.js.map +0 -1
- package/lib-mjs/paste/utils/linkParser.js.map +0 -1
- /package/lib/paste/{utils → parsers}/deprecatedColorParser.d.ts +0 -0
- /package/lib/paste/{utils → parsers}/deprecatedColorParser.js +0 -0
- /package/lib/paste/{utils → parsers}/linkParser.d.ts +0 -0
- /package/lib/paste/{utils → parsers}/linkParser.js +0 -0
- /package/lib/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.d.ts +0 -0
- /package/lib-amd/paste/{utils → parsers}/deprecatedColorParser.d.ts +0 -0
- /package/lib-amd/paste/{utils → parsers}/deprecatedColorParser.js +0 -0
- /package/lib-amd/paste/{utils → parsers}/linkParser.d.ts +0 -0
- /package/lib-amd/paste/{utils → parsers}/linkParser.js +0 -0
- /package/lib-amd/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.d.ts +0 -0
- /package/lib-mjs/paste/{utils → parsers}/deprecatedColorParser.d.ts +0 -0
- /package/lib-mjs/paste/{utils → parsers}/deprecatedColorParser.js +0 -0
- /package/lib-mjs/paste/{utils → parsers}/linkParser.d.ts +0 -0
- /package/lib-mjs/paste/{utils → parsers}/linkParser.js +0 -0
- /package/lib-mjs/paste/{WordDesktop → parsers}/removeNegativeTextIndentParser.d.ts +0 -0
|
@@ -46,9 +46,12 @@ export declare class AutoFormatPlugin implements EditorPlugin {
|
|
|
46
46
|
* @param event The event to handle:
|
|
47
47
|
*/
|
|
48
48
|
onPluginEvent(event: PluginEvent): void;
|
|
49
|
+
private autoLink;
|
|
50
|
+
private tabFeatures;
|
|
49
51
|
private features;
|
|
52
|
+
private enterFeatures;
|
|
53
|
+
private handleKeyboardEvents;
|
|
50
54
|
private handleEditorInputEvent;
|
|
51
55
|
private handleKeyDownEvent;
|
|
52
|
-
private handleEnterKey;
|
|
53
56
|
private handleContentChangedEvent;
|
|
54
57
|
}
|
|
@@ -49,52 +49,71 @@ var AutoFormatPlugin = /** @class */ (function () {
|
|
|
49
49
|
if (options === void 0) { options = DefaultOptions; }
|
|
50
50
|
this.options = options;
|
|
51
51
|
this.editor = null;
|
|
52
|
-
this.
|
|
52
|
+
this.autoLink = {
|
|
53
|
+
enabled: !!(this.options.autoLink || this.options.autoTel || this.options.autoMailto),
|
|
54
|
+
transformFunction: function (_model, previousSegment, paragraph, context) {
|
|
55
|
+
var _a;
|
|
56
|
+
var _b = _this.options, autoLink = _b.autoLink, autoTel = _b.autoTel, autoMailto = _b.autoMailto;
|
|
57
|
+
var linkSegment = (0, roosterjs_content_model_api_1.promoteLink)(previousSegment, paragraph, {
|
|
58
|
+
autoLink: autoLink,
|
|
59
|
+
autoTel: autoTel,
|
|
60
|
+
autoMailto: autoMailto,
|
|
61
|
+
});
|
|
62
|
+
if (linkSegment) {
|
|
63
|
+
return createAnchor(((_a = linkSegment.link) === null || _a === void 0 ? void 0 : _a.format.href) || '', linkSegment.text);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
},
|
|
67
|
+
apiName: 'autoLink',
|
|
68
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoLink,
|
|
69
|
+
};
|
|
70
|
+
this.tabFeatures = [
|
|
53
71
|
{
|
|
54
|
-
autoFormat: 'list',
|
|
55
72
|
enabled: !!(this.options.autoBullet || this.options.autoNumbering),
|
|
56
73
|
transformFunction: function (model, _previousSegment, paragraph, context) {
|
|
57
74
|
return (0, keyboardListTrigger_1.keyboardListTrigger)(model, paragraph, context, _this.options.autoBullet, _this.options.autoNumbering, _this.options.removeListMargins);
|
|
58
75
|
},
|
|
76
|
+
apiName: 'autoToggleList',
|
|
77
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoFormat,
|
|
59
78
|
},
|
|
79
|
+
this.autoLink,
|
|
80
|
+
];
|
|
81
|
+
this.features = (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(this.tabFeatures), false), [
|
|
60
82
|
{
|
|
61
|
-
autoFormat: 'link',
|
|
62
|
-
enabled: !!(this.options.autoLink || this.options.autoTel || this.options.autoMailto),
|
|
63
|
-
transformFunction: function (_model, previousSegment, paragraph, context) {
|
|
64
|
-
var _a;
|
|
65
|
-
var _b = _this.options, autoLink = _b.autoLink, autoTel = _b.autoTel, autoMailto = _b.autoMailto;
|
|
66
|
-
var linkSegment = (0, roosterjs_content_model_api_1.promoteLink)(previousSegment, paragraph, {
|
|
67
|
-
autoLink: autoLink,
|
|
68
|
-
autoTel: autoTel,
|
|
69
|
-
autoMailto: autoMailto,
|
|
70
|
-
});
|
|
71
|
-
if (linkSegment) {
|
|
72
|
-
return createAnchor(((_a = linkSegment.link) === null || _a === void 0 ? void 0 : _a.format.href) || '', linkSegment.text);
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
autoFormat: 'hyphen',
|
|
79
83
|
enabled: !!this.options.autoHyphen,
|
|
84
|
+
apiName: 'autoHyphen',
|
|
85
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.Format,
|
|
80
86
|
transformFunction: function (_model, previousSegment, paragraph, context) {
|
|
81
87
|
return (0, transformHyphen_1.transformHyphen)(previousSegment, paragraph, context);
|
|
82
88
|
},
|
|
83
89
|
},
|
|
84
90
|
{
|
|
85
|
-
autoFormat: 'fraction',
|
|
86
91
|
enabled: !!this.options.autoFraction,
|
|
92
|
+
apiName: 'autoFraction',
|
|
93
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.Format,
|
|
87
94
|
transformFunction: function (_model, previousSegment, paragraph, context) {
|
|
88
95
|
return (0, transformFraction_1.transformFraction)(previousSegment, paragraph, context);
|
|
89
96
|
},
|
|
90
97
|
},
|
|
91
98
|
{
|
|
92
|
-
autoFormat: 'ordinal',
|
|
93
99
|
enabled: !!this.options.autoOrdinals,
|
|
100
|
+
apiName: 'autoOrdinal',
|
|
101
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.Format,
|
|
94
102
|
transformFunction: function (_model, previousSegment, paragraph, context) {
|
|
95
103
|
return (0, transformOrdinals_1.transformOrdinals)(previousSegment, paragraph, context);
|
|
96
104
|
},
|
|
97
105
|
},
|
|
106
|
+
], false);
|
|
107
|
+
this.enterFeatures = [
|
|
108
|
+
{
|
|
109
|
+
enabled: !!this.options.autoHorizontalLine,
|
|
110
|
+
transformFunction: function (model, _previousSegment, paragraph, context) {
|
|
111
|
+
return (0, checkAndInsertHorizontalLine_1.checkAndInsertHorizontalLine)(model, paragraph, context);
|
|
112
|
+
},
|
|
113
|
+
apiName: 'autoHorizontalLine',
|
|
114
|
+
changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoFormat,
|
|
115
|
+
},
|
|
116
|
+
this.autoLink,
|
|
98
117
|
];
|
|
99
118
|
}
|
|
100
119
|
/**
|
|
@@ -141,8 +160,51 @@ var AutoFormatPlugin = /** @class */ (function () {
|
|
|
141
160
|
}
|
|
142
161
|
}
|
|
143
162
|
};
|
|
163
|
+
AutoFormatPlugin.prototype.handleKeyboardEvents = function (editor, features) {
|
|
164
|
+
var formatOptions = {
|
|
165
|
+
changeSource: '',
|
|
166
|
+
apiName: '',
|
|
167
|
+
getChangeData: undefined,
|
|
168
|
+
};
|
|
169
|
+
(0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (model, previousSegment, paragraph, _markerFormat, context) {
|
|
170
|
+
var e_1, _a;
|
|
171
|
+
var featureApplied = undefined;
|
|
172
|
+
var _loop_1 = function (feature) {
|
|
173
|
+
if (feature.enabled) {
|
|
174
|
+
var result_1 = feature.transformFunction(model, previousSegment, paragraph, context);
|
|
175
|
+
if (result_1) {
|
|
176
|
+
if (typeof result_1 !== 'boolean') {
|
|
177
|
+
formatOptions.getChangeData = function () { return result_1; };
|
|
178
|
+
}
|
|
179
|
+
featureApplied = feature;
|
|
180
|
+
return "break";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
try {
|
|
185
|
+
for (var features_1 = (0, tslib_1.__values)(features), features_1_1 = features_1.next(); !features_1_1.done; features_1_1 = features_1.next()) {
|
|
186
|
+
var feature = features_1_1.value;
|
|
187
|
+
var state_1 = _loop_1(feature);
|
|
188
|
+
if (state_1 === "break")
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
193
|
+
finally {
|
|
194
|
+
try {
|
|
195
|
+
if (features_1_1 && !features_1_1.done && (_a = features_1.return)) _a.call(features_1);
|
|
196
|
+
}
|
|
197
|
+
finally { if (e_1) throw e_1.error; }
|
|
198
|
+
}
|
|
199
|
+
if (featureApplied) {
|
|
200
|
+
formatOptions.changeSource = featureApplied.changeSource;
|
|
201
|
+
formatOptions.apiName = featureApplied.apiName;
|
|
202
|
+
}
|
|
203
|
+
return !!featureApplied;
|
|
204
|
+
}, formatOptions);
|
|
205
|
+
return formatOptions;
|
|
206
|
+
};
|
|
144
207
|
AutoFormatPlugin.prototype.handleEditorInputEvent = function (editor, event) {
|
|
145
|
-
var _this = this;
|
|
146
208
|
var rawEvent = event.rawEvent;
|
|
147
209
|
var selection = editor.getDOMSelection();
|
|
148
210
|
if (rawEvent.inputType === 'insertText' &&
|
|
@@ -151,53 +213,12 @@ var AutoFormatPlugin = /** @class */ (function () {
|
|
|
151
213
|
selection.range.collapsed) {
|
|
152
214
|
switch (rawEvent.data) {
|
|
153
215
|
case ' ':
|
|
154
|
-
|
|
155
|
-
changeSource: '',
|
|
156
|
-
apiName: '',
|
|
157
|
-
getChangeData: undefined,
|
|
158
|
-
};
|
|
159
|
-
(0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (model, previousSegment, paragraph, _markerFormat, context) {
|
|
160
|
-
var e_1, _a;
|
|
161
|
-
var formatApplied = undefined;
|
|
162
|
-
var _loop_1 = function (feature) {
|
|
163
|
-
if (feature.enabled) {
|
|
164
|
-
var result_1 = feature.transformFunction(model, previousSegment, paragraph, context);
|
|
165
|
-
if (result_1) {
|
|
166
|
-
if (typeof result_1 !== 'boolean') {
|
|
167
|
-
formatOptions_1.getChangeData = function () { return result_1; };
|
|
168
|
-
}
|
|
169
|
-
formatApplied = feature.autoFormat;
|
|
170
|
-
return "break";
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
try {
|
|
175
|
-
for (var _b = (0, tslib_1.__values)(_this.features), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
176
|
-
var feature = _c.value;
|
|
177
|
-
var state_1 = _loop_1(feature);
|
|
178
|
-
if (state_1 === "break")
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
183
|
-
finally {
|
|
184
|
-
try {
|
|
185
|
-
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
186
|
-
}
|
|
187
|
-
finally { if (e_1) throw e_1.error; }
|
|
188
|
-
}
|
|
189
|
-
if (formatApplied) {
|
|
190
|
-
formatOptions_1.changeSource = getChangeSource(formatApplied);
|
|
191
|
-
formatOptions_1.apiName = getApiName(formatApplied);
|
|
192
|
-
}
|
|
193
|
-
return !!formatApplied;
|
|
194
|
-
}, formatOptions_1);
|
|
216
|
+
this.handleKeyboardEvents(editor, this.features);
|
|
195
217
|
break;
|
|
196
218
|
}
|
|
197
219
|
}
|
|
198
220
|
};
|
|
199
221
|
AutoFormatPlugin.prototype.handleKeyDownEvent = function (editor, event) {
|
|
200
|
-
var _this = this;
|
|
201
222
|
var rawEvent = event.rawEvent;
|
|
202
223
|
if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {
|
|
203
224
|
switch (rawEvent.key) {
|
|
@@ -208,34 +229,21 @@ var AutoFormatPlugin = /** @class */ (function () {
|
|
|
208
229
|
break;
|
|
209
230
|
case 'Tab':
|
|
210
231
|
if (!rawEvent.shiftKey) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
shouldList = (0, keyboardListTrigger_1.keyboardListTrigger)(model, paragraph, context, autoBullet, autoNumbering, removeListMargins);
|
|
216
|
-
context.canUndoByBackspace = shouldList;
|
|
217
|
-
}
|
|
218
|
-
if (shouldList) {
|
|
219
|
-
event.rawEvent.preventDefault();
|
|
220
|
-
}
|
|
221
|
-
return shouldList;
|
|
222
|
-
}, {
|
|
223
|
-
changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoFormat,
|
|
224
|
-
apiName: 'autoToggleList',
|
|
225
|
-
});
|
|
232
|
+
var eventHandled_1 = this.handleKeyboardEvents(editor, this.tabFeatures);
|
|
233
|
+
if (eventHandled_1.apiName == 'autoToggleList') {
|
|
234
|
+
event.rawEvent.preventDefault();
|
|
235
|
+
}
|
|
226
236
|
}
|
|
227
237
|
break;
|
|
228
238
|
case 'Enter':
|
|
229
|
-
this.
|
|
239
|
+
var eventHandled = this.handleKeyboardEvents(editor, this.enterFeatures);
|
|
240
|
+
if (eventHandled.apiName == 'autoHorizontalLine') {
|
|
241
|
+
event.rawEvent.preventDefault();
|
|
242
|
+
}
|
|
230
243
|
break;
|
|
231
244
|
}
|
|
232
245
|
}
|
|
233
246
|
};
|
|
234
|
-
AutoFormatPlugin.prototype.handleEnterKey = function (editor, event) {
|
|
235
|
-
if (this.options.autoHorizontalLine) {
|
|
236
|
-
(0, checkAndInsertHorizontalLine_1.checkAndInsertHorizontalLine)(editor, event);
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
247
|
AutoFormatPlugin.prototype.handleContentChangedEvent = function (editor, event) {
|
|
240
248
|
var _a = this.options, autoLink = _a.autoLink, autoTel = _a.autoTel, autoMailto = _a.autoMailto;
|
|
241
249
|
if (event.source == 'Paste' && (autoLink || autoTel || autoMailto)) {
|
|
@@ -249,16 +257,6 @@ var AutoFormatPlugin = /** @class */ (function () {
|
|
|
249
257
|
return AutoFormatPlugin;
|
|
250
258
|
}());
|
|
251
259
|
exports.AutoFormatPlugin = AutoFormatPlugin;
|
|
252
|
-
var getApiName = function (autoFormat) {
|
|
253
|
-
return autoFormat == 'list' ? 'autoToggleList' : autoFormat == 'hyphen' ? 'autoHyphen' : '';
|
|
254
|
-
};
|
|
255
|
-
var getChangeSource = function (autoFormat) {
|
|
256
|
-
return autoFormat == 'list' || autoFormat == 'hyphen'
|
|
257
|
-
? roosterjs_content_model_dom_1.ChangeSource.AutoFormat
|
|
258
|
-
: autoFormat == 'link'
|
|
259
|
-
? roosterjs_content_model_dom_1.ChangeSource.AutoLink
|
|
260
|
-
: '';
|
|
261
|
-
};
|
|
262
260
|
var createAnchor = function (url, text) {
|
|
263
261
|
var anchor = document.createElement('a');
|
|
264
262
|
anchor.href = url;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutoFormatPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/AutoFormatPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { checkAndInsertHorizontalLine } from './horizontalLine/checkAndInsertHorizontalLine';\nimport { createLink } from './link/createLink';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport { keyboardListTrigger } from './list/keyboardListTrigger';\nimport { transformFraction } from './numbers/transformFraction';\nimport { transformHyphen } from './hyphen/transformHyphen';\nimport { transformOrdinals } from './numbers/transformOrdinals';\nimport { unlink } from './link/unlink';\nimport type { AutoFormatOptions } from './interface/AutoFormatOptions';\nimport type {\n ContentChangedEvent,\n ContentModelText,\n EditorInputEvent,\n EditorPlugin,\n FormatContentModelContext,\n FormatContentModelOptions,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n ReadonlyContentModelDocument,\n ShallowMutableContentModelParagraph,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\ntype AutoFormatFeature = 'list' | 'link' | 'hyphen' | 'fraction' | 'ordinal';\n\n/**\n * @internal\n */\ninterface Feature {\n autoFormat: AutoFormatFeature;\n enabled: boolean;\n transformFunction: (\n model: ReadonlyContentModelDocument,\n previousSegment: ContentModelText,\n paragraph: ShallowMutableContentModelParagraph,\n context: FormatContentModelContext\n ) => boolean | HTMLElement;\n}\n\n/**\n * @internal\n */\nconst DefaultOptions: Partial<AutoFormatOptions> = {\n autoBullet: false,\n autoNumbering: false,\n autoUnlink: false,\n autoLink: false,\n autoHyphen: false,\n autoFraction: false,\n autoOrdinals: false,\n removeListMargins: false,\n autoHorizontalLine: false,\n};\n\n/**\n * Auto Format plugin handles auto formatting, such as transforming * characters into a bullet list.\n * It can be customized with options to enable or disable auto list features.\n */\nexport class AutoFormatPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n /**\n * @param options An optional parameter that takes in an object of type AutoFormatOptions, which includes the following properties:\n * - autoBullet: A boolean that enables or disables automatic bullet list formatting. Defaults to false.\n * - autoNumbering: A boolean that enables or disables automatic numbering formatting. Defaults to false.\n * - removeListMargins: A boolean to remove list margins when it is automatically triggered. Defaults to false.\n * - autoHyphen: A boolean that enables or disables automatic hyphen transformation. Defaults to false.\n * - autoFraction: A boolean that enables or disables automatic fraction transformation. Defaults to false.\n * - autoOrdinals: A boolean that enables or disables automatic ordinal number transformation. Defaults to false.\n * - autoLink: A boolean that enables or disables automatic hyperlink url address creation when pasting or typing content. Defaults to false.\n * - autoUnlink: A boolean that enables or disables automatic hyperlink removal when pressing backspace. Defaults to false.\n * - autoTel: A boolean that enables or disables automatic hyperlink telephone numbers transformation. Defaults to false.\n * - autoMailto: A boolean that enables or disables automatic hyperlink email address transformation. Defaults to false.\n * - autoHorizontalLine: A boolean that enables or disables automatic horizontal line creation. Defaults to false.\n */\n constructor(private options: AutoFormatOptions = DefaultOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'AutoFormat';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (this.editor) {\n switch (event.eventType) {\n case 'input':\n this.handleEditorInputEvent(this.editor, event);\n break;\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'contentChanged':\n this.handleContentChangedEvent(this.editor, event);\n break;\n }\n }\n }\n\n private features: Feature[] = [\n {\n autoFormat: 'list',\n enabled: !!(this.options.autoBullet || this.options.autoNumbering),\n transformFunction: (model, _previousSegment, paragraph, context) =>\n keyboardListTrigger(\n model,\n paragraph,\n context,\n this.options.autoBullet,\n this.options.autoNumbering,\n this.options.removeListMargins\n ),\n },\n {\n autoFormat: 'link',\n enabled: !!(this.options.autoLink || this.options.autoTel || this.options.autoMailto),\n transformFunction: (_model, previousSegment, paragraph, context) => {\n const { autoLink, autoTel, autoMailto } = this.options;\n const linkSegment = promoteLink(previousSegment, paragraph, {\n autoLink,\n autoTel,\n autoMailto,\n });\n\n if (linkSegment) {\n return createAnchor(linkSegment.link?.format.href || '', linkSegment.text);\n }\n return false;\n },\n },\n {\n autoFormat: 'hyphen',\n enabled: !!this.options.autoHyphen,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformHyphen(previousSegment, paragraph, context),\n },\n {\n autoFormat: 'fraction',\n enabled: !!this.options.autoFraction,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformFraction(previousSegment, paragraph, context),\n },\n {\n autoFormat: 'ordinal',\n enabled: !!this.options.autoOrdinals,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformOrdinals(previousSegment, paragraph, context),\n },\n ];\n\n private handleEditorInputEvent(editor: IEditor, event: EditorInputEvent) {\n const rawEvent = event.rawEvent;\n const selection = editor.getDOMSelection();\n if (\n rawEvent.inputType === 'insertText' &&\n selection &&\n selection.type === 'range' &&\n selection.range.collapsed\n ) {\n switch (rawEvent.data) {\n case ' ':\n const formatOptions: FormatContentModelOptions = {\n changeSource: '',\n apiName: '',\n getChangeData: undefined,\n };\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (model, previousSegment, paragraph, _markerFormat, context) => {\n let formatApplied: AutoFormatFeature | undefined = undefined;\n\n for (const feature of this.features) {\n if (feature.enabled) {\n const result = feature.transformFunction(\n model,\n previousSegment,\n paragraph,\n context\n );\n if (result) {\n if (typeof result !== 'boolean') {\n formatOptions.getChangeData = () => result;\n }\n formatApplied = feature.autoFormat;\n break;\n }\n }\n }\n\n if (formatApplied) {\n formatOptions.changeSource = getChangeSource(formatApplied);\n formatOptions.apiName = getApiName(formatApplied);\n }\n\n return !!formatApplied;\n },\n formatOptions\n );\n\n break;\n }\n }\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n if (this.options.autoUnlink) {\n unlink(editor, rawEvent);\n }\n break;\n case 'Tab':\n if (!rawEvent.shiftKey) {\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (model, _previousSegment, paragraph, _markerFormat, context) => {\n const {\n autoBullet,\n autoNumbering,\n removeListMargins,\n } = this.options;\n let shouldList = false;\n if (autoBullet || autoNumbering) {\n shouldList = keyboardListTrigger(\n model,\n paragraph,\n context,\n autoBullet,\n autoNumbering,\n removeListMargins\n );\n context.canUndoByBackspace = shouldList;\n }\n if (shouldList) {\n event.rawEvent.preventDefault();\n }\n return shouldList;\n },\n {\n changeSource: ChangeSource.AutoFormat,\n apiName: 'autoToggleList',\n }\n );\n }\n break;\n case 'Enter':\n this.handleEnterKey(editor, event);\n break;\n }\n }\n }\n\n private handleEnterKey(editor: IEditor, event: KeyDownEvent) {\n if (this.options.autoHorizontalLine) {\n checkAndInsertHorizontalLine(editor, event);\n }\n }\n\n private handleContentChangedEvent(editor: IEditor, event: ContentChangedEvent) {\n const { autoLink, autoTel, autoMailto } = this.options;\n if (event.source == 'Paste' && (autoLink || autoTel || autoMailto)) {\n createLink(editor, {\n autoLink,\n autoTel,\n autoMailto,\n });\n }\n }\n}\n\nconst getApiName = (autoFormat: AutoFormatFeature) => {\n return autoFormat == 'list' ? 'autoToggleList' : autoFormat == 'hyphen' ? 'autoHyphen' : '';\n};\n\nconst getChangeSource = (autoFormat: AutoFormatFeature) => {\n return autoFormat == 'list' || autoFormat == 'hyphen'\n ? ChangeSource.AutoFormat\n : autoFormat == 'link'\n ? ChangeSource.AutoLink\n : '';\n};\n\nconst createAnchor = (url: string, text: string) => {\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.textContent = text;\n return anchor;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"AutoFormatPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/AutoFormatPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { checkAndInsertHorizontalLine } from './horizontalLine/checkAndInsertHorizontalLine';\nimport { createLink } from './link/createLink';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport { keyboardListTrigger } from './list/keyboardListTrigger';\nimport { transformFraction } from './numbers/transformFraction';\nimport { transformHyphen } from './hyphen/transformHyphen';\nimport { transformOrdinals } from './numbers/transformOrdinals';\nimport { unlink } from './link/unlink';\nimport type { AutoFormatOptions } from './interface/AutoFormatOptions';\nimport type {\n ContentChangedEvent,\n ContentModelText,\n EditorInputEvent,\n EditorPlugin,\n FormatContentModelContext,\n FormatContentModelOptions,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n ReadonlyContentModelDocument,\n ShallowMutableContentModelParagraph,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\ninterface Feature {\n enabled: boolean;\n transformFunction: (\n model: ReadonlyContentModelDocument,\n previousSegment: ContentModelText,\n paragraph: ShallowMutableContentModelParagraph,\n context: FormatContentModelContext\n ) => boolean | HTMLElement;\n changeSource: string;\n apiName: string;\n}\n\n/**\n * @internal\n */\nconst DefaultOptions: Partial<AutoFormatOptions> = {\n autoBullet: false,\n autoNumbering: false,\n autoUnlink: false,\n autoLink: false,\n autoHyphen: false,\n autoFraction: false,\n autoOrdinals: false,\n removeListMargins: false,\n autoHorizontalLine: false,\n};\n\n/**\n * Auto Format plugin handles auto formatting, such as transforming * characters into a bullet list.\n * It can be customized with options to enable or disable auto list features.\n */\nexport class AutoFormatPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n /**\n * @param options An optional parameter that takes in an object of type AutoFormatOptions, which includes the following properties:\n * - autoBullet: A boolean that enables or disables automatic bullet list formatting. Defaults to false.\n * - autoNumbering: A boolean that enables or disables automatic numbering formatting. Defaults to false.\n * - removeListMargins: A boolean to remove list margins when it is automatically triggered. Defaults to false.\n * - autoHyphen: A boolean that enables or disables automatic hyphen transformation. Defaults to false.\n * - autoFraction: A boolean that enables or disables automatic fraction transformation. Defaults to false.\n * - autoOrdinals: A boolean that enables or disables automatic ordinal number transformation. Defaults to false.\n * - autoLink: A boolean that enables or disables automatic hyperlink url address creation when pasting or typing content. Defaults to false.\n * - autoUnlink: A boolean that enables or disables automatic hyperlink removal when pressing backspace. Defaults to false.\n * - autoTel: A boolean that enables or disables automatic hyperlink telephone numbers transformation. Defaults to false.\n * - autoMailto: A boolean that enables or disables automatic hyperlink email address transformation. Defaults to false.\n * - autoHorizontalLine: A boolean that enables or disables automatic horizontal line creation. Defaults to false.\n */\n constructor(private options: AutoFormatOptions = DefaultOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'AutoFormat';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (this.editor) {\n switch (event.eventType) {\n case 'input':\n this.handleEditorInputEvent(this.editor, event);\n break;\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'contentChanged':\n this.handleContentChangedEvent(this.editor, event);\n break;\n }\n }\n }\n\n private autoLink: Feature = {\n enabled: !!(this.options.autoLink || this.options.autoTel || this.options.autoMailto),\n transformFunction: (_model, previousSegment, paragraph, context) => {\n const { autoLink, autoTel, autoMailto } = this.options;\n const linkSegment = promoteLink(previousSegment, paragraph, {\n autoLink,\n autoTel,\n autoMailto,\n });\n\n if (linkSegment) {\n return createAnchor(linkSegment.link?.format.href || '', linkSegment.text);\n }\n return false;\n },\n apiName: 'autoLink',\n changeSource: ChangeSource.AutoLink,\n };\n\n private tabFeatures: Feature[] = [\n {\n enabled: !!(this.options.autoBullet || this.options.autoNumbering),\n transformFunction: (model, _previousSegment, paragraph, context) =>\n keyboardListTrigger(\n model,\n paragraph,\n context,\n this.options.autoBullet,\n this.options.autoNumbering,\n this.options.removeListMargins\n ),\n apiName: 'autoToggleList',\n changeSource: ChangeSource.AutoFormat,\n },\n this.autoLink,\n ];\n\n private features: Feature[] = [\n ...this.tabFeatures,\n {\n enabled: !!this.options.autoHyphen,\n apiName: 'autoHyphen',\n changeSource: ChangeSource.Format,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformHyphen(previousSegment, paragraph, context),\n },\n {\n enabled: !!this.options.autoFraction,\n apiName: 'autoFraction',\n changeSource: ChangeSource.Format,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformFraction(previousSegment, paragraph, context),\n },\n {\n enabled: !!this.options.autoOrdinals,\n apiName: 'autoOrdinal',\n changeSource: ChangeSource.Format,\n transformFunction: (_model, previousSegment, paragraph, context) =>\n transformOrdinals(previousSegment, paragraph, context),\n },\n ];\n\n private enterFeatures: Feature[] = [\n {\n enabled: !!this.options.autoHorizontalLine,\n transformFunction: (model, _previousSegment, paragraph, context) =>\n checkAndInsertHorizontalLine(model, paragraph, context),\n apiName: 'autoHorizontalLine',\n changeSource: ChangeSource.AutoFormat,\n },\n this.autoLink,\n ];\n\n private handleKeyboardEvents(editor: IEditor, features: Feature[]): FormatContentModelOptions {\n const formatOptions: FormatContentModelOptions = {\n changeSource: '',\n apiName: '',\n getChangeData: undefined,\n };\n\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (model, previousSegment, paragraph, _markerFormat, context) => {\n let featureApplied: Feature | undefined = undefined;\n for (const feature of features) {\n if (feature.enabled) {\n const result = feature.transformFunction(\n model,\n previousSegment,\n paragraph,\n context\n );\n if (result) {\n if (typeof result !== 'boolean') {\n formatOptions.getChangeData = () => result;\n }\n featureApplied = feature;\n break;\n }\n }\n }\n\n if (featureApplied) {\n formatOptions.changeSource = featureApplied.changeSource;\n formatOptions.apiName = featureApplied.apiName;\n }\n\n return !!featureApplied;\n },\n formatOptions\n );\n return formatOptions;\n }\n\n private handleEditorInputEvent(editor: IEditor, event: EditorInputEvent) {\n const rawEvent = event.rawEvent;\n const selection = editor.getDOMSelection();\n if (\n rawEvent.inputType === 'insertText' &&\n selection &&\n selection.type === 'range' &&\n selection.range.collapsed\n ) {\n switch (rawEvent.data) {\n case ' ':\n this.handleKeyboardEvents(editor, this.features);\n break;\n }\n }\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n if (this.options.autoUnlink) {\n unlink(editor, rawEvent);\n }\n break;\n case 'Tab':\n if (!rawEvent.shiftKey) {\n const eventHandled = this.handleKeyboardEvents(editor, this.tabFeatures);\n if (eventHandled.apiName == 'autoToggleList') {\n event.rawEvent.preventDefault();\n }\n }\n break;\n case 'Enter':\n const eventHandled = this.handleKeyboardEvents(editor, this.enterFeatures);\n if (eventHandled.apiName == 'autoHorizontalLine') {\n event.rawEvent.preventDefault();\n }\n break;\n }\n }\n }\n\n private handleContentChangedEvent(editor: IEditor, event: ContentChangedEvent) {\n const { autoLink, autoTel, autoMailto } = this.options;\n if (event.source == 'Paste' && (autoLink || autoTel || autoMailto)) {\n createLink(editor, {\n autoLink,\n autoTel,\n autoMailto,\n });\n }\n }\n}\n\nconst createAnchor = (url: string, text: string) => {\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.textContent = text;\n return anchor;\n};\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FormatContentModelContext,
|
|
1
|
+
import type { FormatContentModelContext, ReadonlyContentModelDocument, ShallowMutableContentModelParagraph } from 'roosterjs-content-model-types';
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
@@ -11,7 +11,7 @@ export declare type HorizontalLineTriggerCharacter = '-' | '=' | '_' | '*' | '~'
|
|
|
11
11
|
* @param model the model to insert horizontal line into
|
|
12
12
|
* @param context the formatting context
|
|
13
13
|
*/
|
|
14
|
-
export declare function insertHorizontalLineIntoModel(model:
|
|
14
|
+
export declare function insertHorizontalLineIntoModel(model: ReadonlyContentModelDocument, context: FormatContentModelContext, triggerChar: HorizontalLineTriggerCharacter): void;
|
|
15
15
|
/**
|
|
16
16
|
* @internal
|
|
17
17
|
*
|
|
@@ -21,4 +21,4 @@ export declare function insertHorizontalLineIntoModel(model: ShallowMutableConte
|
|
|
21
21
|
* @param event The keydown event
|
|
22
22
|
* @returns True if horizontal line is inserted, otherwise false
|
|
23
23
|
*/
|
|
24
|
-
export declare
|
|
24
|
+
export declare const checkAndInsertHorizontalLine: (model: ReadonlyContentModelDocument, paragraph: ShallowMutableContentModelParagraph, context: FormatContentModelContext) => boolean;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.checkAndInsertHorizontalLine = exports.insertHorizontalLineIntoModel = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
|
-
var roosterjs_content_model_api_1 = require("roosterjs-content-model-api");
|
|
6
5
|
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
7
6
|
var HorizontalLineTriggerCharacters = [
|
|
8
7
|
'-',
|
|
@@ -66,27 +65,21 @@ exports.insertHorizontalLineIntoModel = insertHorizontalLineIntoModel;
|
|
|
66
65
|
* @param event The keydown event
|
|
67
66
|
* @returns True if horizontal line is inserted, otherwise false
|
|
68
67
|
*/
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
var checkAndInsertHorizontalLine = function (model, paragraph, context) {
|
|
69
|
+
var allText = paragraph.segments.reduce(function (acc, segment) { return (segment.segmentType === 'Text' ? acc + segment.text : acc); }, '');
|
|
70
|
+
// At least 3 characters are needed to trigger horizontal line
|
|
71
|
+
if (allText.length < 3) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return HorizontalLineTriggerCharacters.some(function (triggerCharacter) {
|
|
75
|
+
var shouldFormat = allText.split('').every(function (char) { return char === triggerCharacter; });
|
|
76
|
+
if (shouldFormat) {
|
|
77
|
+
paragraph.segments = paragraph.segments.filter(function (s) { return s.segmentType != 'Text'; });
|
|
78
|
+
insertHorizontalLineIntoModel(model, context, triggerCharacter);
|
|
79
|
+
context.canUndoByBackspace = true;
|
|
75
80
|
}
|
|
76
|
-
return
|
|
77
|
-
var shouldFormat = allText.split('').every(function (char) { return char === triggerCharacter; });
|
|
78
|
-
if (shouldFormat) {
|
|
79
|
-
para.segments = para.segments.filter(function (s) { return s.segmentType != 'Text'; });
|
|
80
|
-
insertHorizontalLineIntoModel(model, context, triggerCharacter);
|
|
81
|
-
event.rawEvent.preventDefault();
|
|
82
|
-
context.canUndoByBackspace = true;
|
|
83
|
-
}
|
|
84
|
-
return shouldFormat;
|
|
85
|
-
});
|
|
86
|
-
}, {
|
|
87
|
-
changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoFormat,
|
|
88
|
-
apiName: 'autoHorizontalLine',
|
|
81
|
+
return shouldFormat;
|
|
89
82
|
});
|
|
90
|
-
}
|
|
83
|
+
};
|
|
91
84
|
exports.checkAndInsertHorizontalLine = checkAndInsertHorizontalLine;
|
|
92
85
|
//# sourceMappingURL=checkAndInsertHorizontalLine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkAndInsertHorizontalLine.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/horizontalLine/checkAndInsertHorizontalLine.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"checkAndInsertHorizontalLine.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/horizontalLine/checkAndInsertHorizontalLine.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ContentModelDividerFormat,\n FormatContentModelContext,\n ReadonlyContentModelDocument,\n ShallowMutableContentModelParagraph,\n} from 'roosterjs-content-model-types';\nimport {\n addBlock,\n createContentModelDocument,\n createDivider,\n mergeModel,\n} from 'roosterjs-content-model-dom';\n\n/**\n * @internal\n */\nexport type HorizontalLineTriggerCharacter = '-' | '=' | '_' | '*' | '~' | '#';\nconst HorizontalLineTriggerCharacters: HorizontalLineTriggerCharacter[] = [\n '-',\n '=',\n '_',\n '*',\n '~',\n '#',\n];\n\nconst commonStyles: ContentModelDividerFormat = {\n width: '98%',\n display: 'inline-block',\n};\n\nconst HorizontalLineStyles: Map<\n HorizontalLineTriggerCharacter,\n ContentModelDividerFormat\n> = new Map([\n [\n '-',\n {\n borderTop: '1px none',\n borderRight: '1px none',\n borderBottom: '1px solid',\n borderLeft: '1px none',\n ...commonStyles,\n },\n ],\n [\n '=',\n {\n borderTop: '3pt double',\n borderRight: '3pt none',\n borderBottom: '3pt none',\n borderLeft: '3pt none',\n ...commonStyles,\n },\n ],\n [\n '_',\n {\n borderTop: '1px solid',\n borderRight: '1px none',\n borderBottom: '1px solid',\n borderLeft: '1px none',\n ...commonStyles,\n },\n ],\n [\n '*',\n {\n borderTop: '1px none',\n borderRight: '1px none',\n borderBottom: '3px dotted',\n borderLeft: '1px none',\n ...commonStyles,\n },\n ],\n [\n '~',\n {\n borderTop: '1px none',\n borderRight: '1px none',\n borderBottom: '1px solid',\n borderLeft: '1px none',\n ...commonStyles,\n },\n ],\n [\n '#',\n {\n borderTop: '3pt double',\n borderRight: '3pt none',\n borderBottom: '3pt double',\n borderLeft: '3pt none',\n ...commonStyles,\n },\n ],\n]);\n\n/**\n * @internal exported only for unit test\n *\n * Create a horizontal line and insert it into the model\n *\n * @param model the model to insert horizontal line into\n * @param context the formatting context\n */\nexport function insertHorizontalLineIntoModel(\n model: ReadonlyContentModelDocument,\n context: FormatContentModelContext,\n triggerChar: HorizontalLineTriggerCharacter\n) {\n const hr = createDivider('hr', HorizontalLineStyles.get(triggerChar));\n const doc = createContentModelDocument();\n addBlock(doc, hr);\n mergeModel(model, doc, context);\n}\n\n/**\n * @internal\n *\n * Check if the current line should be formatted as horizontal line, and insert horizontal line if needed\n *\n * @param editor The editor to check and insert horizontal line\n * @param event The keydown event\n * @returns True if horizontal line is inserted, otherwise false\n */\nexport const checkAndInsertHorizontalLine = (\n model: ReadonlyContentModelDocument,\n paragraph: ShallowMutableContentModelParagraph,\n context: FormatContentModelContext\n) => {\n const allText = paragraph.segments.reduce(\n (acc, segment) => (segment.segmentType === 'Text' ? acc + segment.text : acc),\n ''\n );\n // At least 3 characters are needed to trigger horizontal line\n if (allText.length < 3) {\n return false;\n }\n\n return HorizontalLineTriggerCharacters.some(triggerCharacter => {\n const shouldFormat = allText.split('').every(char => char === triggerCharacter);\n if (shouldFormat) {\n paragraph.segments = paragraph.segments.filter(s => s.segmentType != 'Text');\n insertHorizontalLineIntoModel(model, context, triggerCharacter);\n context.canUndoByBackspace = true;\n }\n return shouldFormat;\n });\n};\n"]}
|
package/lib/edit/EditPlugin.d.ts
CHANGED
|
@@ -12,6 +12,13 @@ export declare type EditOptions = {
|
|
|
12
12
|
* @default true
|
|
13
13
|
*/
|
|
14
14
|
handleExpandedSelectionOnDelete?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Callback function to determine whether the Rooster should handle the Enter key press.
|
|
17
|
+
* If the function returns true, the Rooster will handle the Enter key press instead of the browser.
|
|
18
|
+
* @param editor - The editor instance.
|
|
19
|
+
* @returns A boolean
|
|
20
|
+
*/
|
|
21
|
+
shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;
|
|
15
22
|
};
|
|
16
23
|
/**
|
|
17
24
|
* Edit plugins helps editor to do editing operation on top of content model.
|
|
@@ -32,6 +39,8 @@ export declare class EditPlugin implements EditorPlugin {
|
|
|
32
39
|
* handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.
|
|
33
40
|
*/
|
|
34
41
|
constructor(options?: EditOptions);
|
|
42
|
+
private createNormalEnterChecker;
|
|
43
|
+
private getHandleNormalEnter;
|
|
35
44
|
/**
|
|
36
45
|
* Get name of this plugin
|
|
37
46
|
*/
|
package/lib/edit/EditPlugin.js
CHANGED
|
@@ -38,8 +38,24 @@ var EditPlugin = /** @class */ (function () {
|
|
|
38
38
|
this.disposer = null;
|
|
39
39
|
this.shouldHandleNextInputEvent = false;
|
|
40
40
|
this.selectionAfterDelete = null;
|
|
41
|
-
this.handleNormalEnter = false;
|
|
41
|
+
this.handleNormalEnter = function (editor) { return false; };
|
|
42
42
|
}
|
|
43
|
+
EditPlugin.prototype.createNormalEnterChecker = function (result) {
|
|
44
|
+
return result ? function () { return true; } : function () { return false; };
|
|
45
|
+
};
|
|
46
|
+
EditPlugin.prototype.getHandleNormalEnter = function (editor) {
|
|
47
|
+
switch (typeof this.options.shouldHandleEnterKey) {
|
|
48
|
+
case 'function':
|
|
49
|
+
return this.options.shouldHandleEnterKey;
|
|
50
|
+
break;
|
|
51
|
+
case 'boolean':
|
|
52
|
+
return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
return this.createNormalEnterChecker(editor.isExperimentalFeatureEnabled('HandleEnterKey'));
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
43
59
|
/**
|
|
44
60
|
* Get name of this plugin
|
|
45
61
|
*/
|
|
@@ -55,7 +71,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
55
71
|
EditPlugin.prototype.initialize = function (editor) {
|
|
56
72
|
var _this = this;
|
|
57
73
|
this.editor = editor;
|
|
58
|
-
this.handleNormalEnter = this.editor
|
|
74
|
+
this.handleNormalEnter = this.getHandleNormalEnter(editor);
|
|
59
75
|
if (editor.getEnvironment().isAndroid) {
|
|
60
76
|
this.disposer = this.editor.attachDomEvent({
|
|
61
77
|
beforeinput: {
|
|
@@ -162,7 +178,7 @@ var EditPlugin = /** @class */ (function () {
|
|
|
162
178
|
if (!hasCtrlOrMetaKey &&
|
|
163
179
|
!event.rawEvent.isComposing &&
|
|
164
180
|
event.rawEvent.keyCode !== DEAD_KEY) {
|
|
165
|
-
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.handleNormalEnter);
|
|
181
|
+
(0, keyboardEnter_1.keyboardEnter)(editor, rawEvent, this.handleNormalEnter(editor));
|
|
166
182
|
}
|
|
167
183
|
break;
|
|
168
184
|
default:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts"],"names":[],"mappings":";;;AAAA,mDAAkD;AAClD,iDAAgD;AAChD,iDAAgD;AAChD,6CAA4C;AAC5C,2EAA8D;AAyB9D,IAAM,aAAa,GAAG,CAAC,CAAC;AACxB,IAAM,UAAU,GAAG,EAAE,CAAC;AACtB;;;;;GAKG;AACH,IAAM,QAAQ,GAAG,GAAG,CAAC;AAErB,IAAM,cAAc,GAAyB;IACzC,YAAY,EAAE,IAAI;IAClB,+BAA+B,EAAE,IAAI;CACxC,CAAC;AAEF;;;;;;GAMG;AACH;IAOI;;;OAGG;IACH,oBAAoB,OAAqC;QAArC,wBAAA,EAAA,wBAAqC;QAArC,YAAO,GAAP,OAAO,CAA8B;QAVjD,WAAM,GAAmB,IAAI,CAAC;QAC9B,aAAQ,GAAwB,IAAI,CAAC;QACrC,+BAA0B,GAAG,KAAK,CAAC;QACnC,yBAAoB,GAAwB,IAAI,CAAC;QACjD,sBAAiB,GAAG,KAAK,CAAC;IAM0B,CAAC;IAE7D;;OAEG;IACH,4BAAO,GAAP;QACI,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACH,+BAAU,GAAV,UAAW,MAAe;QAA1B,iBAWC;QAVG,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC,4BAA4B,CAAC,gBAAgB,CAAC,CAAC;QAEpF,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE;YACnC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;gBACvC,WAAW,EAAE;oBACT,cAAc,EAAE,UAAA,CAAC,IAAI,OAAA,KAAI,CAAC,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAtC,CAAsC;iBAC9D;aACJ,CAAC,CAAC;SACN;IACL,CAAC;IAED;;;;OAIG;IACH,4BAAO,GAAP;;QACI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAA,IAAI,CAAC,QAAQ,+CAAb,IAAI,CAAa,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACzB,CAAC;IAED;;;;;OAKG;IACH,kCAAa,GAAb,UAAc,KAAkB;QAC5B,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,QAAQ,KAAK,CAAC,SAAS,EAAE;gBACrB,KAAK,SAAS;oBACV,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;oBAC5C,MAAM;gBACV,KAAK,OAAO;oBACR,IAAI,IAAI,CAAC,oBAAoB,EAAE;wBAC3B,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;wBACvD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;qBACpC;oBACD,MAAM;aACb;SACJ;IACL,CAAC;IAED;;;;;;;OAOG;IACH,+CAA0B,GAA1B,UAA2B,KAAkB;QACzC,IACI,IAAI,CAAC,MAAM;YACX,IAAI,CAAC,OAAO,CAAC,YAAY;YACzB,KAAK,CAAC,SAAS,IAAI,SAAS;YAC5B,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,KAAK;YAC3B,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAC1B;YACE,IAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAChD,IAAM,cAAc,GAChB,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,IAAI,SAAS,CAAC,KAAK,CAAC,SAAS;gBACnD,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,cAAc;gBAChC,CAAC,CAAC,IAAI,CAAC;YACf,IAAM,KAAK,GAAG,cAAc;gBACxB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,0BAA0B,CAAC,cAAc,EAAE,OAAO,CAAC;gBAChF,CAAC,CAAC,IAAI,CAAC;YACX,IAAM,WAAW,GAAG,KAAK,IAAI,IAAA,6CAAe,EAAC,KAAK,CAAC,CAAC;YAEpD,IAAI,WAAW,EAAE;gBACb,IAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACpD,IAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAExD,IAAI,OAAO,QAAQ,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE;oBAClE,qHAAqH;oBACrH,8FAA8F;oBAC9F,OAAO,IAAI,CAAC;iBACf;aACJ;SACJ;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,uCAAkB,GAA1B,UAA2B,MAAe,EAAE,KAAmB;QAC3D,IAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAChC,IAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;QAE9D,IAAI,CAAC,QAAQ,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE;YAC3D,QAAQ,QAAQ,CAAC,GAAG,EAAE;gBAClB,KAAK,WAAW;oBACZ,8CAA8C;oBAC9C,qIAAqI;oBACrI,IAAA,+BAAc,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;oBAC/E,MAAM;gBAEV,KAAK,QAAQ;oBACT,8CAA8C;oBAC9C,qIAAqI;oBACrI,2FAA2F;oBAC3F,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE;wBAC1B,IAAA,+BAAc,EACV,MAAM,EACN,QAAQ,EACR,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAC/C,CAAC;qBACL;oBACD,MAAM;gBAEV,KAAK,KAAK;oBACN,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,gBAAgB,EAAE;wBAChD,IAAA,yBAAW,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;qBACjC;oBACD,MAAM;gBACV,KAAK,cAAc;oBACf,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE;wBACnC,IAAI,CAAC,0BAA0B,GAAG,IAAI,CAAC;qBAC1C;oBACD,MAAM;gBAEV,KAAK,OAAO;oBACR,IACI,CAAC,gBAAgB;wBACjB,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW;wBAC3B,KAAK,CAAC,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACrC;wBACE,IAAA,6BAAa,EAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;qBAC3D;oBACD,MAAM;gBAEV;oBACI,IAAA,6BAAa,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAChC,MAAM;aACb;SACJ;IACL,CAAC;IAEO,2CAAsB,GAA9B,UAA+B,MAAe,EAAE,QAAe;QAC3D,gFAAgF;QAChF,uGAAuG;QACvG,IACI,CAAC,IAAI,CAAC,0BAA0B;YAChC,CAAC,CAAC,QAAQ,YAAY,UAAU,CAAC;YACjC,QAAQ,CAAC,gBAAgB,EAC3B;YACE,OAAO;SACV;QACD,IAAI,CAAC,0BAA0B,GAAG,KAAK,CAAC;QAExC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,QAAQ,QAAQ,CAAC,SAAS,EAAE;YACxB,KAAK,uBAAuB;gBACxB,OAAO,GAAG,IAAA,+BAAc,EACpB,MAAM,EACN,IAAI,aAAa,CAAC,SAAS,EAAE;oBACzB,GAAG,EAAE,WAAW;oBAChB,OAAO,EAAE,aAAa;oBACtB,KAAK,EAAE,aAAa;iBACvB,CAAC,EACF,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAC/C,CAAC;gBACF,MAAM;YACV,KAAK,sBAAsB;gBACvB,OAAO,GAAG,IAAA,+BAAc,EACpB,MAAM,EACN,IAAI,aAAa,CAAC,SAAS,EAAE;oBACzB,GAAG,EAAE,QAAQ;oBACb,OAAO,EAAE,UAAU;oBACnB,KAAK,EAAE,UAAU;iBACpB,CAAC,EACF,IAAI,CAAC,OAAO,CAAC,+BAA+B,CAC/C,CAAC;gBACF,MAAM;SACb;QAED,IAAI,OAAO,EAAE;YACT,QAAQ,CAAC,cAAc,EAAE,CAAC;YAE1B,sEAAsE;YACtE,oDAAoD;YACpD,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;SACxD;IACL,CAAC;IACL,iBAAC;AAAD,CAAC,AApND,IAoNC;AApNY,gCAAU","sourcesContent":["import { keyboardDelete } from './keyboardDelete';\nimport { keyboardEnter } from './keyboardEnter';\nimport { keyboardInput } from './keyboardInput';\nimport { keyboardTab } from './keyboardTab';\nimport { parseTableCells } from 'roosterjs-content-model-dom';\nimport type {\n DOMSelection,\n EditorPlugin,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Options to customize the keyboard handling behavior of Edit plugin\n */\nexport type EditOptions = {\n /**\n * Whether to handle Tab key in keyboard. @default true\n */\n handleTabKey?: boolean;\n\n /**\n * Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.\n * @default true\n */\n handleExpandedSelectionOnDelete?: boolean;\n};\n\nconst BACKSPACE_KEY = 8;\nconst DELETE_KEY = 46;\n/**\n * According to https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n * 229 can be sent in variants generated when Long press (iOS) or using IM.\n *\n * Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229\n */\nconst DEAD_KEY = 229;\n\nconst DefaultOptions: Partial<EditOptions> = {\n handleTabKey: true,\n handleExpandedSelectionOnDelete: true,\n};\n\n/**\n * Edit plugins helps editor to do editing operation on top of content model.\n * This includes:\n * 1. Delete Key\n * 2. Backspace Key\n * 3. Tab Key\n */\nexport class EditPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n private disposer: (() => void) | null = null;\n private shouldHandleNextInputEvent = false;\n private selectionAfterDelete: DOMSelection | null = null;\n private handleNormalEnter = false;\n\n /**\n * @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:\n * handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.\n */\n constructor(private options: EditOptions = DefaultOptions) {}\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Edit';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n this.handleNormalEnter = this.editor.isExperimentalFeatureEnabled('HandleEnterKey');\n\n if (editor.getEnvironment().isAndroid) {\n this.disposer = this.editor.attachDomEvent({\n beforeinput: {\n beforeDispatch: e => this.handleBeforeInputEvent(editor, e),\n },\n });\n }\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n this.disposer?.();\n this.disposer = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (this.editor) {\n switch (event.eventType) {\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'keyUp':\n if (this.selectionAfterDelete) {\n this.editor.setDOMSelection(this.selectionAfterDelete);\n this.selectionAfterDelete = null;\n }\n break;\n }\n }\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * Handle an event exclusively means other plugin will not receive this event in\n * onPluginEvent method.\n * If two plugins will return true in willHandleEventExclusively() for the same event,\n * the final result depends on the order of the plugins are added into editor\n * @param event The event to check:\n */\n willHandleEventExclusively(event: PluginEvent) {\n if (\n this.editor &&\n this.options.handleTabKey &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == 'Tab' &&\n !event.rawEvent.shiftKey\n ) {\n const selection = this.editor.getDOMSelection();\n const startContainer =\n selection?.type == 'range' && selection.range.collapsed\n ? selection.range.startContainer\n : null;\n const table = startContainer\n ? this.editor.getDOMHelper().findClosestElementAncestor(startContainer, 'table')\n : null;\n const parsedTable = table && parseTableCells(table);\n\n if (parsedTable) {\n const lastRow = parsedTable[parsedTable.length - 1];\n const lastCell = lastRow && lastRow[lastRow.length - 1];\n\n if (typeof lastCell == 'object' && lastCell.contains(startContainer)) {\n // When TAB in the last cell of a table, we will generate new table row, so prevent other plugins handling this event\n // e.g. SelectionPlugin will move the focus out of table, which is conflict with this behavior\n return true;\n }\n }\n }\n\n return false;\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n const hasCtrlOrMetaKey = rawEvent.ctrlKey || rawEvent.metaKey;\n\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n keyboardDelete(editor, rawEvent, this.options.handleExpandedSelectionOnDelete);\n break;\n\n case 'Delete':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(\n editor,\n rawEvent,\n this.options.handleExpandedSelectionOnDelete\n );\n }\n break;\n\n case 'Tab':\n if (this.options.handleTabKey && !hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent);\n }\n break;\n case 'Unidentified':\n if (editor.getEnvironment().isAndroid) {\n this.shouldHandleNextInputEvent = true;\n }\n break;\n\n case 'Enter':\n if (\n !hasCtrlOrMetaKey &&\n !event.rawEvent.isComposing &&\n event.rawEvent.keyCode !== DEAD_KEY\n ) {\n keyboardEnter(editor, rawEvent, this.handleNormalEnter);\n }\n break;\n\n default:\n keyboardInput(editor, rawEvent);\n break;\n }\n }\n }\n\n private handleBeforeInputEvent(editor: IEditor, rawEvent: Event) {\n // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key\n // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic\n if (\n !this.shouldHandleNextInputEvent ||\n !(rawEvent instanceof InputEvent) ||\n rawEvent.defaultPrevented\n ) {\n return;\n }\n this.shouldHandleNextInputEvent = false;\n\n let handled = false;\n switch (rawEvent.inputType) {\n case 'deleteContentBackward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Backspace',\n keyCode: BACKSPACE_KEY,\n which: BACKSPACE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n break;\n case 'deleteContentForward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Delete',\n keyCode: DELETE_KEY,\n which: DELETE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n break;\n }\n\n if (handled) {\n rawEvent.preventDefault();\n\n // Restore the selection on keyup event to avoid the cursor jump issue\n // See: https://issues.chromium.org/issues/330596261\n this.selectionAfterDelete = editor.getDOMSelection();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"EditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { keyboardDelete } from './keyboardDelete';\nimport { keyboardEnter } from './keyboardEnter';\nimport { keyboardInput } from './keyboardInput';\nimport { keyboardTab } from './keyboardTab';\nimport { parseTableCells } from 'roosterjs-content-model-dom';\nimport type {\n DOMSelection,\n EditorPlugin,\n IEditor,\n KeyDownEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\n/**\n * Options to customize the keyboard handling behavior of Edit plugin\n */\nexport type EditOptions = {\n /**\n * Whether to handle Tab key in keyboard. @default true\n */\n handleTabKey?: boolean;\n\n /**\n * Whether expanded selection within a text node should be handled by CM when pressing Backspace/Delete key.\n * @default true\n */\n handleExpandedSelectionOnDelete?: boolean;\n\n /**\n * Callback function to determine whether the Rooster should handle the Enter key press.\n * If the function returns true, the Rooster will handle the Enter key press instead of the browser.\n * @param editor - The editor instance.\n * @returns A boolean\n */\n shouldHandleEnterKey?: ((editor: IEditor) => boolean) | boolean;\n};\n\nconst BACKSPACE_KEY = 8;\nconst DELETE_KEY = 46;\n/**\n * According to https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n * 229 can be sent in variants generated when Long press (iOS) or using IM.\n *\n * Other cases: https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229\n */\nconst DEAD_KEY = 229;\n\nconst DefaultOptions: Partial<EditOptions> = {\n handleTabKey: true,\n handleExpandedSelectionOnDelete: true,\n};\n\n/**\n * Edit plugins helps editor to do editing operation on top of content model.\n * This includes:\n * 1. Delete Key\n * 2. Backspace Key\n * 3. Tab Key\n */\nexport class EditPlugin implements EditorPlugin {\n private editor: IEditor | null = null;\n private disposer: (() => void) | null = null;\n private shouldHandleNextInputEvent = false;\n private selectionAfterDelete: DOMSelection | null = null;\n private handleNormalEnter: (editor: IEditor) => boolean = (editor: IEditor) => false;\n\n /**\n * @param options An optional parameter that takes in an object of type EditOptions, which includes the following properties:\n * handleTabKey: A boolean that enables or disables Tab key handling. Defaults to true.\n */\n constructor(private options: EditOptions = DefaultOptions) {}\n\n private createNormalEnterChecker(result: boolean) {\n return result ? () => true : () => false;\n }\n\n private getHandleNormalEnter(editor: IEditor) {\n switch (typeof this.options.shouldHandleEnterKey) {\n case 'function':\n return this.options.shouldHandleEnterKey;\n break;\n case 'boolean':\n return this.createNormalEnterChecker(this.options.shouldHandleEnterKey);\n break;\n default:\n return this.createNormalEnterChecker(\n editor.isExperimentalFeatureEnabled('HandleEnterKey')\n );\n break;\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Edit';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n this.handleNormalEnter = this.getHandleNormalEnter(editor);\n\n if (editor.getEnvironment().isAndroid) {\n this.disposer = this.editor.attachDomEvent({\n beforeinput: {\n beforeDispatch: e => this.handleBeforeInputEvent(editor, e),\n },\n });\n }\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n this.editor = null;\n this.disposer?.();\n this.disposer = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (this.editor) {\n switch (event.eventType) {\n case 'keyDown':\n this.handleKeyDownEvent(this.editor, event);\n break;\n case 'keyUp':\n if (this.selectionAfterDelete) {\n this.editor.setDOMSelection(this.selectionAfterDelete);\n this.selectionAfterDelete = null;\n }\n break;\n }\n }\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * Handle an event exclusively means other plugin will not receive this event in\n * onPluginEvent method.\n * If two plugins will return true in willHandleEventExclusively() for the same event,\n * the final result depends on the order of the plugins are added into editor\n * @param event The event to check:\n */\n willHandleEventExclusively(event: PluginEvent) {\n if (\n this.editor &&\n this.options.handleTabKey &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == 'Tab' &&\n !event.rawEvent.shiftKey\n ) {\n const selection = this.editor.getDOMSelection();\n const startContainer =\n selection?.type == 'range' && selection.range.collapsed\n ? selection.range.startContainer\n : null;\n const table = startContainer\n ? this.editor.getDOMHelper().findClosestElementAncestor(startContainer, 'table')\n : null;\n const parsedTable = table && parseTableCells(table);\n\n if (parsedTable) {\n const lastRow = parsedTable[parsedTable.length - 1];\n const lastCell = lastRow && lastRow[lastRow.length - 1];\n\n if (typeof lastCell == 'object' && lastCell.contains(startContainer)) {\n // When TAB in the last cell of a table, we will generate new table row, so prevent other plugins handling this event\n // e.g. SelectionPlugin will move the focus out of table, which is conflict with this behavior\n return true;\n }\n }\n }\n\n return false;\n }\n\n private handleKeyDownEvent(editor: IEditor, event: KeyDownEvent) {\n const rawEvent = event.rawEvent;\n const hasCtrlOrMetaKey = rawEvent.ctrlKey || rawEvent.metaKey;\n\n if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {\n switch (rawEvent.key) {\n case 'Backspace':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n keyboardDelete(editor, rawEvent, this.options.handleExpandedSelectionOnDelete);\n break;\n\n case 'Delete':\n // Use our API to handle BACKSPACE/DELETE key.\n // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache\n // And leave it to browser when shift key is pressed so that browser will trigger cut event\n if (!event.rawEvent.shiftKey) {\n keyboardDelete(\n editor,\n rawEvent,\n this.options.handleExpandedSelectionOnDelete\n );\n }\n break;\n\n case 'Tab':\n if (this.options.handleTabKey && !hasCtrlOrMetaKey) {\n keyboardTab(editor, rawEvent);\n }\n break;\n case 'Unidentified':\n if (editor.getEnvironment().isAndroid) {\n this.shouldHandleNextInputEvent = true;\n }\n break;\n\n case 'Enter':\n if (\n !hasCtrlOrMetaKey &&\n !event.rawEvent.isComposing &&\n event.rawEvent.keyCode !== DEAD_KEY\n ) {\n keyboardEnter(editor, rawEvent, this.handleNormalEnter(editor));\n }\n break;\n\n default:\n keyboardInput(editor, rawEvent);\n break;\n }\n }\n }\n\n private handleBeforeInputEvent(editor: IEditor, rawEvent: Event) {\n // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key\n // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic\n if (\n !this.shouldHandleNextInputEvent ||\n !(rawEvent instanceof InputEvent) ||\n rawEvent.defaultPrevented\n ) {\n return;\n }\n this.shouldHandleNextInputEvent = false;\n\n let handled = false;\n switch (rawEvent.inputType) {\n case 'deleteContentBackward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Backspace',\n keyCode: BACKSPACE_KEY,\n which: BACKSPACE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n break;\n case 'deleteContentForward':\n handled = keyboardDelete(\n editor,\n new KeyboardEvent('keydown', {\n key: 'Delete',\n keyCode: DELETE_KEY,\n which: DELETE_KEY,\n }),\n this.options.handleExpandedSelectionOnDelete\n );\n break;\n }\n\n if (handled) {\n rawEvent.preventDefault();\n\n // Restore the selection on keyup event to avoid the cursor jump issue\n // See: https://issues.chromium.org/issues/330596261\n this.selectionAfterDelete = editor.getDOMSelection();\n }\n }\n}\n"]}
|