Skip to content

Commit 18d651a

Browse files
committed
Merge branch 't/12448' into major
2 parents 33c8854 + 553a5eb commit 18d651a

File tree

7 files changed

+346
-54
lines changed

7 files changed

+346
-54
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ New Features:
1313
* [#11583](http://dev.ckeditor.com/ticket/11583): Added support for HTML5 `required` attribute in various form elements. Thanks to [Steven Busse](https://github.com/sbusse)!
1414
* [#12143](http://dev.ckeditor.com/ticket/12143): Added [`config.floatSpacePreferRight`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-floatSpacePreferRight) configuration option that switches the alignment of the floating toolbar. Thanks to [InvisibleBacon](http://github.com/InvisibleBacon)!
1515
* [#12416](http://dev.ckeditor.com/ticket/12416): Added [`widget.definition.upcastPriority`](http://docs.ckeditor.com/#!/api/CKEDITOR.plugins.widget.definition-property-upcastPriority) property which gives more control over widgets upcasting order to the widget author.
16+
* [#12448](http://dev.ckeditor.com/ticket/12448): Set of new methods, params and events giving the developer more control over HTML insertion. See the [`editable.insertHtml()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertHtml) param `range`, the [`editable.insertHtmlIntoRange()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editable-method-insertHtmlIntoRange) method and the [`editor.afterInsertHtml`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-afterInsertHtml) event.
1617

1718
Fixed Issues:
1819

core/editable.js

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,18 @@
231231
},
232232

233233
/**
234-
* @see CKEDITOR.editor#insertHtml
235-
*/
236-
insertHtml: function( data, mode ) {
237-
beforeInsert( this );
238-
// Default mode is 'html'.
239-
insert( this, mode || 'html', data );
240-
},
241-
242-
/**
243-
* @see CKEDITOR.editor#insertText
234+
* Low-level method for inserting text into the editable.
235+
* See the {@link CKEDITOR.editor#method-insertText} method which is the editor-level API
236+
* for this purpose.
237+
*
238+
* @param {String} text
244239
*/
245240
insertText: function( text ) {
246-
beforeInsert( this );
247-
insert( this, 'text', this.transformPlainTextToHtml( text ) );
241+
this.insertHtml( this.transformPlainTextToHtml( text ), 'text' );
248242
},
249243

250244
/**
251-
* Set enterMode based on current selection and {@link CKEDITOR.editor#activeEnterMode}
252-
* and call {@link CKEDITOR.tools#transformPlainTextToHtml}.
245+
* Transforms plain text to HTML based on current selection and {@link CKEDITOR.editor#activeEnterMode}.
253246
*
254247
* @since 4.5
255248
* @param {String} text Text to transform.
@@ -263,9 +256,79 @@
263256
return CKEDITOR.tools.transformPlainTextToHtml( text, enterMode );
264257
},
265258

259+
/**
260+
* Low-level method for inserting HTML into the editable.
261+
* See the {@link CKEDITOR.editor#method-insertHtml} method which is the editor-level API
262+
* for this purpose.
263+
*
264+
* @param {String} data The HTML to be inserted.
265+
* @param {String} [mode='html'] See {@link CKEDITOR.editor#method-insertHtml}'s param.
266+
* @param {CKEDITOR.dom.range} [range] If specified the HTML will be inserted into the range
267+
* instead of into the selection.
268+
*/
269+
insertHtml: function( data, mode, range ) {
270+
if ( !range )
271+
this.insertHtmlIntoSelection( data, mode );
272+
else
273+
this.insertHtmlIntoRange( data, range, mode );
274+
},
275+
276+
/**
277+
* Inserts HTML into the selection. See also the {@link #insertHtml} method.
278+
*
279+
* Fires the {@link CKEDITOR.editor#event-afterInsertHtml} event.
280+
*
281+
* @since 4.5
282+
* @param {String} data The HTML to be inserted.
283+
* @param {String} [mode='html'] See {@link CKEDITOR.editor#method-insertHtml}'s param.
284+
*/
285+
insertHtmlIntoSelection: function( data, mode ) {
286+
// HTML insertion only considers the first range.
287+
// Note: getRanges will be overwritten for tests since we want to test
288+
// custom ranges and bypass native selections.
289+
var range = this.editor.getSelection().getRanges()[ 0 ];
290+
291+
beforeInsert( this );
292+
293+
// Default mode is 'html'.
294+
insert( this, mode || 'html', data, range );
295+
296+
// Make the final range selection.
297+
range.select();
298+
299+
afterInsert( this );
300+
301+
this.editor.fire( 'afterInsertHtml', {} );
302+
},
303+
304+
/**
305+
* Inserts HTML into the position in the editor determined by the range.
306+
*
307+
* Fires the {@link CKEDITOR.editor#event-afterInsertHtml} event.
308+
*
309+
* **Note:** This method does not {@link CKEDITOR.editor#saveSnashot save undo snapshots}.
310+
*
311+
* @since 4.5
312+
* @param {String} data HTML code to be inserted into the editor.
313+
* @param {CKEDITOR.dom.range} range The range as a place of insertion.
314+
* @param {String} [mode='html'] Mode in which HTML will be inserted.
315+
* See {@link CKEDITOR.editor#method-insertHtml}.
316+
*/
317+
insertHtmlIntoRange: function( data, range, mode ) {
318+
// Default mode is 'html'
319+
insert( this, mode || 'html', data, range );
320+
321+
this.editor.fire( 'afterInsertHtml', { intoRange: range } );
322+
},
266323

267324
/**
268-
* @see CKEDITOR.editor#insertElement
325+
* Low-level method for inserting an element into the editable.
326+
* See the {@link CKEDITOR.editor#method-insertElement} method which is the editor-level API
327+
* for this purpose.
328+
*
329+
* @param {CKEDITOR.dom.element} element The element to insert.
330+
* @param {CKEDITOR.dom.range} [range] If specified the element will be inserted into the range
331+
* instead of into the selection.
269332
*/
270333
insertElement: function( element, range ) {
271334
if ( !range )
@@ -275,7 +338,9 @@
275338
},
276339

277340
/**
278-
* Inserts an element into the position in the editor determined by range.
341+
* Inserts an element into the position in the editor determined by the range.
342+
*
343+
* **Note:** This method does not {@link CKEDITOR.editor#saveSnashot save undo snapshots}.
279344
*
280345
* @param {CKEDITOR.dom.element} element The element to be inserted.
281346
* @param {CKEDITOR.dom.range} range The range as a place of insertion.
@@ -332,7 +397,7 @@
332397
},
333398

334399
/**
335-
* Inserts an element into the currently selected position in the editor.
400+
* Inserts an element into the selection.
336401
*
337402
* @param {CKEDITOR.dom.element} element The element to be inserted.
338403
*/
@@ -1260,14 +1325,8 @@
12601325

12611326
// Inserts the given (valid) HTML into the range position (with range content deleted),
12621327
// guarantee it's result to be a valid DOM tree.
1263-
function insert( editable, type, data ) {
1328+
function insert( editable, type, data, range ) {
12641329
var editor = editable.editor,
1265-
selection = editor.getSelection(),
1266-
// HTML insertion only considers the first range.
1267-
// Note: getRanges will be overwritten for tests since we want to test
1268-
// custom ranges and bypass native selections.
1269-
// TODO what should we do with others? Remove?
1270-
range = selection.getRanges()[ 0 ],
12711330
dontFilter = false;
12721331

12731332
if ( type == 'unfiltered_html' ) {
@@ -1320,11 +1379,6 @@
13201379
// Set final range position and clean up.
13211380

13221381
cleanupAfterInsertion( that );
1323-
1324-
// Make the final range selection.
1325-
range.select();
1326-
1327-
afterInsert( editable );
13281382
}
13291383

13301384
// Prepare range to its data deletion.

core/editor.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,10 @@
10191019
*
10201020
* CKEDITOR.instances.editor1.insertHtml( '<p>This is a new paragraph.</p>' );
10211021
*
1022+
* Fires the {@link #event-insertHtml} and {@link #event-afterInsertHtml} events. The HTML is inserted
1023+
* in {@link #event-insertHtml} event's listener with a default priority (10) so you can add listeners with
1024+
* lower or higher priorities in order to execute some code before or after the HTML is inserted.
1025+
*
10221026
* @param {String} html HTML code to be inserted into the editor.
10231027
* @param {String} [mode='html'] The mode in which the HTML code will be inserted. One of the following:
10241028
*
@@ -1041,6 +1045,10 @@
10411045
*
10421046
* CKEDITOR.instances.editor1.insertText( ' line1 \n\n line2' );
10431047
*
1048+
* Fires the {@link #event-insertText} and {@link #event-afterInsertHtml} events. The text is inserted
1049+
* in {@link #event-insertText} event's listener with a default priority (10) so you can add listeners with
1050+
* lower or higher priorities in order to execute some code before or after the text is inserted.
1051+
*
10441052
* @since 3.5
10451053
* @param {String} text Text to be inserted into the editor.
10461054
*/
@@ -1055,6 +1063,10 @@
10551063
* var element = CKEDITOR.dom.element.createFromHtml( '<img src="hello.png" border="0" title="Hello" />' );
10561064
* CKEDITOR.instances.editor1.insertElement( element );
10571065
*
1066+
* Fires the {@link #event-insertElement} event. The element is inserted in listener with a default priority (10)
1067+
* so you can add listeners with lower or higher priorities in order to execute some code before or after
1068+
* the element is inserted.
1069+
*
10581070
* @param {CKEDITOR.dom.element} element The element to be inserted
10591071
* into the editor.
10601072
*/
@@ -1701,7 +1713,8 @@ CKEDITOR.ELEMENT_MODE_INLINE = 3;
17011713
*/
17021714

17031715
/**
1704-
* Internal event to perform the {@link #method-insertHtml} call.
1716+
* Fired by the {@link #method-insertHtml} method. See the method documentation for more information
1717+
* on how this event can be used.
17051718
*
17061719
* @event insertHtml
17071720
* @param {CKEDITOR.editor} editor This editor instance.
@@ -1711,21 +1724,34 @@ CKEDITOR.ELEMENT_MODE_INLINE = 3;
17111724
*/
17121725

17131726
/**
1714-
* Internal event to perform the {@link #method-insertText} call.
1727+
* Fired by the {@link #method-insertText} method. See the method documentation for more information
1728+
* on how this event can be used.
17151729
*
17161730
* @event insertText
17171731
* @param {CKEDITOR.editor} editor This editor instance.
17181732
* @param {String} data The text to insert.
17191733
*/
17201734

17211735
/**
1722-
* Internal event to perform the {@link #method-insertElement} call.
1736+
* Fired by the {@link #method-insertElement} method. See the method documentation for more information
1737+
* on how this event can be used.
17231738
*
17241739
* @event insertElement
17251740
* @param {CKEDITOR.editor} editor This editor instance.
17261741
* @param {CKEDITOR.dom.element} data The element to insert.
17271742
*/
17281743

1744+
/**
1745+
* Event fired after data insertion using insertHtml or insertHtmlIntoRange methods.
1746+
*
1747+
* @since 4.5
1748+
* @event afterInsertHtml
1749+
* @param data
1750+
* @param {CKEDITOR.dom.range} [data.intoRange] If set the HTML was inserted into the range
1751+
* instead of into the selection. See the {@link CKEDITOR.editable#insertHtml} method which accepts range
1752+
* as a parameter.
1753+
*/
1754+
17291755
/**
17301756
* Event fired after the {@link #property-readOnly} property changes.
17311757
*

plugins/widget/plugin.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,18 +2626,19 @@
26262626
} );
26272627

26282628
// Listen with high priority to check widgets after data was inserted.
2629-
editor.on( 'insertText', checkNewWidgets, null, null, 999 );
2630-
editor.on( 'insertHtml', checkNewWidgets, null, null, 999 );
2631-
2632-
function checkNewWidgets() {
2633-
editor.fire( 'lockSnapshot' );
2629+
editor.on( 'afterInsertHtml', function( evt ) {
2630+
if ( evt.data.intoRange ) {
2631+
widgetsRepo.checkWidgets( { initOnlyNew: true } );
2632+
} else {
2633+
editor.fire( 'lockSnapshot' );
26342634

2635-
// Init only new for performance reason.
2636-
// Focus inited if only widget was processed.
2637-
widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } );
2635+
// Init only new for performance reason.
2636+
// Focus inited if only widget was processed.
2637+
widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } );
26382638

2639-
editor.fire( 'unlockSnapshot' );
2640-
}
2639+
editor.fire( 'unlockSnapshot' );
2640+
}
2641+
} );
26412642
}
26422643

26432644
// Helper for coordinating which widgets should be

tests/core/editable/_helpers/insertion.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ var insertionDT = ( function() {
6464
assertInsertion: function( editablesNames, source, insertion, expected, enterMode, message ) {
6565
var editableName, result, editor, modes, mode,
6666
root, checkAllModes, rangeList, revertChanges, revertChanges2,
67-
expectedForMode;
67+
expectedForMode, afterInsertCount, afterInsertData;
6868

6969
editablesNames = editablesNames.split( ',' );
7070
// Check all supported modes if expected value is a string or regexp.
@@ -97,7 +97,7 @@ var insertionDT = ( function() {
9797
while ( 1 ) {
9898
var startContainer = range.startContainer,
9999
startOffset = range.startOffset;
100-
// Limit the fix only to non-block elements.(#3950)
100+
// Limit the fix only to non-block elements. (#3950)
101101
if (
102102
startOffset ==
103103
(
@@ -146,13 +146,20 @@ var insertionDT = ( function() {
146146
editor = this.editorsPool[ editableName ];
147147
root = editor.editable();
148148

149+
editor.on( 'afterInsertHtml', function( evt ) {
150+
afterInsertCount++;
151+
afterInsertData = evt.data;
152+
} );
153+
149154
// Set enter mode to the given value or reset to the default one.
150155
editor.enterMode = enterMode || editor._.defaultEnterMode;
151156

152157
for ( mode in modes ) {
153158
// Selection::getRanges() will read from this variable.
154159
rangeList = new CKEDITOR.dom.rangeList( tools.setHtmlWithRange( root, source, root ) );
155160

161+
afterInsertCount = 0;
162+
156163
if ( mode == 'insertElement' )
157164
editor.insertElement( CKEDITOR.dom.element.createFromHtml( insertion, editor.document ) );
158165
else if ( mode == 'insertText' )
@@ -172,6 +179,11 @@ var insertionDT = ( function() {
172179
assert[ expectedForMode.exec ? 'isMatching' : 'areSame' ]( expectedForMode, result,
173180
( message || 'editor\'s content should equal expected value' ) +
174181
' (editable: "' + editableName + '" & mode: "' + mode + '")' );
182+
183+
if ( mode != 'insertElement' ) {
184+
assert.areSame( 1, afterInsertCount, 'There should be 1 afterInsertHtml event after every insertion.' );
185+
assert.isUndefined( afterInsertData.intoRange, 'intoRange parameter should be undefined.' );
186+
}
175187
}
176188
}
177189

0 commit comments

Comments
 (0)