|
278 | 278 | * Checks if all widget instances are still present in the DOM.
|
279 | 279 | * Destroys those instances that are not present.
|
280 | 280 | * Reinitializes widgets on widget wrappers for which widget instances
|
281 |
| - * cannot be found. |
| 281 | + * cannot be found. Takes nested widgets into account too. |
282 | 282 | *
|
283 | 283 | * This method triggers the {@link #event-checkWidgets} event whose listeners
|
284 | 284 | * can cancel the method's execution or modify its options.
|
|
321 | 321 | },
|
322 | 322 |
|
323 | 323 | /**
|
324 |
| - * Destroys the widget instance. |
| 324 | + * Destroys the widget instance and all its nested widgets (widgets inside its nested editables). |
325 | 325 | *
|
326 | 326 | * @param {CKEDITOR.plugins.widget} widget The widget instance to be destroyed.
|
327 | 327 | * @param {Boolean} [offline] Whether the widget is offline (detached from the DOM tree) —
|
|
341 | 341 | *
|
342 | 342 | * @param {Boolean} [offline] Whether the widgets are offline (detached from the DOM tree) —
|
343 | 343 | * in this case the DOM (attributes, classes, etc.) will not be cleaned up.
|
| 344 | + * @param {CKEDITOR.dom.element} [container] Container within widgets will be destroyed. |
| 345 | + * This option will be ignored if `offline` flag was set to `true`, because in such case |
| 346 | + * it is not possible to find widgets within passed block. |
344 | 347 | */
|
345 |
| - destroyAll: function( offline ) { |
| 348 | + destroyAll: function( offline, container ) { |
| 349 | + if ( container && !offline ) { |
| 350 | + var wrappers = container.find( '.cke_widget_wrapper' ), |
| 351 | + l = wrappers.count(), |
| 352 | + i = 0, |
| 353 | + widget; |
| 354 | + |
| 355 | + // Length is constant, because this is not a live node list. |
| 356 | + // Note: since querySelectorAll returns nodes in document order, |
| 357 | + // outer widgets are always placed before their nested widgets and therefore |
| 358 | + // are destroyed before them. |
| 359 | + for ( ; i < l; ++i ) { |
| 360 | + widget = this.getByElement( wrappers.getItem( i ), true ); |
| 361 | + // Widget might not be found, because it could be a nested widget, |
| 362 | + // which would be destroyed when destroying its parent. |
| 363 | + if ( widget ) |
| 364 | + this.destroy( widget ); |
| 365 | + } |
| 366 | + |
| 367 | + return; |
| 368 | + } |
| 369 | + |
346 | 370 | var instances = this.instances,
|
347 | 371 | widget;
|
348 | 372 |
|
|
1005 | 1029 | },
|
1006 | 1030 |
|
1007 | 1031 | /**
|
1008 |
| - * Destroys a nested editable. |
| 1032 | + * Destroys a nested editable and all nested widgets. |
1009 | 1033 | *
|
1010 | 1034 | * @param {String} editableName Nested editable name.
|
1011 | 1035 | * @param {Boolean} [offline] See {@link #method-destroy} method.
|
|
1018 | 1042 | this.editor.focusManager.remove( editable );
|
1019 | 1043 |
|
1020 | 1044 | if ( !offline ) {
|
| 1045 | + this.repository.destroyAll( false, editable ); |
1021 | 1046 | editable.removeClass( 'cke_widget_editable' );
|
1022 | 1047 | editable.removeClass( 'cke_widget_editable_focused' );
|
1023 | 1048 | editable.removeAttributes( [ 'contenteditable', 'data-cke-widget-editable', 'data-cke-enter-mode' ] );
|
|
1158 | 1183 |
|
1159 | 1184 | // Finally, process editable's data. This data wasn't processed when loading
|
1160 | 1185 | // editor's data, becuase they need to be processed separately, with its own filters and settings.
|
| 1186 | + editable._.initialSetData = true; |
1161 | 1187 | editable.setData( editable.getHtml() );
|
1162 | 1188 |
|
1163 | 1189 | return true;
|
|
1486 | 1512 | // Call the base constructor.
|
1487 | 1513 | CKEDITOR.dom.element.call( this, element.$ );
|
1488 | 1514 | this.editor = editor;
|
| 1515 | + this._ = {}; |
1489 | 1516 | var filter = this.filter = config.filter;
|
1490 | 1517 |
|
1491 | 1518 | // If blockless editable - always use BR mode.
|
|
1503 | 1530 | * and the {@link CKEDITOR.editor#filter}. This ensures that the data was filtered and prepared to be
|
1504 | 1531 | * edited like the {@link CKEDITOR.editor#method-setData editor data}.
|
1505 | 1532 | *
|
| 1533 | + * Before content is changed all nested widgets are destroyed. Afterwards, after new content is loaded |
| 1534 | + * all nested widgets are initialized. |
| 1535 | + * |
1506 | 1536 | * @param {String} data
|
1507 | 1537 | */
|
1508 | 1538 | setData: function( data ) {
|
| 1539 | + // For performance reasons don't call destroyAll when initializing nested editable, |
| 1540 | + // because there are not widgets inside. |
| 1541 | + if ( !this._.initialSetData ) { |
| 1542 | + // Destroy all nested widgets before setting data. |
| 1543 | + this.editor.widgets.destroyAll( false, this ); |
| 1544 | + } |
| 1545 | + this._.initialSetData = false; |
| 1546 | + |
1509 | 1547 | data = this.editor.dataProcessor.toHtml( data, {
|
1510 | 1548 | context: this.getName(),
|
1511 | 1549 | filter: this.filter,
|
|
1715 | 1753 |
|
1716 | 1754 | var editable = this.editor.editable(),
|
1717 | 1755 | instances = this.instances,
|
1718 |
| - newInstances, i, count, wrapper; |
| 1756 | + newInstances, i, count, wrapper, notYetInitialized; |
1719 | 1757 |
|
1720 | 1758 | if ( !editable )
|
1721 | 1759 | return;
|
|
1736 | 1774 | // Create widgets on existing wrappers if they do not exists.
|
1737 | 1775 | for ( i = 0, count = wrappers.count(); i < count; i++ ) {
|
1738 | 1776 | wrapper = wrappers.getItem( i );
|
1739 |
| - |
1740 |
| - // Check if there's no instance for this widget and that |
1741 |
| - // wrapper is not inside some temporary element like copybin (#11088). |
1742 |
| - if ( !this.getByElement( wrapper, true ) && !findParent( wrapper, isDomTemp ) ) { |
| 1777 | + notYetInitialized = !this.getByElement( wrapper, true ); |
| 1778 | + |
| 1779 | + // Check if: |
| 1780 | + // * there's no instance for this widget |
| 1781 | + // * wrapper is not inside some temporary element like copybin (#11088) |
| 1782 | + // * it was a nested widget's wrapper which has been detached from DOM, |
| 1783 | + // when nested editable has been initialized (it overwrites its innerHTML |
| 1784 | + // and initializes nested widgets). |
| 1785 | + if ( notYetInitialized && !findParent( wrapper, isDomTemp ) && editable.contains( wrapper ) ) { |
1743 | 1786 | // Add cke_widget_new class because otherwise
|
1744 | 1787 | // widget will not be created on such wrapper.
|
1745 | 1788 | wrapper.addClass( 'cke_widget_new' );
|
|
0 commit comments