]> git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blobdiff - sources/plugins/widget/plugin.js
Add oembed
[perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git] / sources / plugins / widget / plugin.js
diff --git a/sources/plugins/widget/plugin.js b/sources/plugins/widget/plugin.js
new file mode 100644 (file)
index 0000000..2708e09
--- /dev/null
@@ -0,0 +1,4147 @@
+/**\r
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r
+ * For licensing, see LICENSE.md or http://ckeditor.com/license\r
+ */\r
+\r
+/**\r
+ * @fileOverview [Widget](http://ckeditor.com/addon/widget) plugin.\r
+ */\r
+\r
+'use strict';\r
+\r
+( function() {\r
+       var DRAG_HANDLER_SIZE = 15;\r
+\r
+       CKEDITOR.plugins.add( 'widget', {\r
+               // jscs:disable maximumLineLength\r
+               lang: 'af,ar,az,bg,ca,cs,cy,da,de,de-ch,el,en,en-gb,eo,es,es-mx,eu,fa,fi,fr,gl,he,hr,hu,id,it,ja,km,ko,ku,lv,nb,nl,no,oc,pl,pt,pt-br,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%\r
+               // jscs:enable maximumLineLength\r
+               requires: 'lineutils,clipboard,widgetselection',\r
+               onLoad: function() {\r
+                       CKEDITOR.addCss(\r
+                               '.cke_widget_wrapper{' +\r
+                                       'position:relative;' +\r
+                                       'outline:none' +\r
+                               '}' +\r
+                               '.cke_widget_inline{' +\r
+                                       'display:inline-block' +\r
+                               '}' +\r
+                               '.cke_widget_wrapper:hover>.cke_widget_element{' +\r
+                                       'outline:2px solid yellow;' +\r
+                                       'cursor:default' +\r
+                               '}' +\r
+                               '.cke_widget_wrapper:hover .cke_widget_editable{' +\r
+                                       'outline:2px solid yellow' +\r
+                               '}' +\r
+                               '.cke_widget_wrapper.cke_widget_focused>.cke_widget_element,' +\r
+                               // We need higher specificity than hover style.\r
+                               '.cke_widget_wrapper .cke_widget_editable.cke_widget_editable_focused{' +\r
+                                       'outline:2px solid #ace' +\r
+                               '}' +\r
+                               '.cke_widget_editable{' +\r
+                                       'cursor:text' +\r
+                               '}' +\r
+                               '.cke_widget_drag_handler_container{' +\r
+                                       'position:absolute;' +\r
+                                       'width:' + DRAG_HANDLER_SIZE + 'px;' +\r
+                                       'height:0;' +\r
+                                       // Initially drag handler should not be visible, until its position will be\r
+                                       // calculated (http://dev.ckeditor.com/ticket/11177).\r
+                                       // We need to hide unpositined handlers, so they don't extend\r
+                                       // widget's outline far to the left (http://dev.ckeditor.com/ticket/12024).\r
+                                       'display:none;' +\r
+                                       'opacity:0.75;' +\r
+                                       'transition:height 0s 0.2s;' + // Delay hiding drag handler.\r
+                                       // Prevent drag handler from being misplaced (http://dev.ckeditor.com/ticket/11198).\r
+                                       'line-height:0' +\r
+                               '}' +\r
+                               '.cke_widget_wrapper:hover>.cke_widget_drag_handler_container{' +\r
+                                       'height:' + DRAG_HANDLER_SIZE + 'px;' +\r
+                                       'transition:none' +\r
+                               '}' +\r
+                               '.cke_widget_drag_handler_container:hover{' +\r
+                                       'opacity:1' +\r
+                               '}' +\r
+                               'img.cke_widget_drag_handler{' +\r
+                                       'cursor:move;' +\r
+                                       'width:' + DRAG_HANDLER_SIZE + 'px;' +\r
+                                       'height:' + DRAG_HANDLER_SIZE + 'px;' +\r
+                                       'display:inline-block' +\r
+                               '}' +\r
+                               '.cke_widget_mask{' +\r
+                                       'position:absolute;' +\r
+                                       'top:0;' +\r
+                                       'left:0;' +\r
+                                       'width:100%;' +\r
+                                       'height:100%;' +\r
+                                       'display:block' +\r
+                               '}' +\r
+                               '.cke_editable.cke_widget_dragging, .cke_editable.cke_widget_dragging *{' +\r
+                                       'cursor:move !important' +\r
+                               '}'\r
+                       );\r
+               },\r
+\r
+               beforeInit: function( editor ) {\r
+                       /**\r
+                        * An instance of widget repository. It contains all\r
+                        * {@link CKEDITOR.plugins.widget.repository#registered registered widget definitions} and\r
+                        * {@link CKEDITOR.plugins.widget.repository#instances initialized instances}.\r
+                        *\r
+                        *              editor.widgets.add( 'someName', {\r
+                        *                      // Widget definition...\r
+                        *              } );\r
+                        *\r
+                        *              editor.widgets.registered.someName; // -> Widget definition\r
+                        *\r
+                        * @since 4.3\r
+                        * @readonly\r
+                        * @property {CKEDITOR.plugins.widget.repository} widgets\r
+                        * @member CKEDITOR.editor\r
+                        */\r
+                       editor.widgets = new Repository( editor );\r
+               },\r
+\r
+               afterInit: function( editor ) {\r
+                       addWidgetButtons( editor );\r
+                       setupContextMenu( editor );\r
+               }\r
+       } );\r
+\r
+       /**\r
+        * Widget repository. It keeps track of all {@link #registered registered widget definitions} and\r
+        * {@link #instances initialized instances}. An instance of the repository is available under\r
+        * the {@link CKEDITOR.editor#widgets} property.\r
+        *\r
+        * @class CKEDITOR.plugins.widget.repository\r
+        * @mixins CKEDITOR.event\r
+        * @constructor Creates a widget repository instance. Note that the widget plugin automatically\r
+        * creates a repository instance which is available under the {@link CKEDITOR.editor#widgets} property.\r
+        * @param {CKEDITOR.editor} editor The editor instance for which the repository will be created.\r
+        */\r
+       function Repository( editor ) {\r
+               /**\r
+                * The editor instance for which this repository was created.\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.editor} editor\r
+                */\r
+               this.editor = editor;\r
+\r
+               /**\r
+                * A hash of registered widget definitions (definition name => {@link CKEDITOR.plugins.widget.definition}).\r
+                *\r
+                * To register a definition use the {@link #add} method.\r
+                *\r
+                * @readonly\r
+                */\r
+               this.registered = {};\r
+\r
+               /**\r
+                * An object containing initialized widget instances (widget id => {@link CKEDITOR.plugins.widget}).\r
+                *\r
+                * @readonly\r
+                */\r
+               this.instances = {};\r
+\r
+               /**\r
+                * An array of selected widget instances.\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.plugins.widget[]} selected\r
+                */\r
+               this.selected = [];\r
+\r
+               /**\r
+                * The focused widget instance. See also {@link CKEDITOR.plugins.widget#event-focus}\r
+                * and {@link CKEDITOR.plugins.widget#event-blur} events.\r
+                *\r
+                *              editor.on( 'selectionChange', function() {\r
+                *                      if ( editor.widgets.focused ) {\r
+                *                              // Do something when a widget is focused...\r
+                *                      }\r
+                *              } );\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.plugins.widget} focused\r
+                */\r
+               this.focused = null;\r
+\r
+               /**\r
+                * The widget instance that contains the nested editable which is currently focused.\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.plugins.widget} widgetHoldingFocusedEditable\r
+                */\r
+               this.widgetHoldingFocusedEditable = null;\r
+\r
+               this._ = {\r
+                       nextId: 0,\r
+                       upcasts: [],\r
+                       upcastCallbacks: [],\r
+                       filters: {}\r
+               };\r
+\r
+               setupWidgetsLifecycle( this );\r
+               setupSelectionObserver( this );\r
+               setupMouseObserver( this );\r
+               setupKeyboardObserver( this );\r
+               setupDragAndDrop( this );\r
+               setupNativeCutAndCopy( this );\r
+       }\r
+\r
+       Repository.prototype = {\r
+               /**\r
+                * Minimum interval between selection checks.\r
+                *\r
+                * @private\r
+                */\r
+               MIN_SELECTION_CHECK_INTERVAL: 500,\r
+\r
+               /**\r
+                * Adds a widget definition to the repository. Fires the {@link CKEDITOR.editor#widgetDefinition} event\r
+                * which allows to modify the widget definition which is going to be registered.\r
+                *\r
+                * @param {String} name The name of the widget definition.\r
+                * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget definition.\r
+                * @returns {CKEDITOR.plugins.widget.definition}\r
+                */\r
+               add: function( name, widgetDef ) {\r
+                       // Create prototyped copy of original widget definition, so we won't modify it.\r
+                       widgetDef = CKEDITOR.tools.prototypedCopy( widgetDef );\r
+                       widgetDef.name = name;\r
+\r
+                       widgetDef._ = widgetDef._ || {};\r
+\r
+                       this.editor.fire( 'widgetDefinition', widgetDef );\r
+\r
+                       if ( widgetDef.template )\r
+                               widgetDef.template = new CKEDITOR.template( widgetDef.template );\r
+\r
+                       addWidgetCommand( this.editor, widgetDef );\r
+                       addWidgetProcessors( this, widgetDef );\r
+\r
+                       this.registered[ name ] = widgetDef;\r
+\r
+                       return widgetDef;\r
+               },\r
+\r
+               /**\r
+                * Adds a callback for element upcasting. Each callback will be executed\r
+                * for every element which is later tested by upcast methods. If a callback\r
+                * returns `false`, the element will not be upcasted.\r
+                *\r
+                *              // Images with the "banner" class will not be upcasted (e.g. to the image widget).\r
+                *              editor.widgets.addUpcastCallback( function( element ) {\r
+                *                      if ( element.name == 'img' && element.hasClass( 'banner' ) )\r
+                *                              return false;\r
+                *              } );\r
+                *\r
+                * @param {Function} callback\r
+                * @param {CKEDITOR.htmlParser.element} callback.element\r
+                */\r
+               addUpcastCallback: function( callback ) {\r
+                       this._.upcastCallbacks.push( callback );\r
+               },\r
+\r
+               /**\r
+                * Checks the selection to update widget states (selection and focus).\r
+                *\r
+                * This method is triggered by the {@link #event-checkSelection} event.\r
+                */\r
+               checkSelection: function() {\r
+                       var sel = this.editor.getSelection(),\r
+                               selectedElement = sel.getSelectedElement(),\r
+                               updater = stateUpdater( this ),\r
+                               widget;\r
+\r
+                       // Widget is focused so commit and finish checking.\r
+                       if ( selectedElement && ( widget = this.getByElement( selectedElement, true ) ) )\r
+                               return updater.focus( widget ).select( widget ).commit();\r
+\r
+                       var range = sel.getRanges()[ 0 ];\r
+\r
+                       // No ranges or collapsed range mean that nothing is selected, so commit and finish checking.\r
+                       if ( !range || range.collapsed )\r
+                               return updater.commit();\r
+\r
+                       // Range is not empty, so create walker checking for wrappers.\r
+                       var walker = new CKEDITOR.dom.walker( range ),\r
+                               wrapper;\r
+\r
+                       walker.evaluator = Widget.isDomWidgetWrapper;\r
+\r
+                       while ( ( wrapper = walker.next() ) )\r
+                               updater.select( this.getByElement( wrapper ) );\r
+\r
+                       updater.commit();\r
+               },\r
+\r
+               /**\r
+                * Checks if all widget instances are still present in the DOM.\r
+                * Destroys those instances that are not present.\r
+                * Reinitializes widgets on widget wrappers for which widget instances\r
+                * cannot be found. Takes nested widgets into account, too.\r
+                *\r
+                * This method triggers the {@link #event-checkWidgets} event whose listeners\r
+                * can cancel the method's execution or modify its options.\r
+                *\r
+                * @param [options] The options object.\r
+                * @param {Boolean} [options.initOnlyNew] Initializes widgets only on newly wrapped\r
+                * widget elements (those which still have the `cke_widget_new` class). When this option is\r
+                * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)\r
+                * will not be reinitialized. This makes the check faster.\r
+                * @param {Boolean} [options.focusInited] If only one widget is initialized by\r
+                * the method, it will be focused.\r
+                */\r
+               checkWidgets: function( options ) {\r
+                       this.fire( 'checkWidgets', CKEDITOR.tools.copy( options || {} ) );\r
+               },\r
+\r
+               /**\r
+                * Removes the widget from the editor and moves the selection to the closest\r
+                * editable position if the widget was focused before.\r
+                *\r
+                * @param {CKEDITOR.plugins.widget} widget The widget instance to be deleted.\r
+                */\r
+               del: function( widget ) {\r
+                       if ( this.focused === widget ) {\r
+                               var editor = widget.editor,\r
+                                       range = editor.createRange(),\r
+                                       found;\r
+\r
+                               // If haven't found place for caret on the default side,\r
+                               // try to find it on the other side.\r
+                               if ( !( found = range.moveToClosestEditablePosition( widget.wrapper, true ) ) )\r
+                                       found = range.moveToClosestEditablePosition( widget.wrapper, false );\r
+\r
+                               if ( found )\r
+                                       editor.getSelection().selectRanges( [ range ] );\r
+                       }\r
+\r
+                       widget.wrapper.remove();\r
+                       this.destroy( widget, true );\r
+               },\r
+\r
+               /**\r
+                * Destroys the widget instance and all its nested widgets (widgets inside its nested editables).\r
+                *\r
+                * @param {CKEDITOR.plugins.widget} widget The widget instance to be destroyed.\r
+                * @param {Boolean} [offline] Whether the widget is offline (detached from the DOM tree) —\r
+                * in this case the DOM (attributes, classes, etc.) will not be cleaned up.\r
+                */\r
+               destroy: function( widget, offline ) {\r
+                       if ( this.widgetHoldingFocusedEditable === widget )\r
+                               setFocusedEditable( this, widget, null, offline );\r
+\r
+                       widget.destroy( offline );\r
+                       delete this.instances[ widget.id ];\r
+                       this.fire( 'instanceDestroyed', widget );\r
+               },\r
+\r
+               /**\r
+                * Destroys all widget instances.\r
+                *\r
+                * @param {Boolean} [offline] Whether the widgets are offline (detached from the DOM tree) —\r
+                * in this case the DOM (attributes, classes, etc.) will not be cleaned up.\r
+                * @param {CKEDITOR.dom.element} [container] The container within widgets will be destroyed.\r
+                * This option will be ignored if the `offline` flag was set to `true`, because in such case\r
+                * it is not possible to find widgets within the passed block.\r
+                */\r
+               destroyAll: function( offline, container ) {\r
+                       var widget,\r
+                               id,\r
+                               instances = this.instances;\r
+\r
+                       if ( container && !offline ) {\r
+                               var wrappers = container.find( '.cke_widget_wrapper' ),\r
+                                       l = wrappers.count(),\r
+                                       i = 0;\r
+\r
+                               // Length is constant, because this is not a live node list.\r
+                               // Note: since querySelectorAll returns nodes in document order,\r
+                               // outer widgets are always placed before their nested widgets and therefore\r
+                               // are destroyed before them.\r
+                               for ( ; i < l; ++i ) {\r
+                                       widget = this.getByElement( wrappers.getItem( i ), true );\r
+                                       // Widget might not be found, because it could be a nested widget,\r
+                                       // which would be destroyed when destroying its parent.\r
+                                       if ( widget )\r
+                                               this.destroy( widget );\r
+                               }\r
+\r
+                               return;\r
+                       }\r
+\r
+                       for ( id in instances ) {\r
+                               widget = instances[ id ];\r
+                               this.destroy( widget, offline );\r
+                       }\r
+               },\r
+\r
+               /**\r
+                * Finalizes a process of widget creation. This includes:\r
+                *\r
+                * * inserting widget element into editor,\r
+                * * marking widget instance as ready (see {@link CKEDITOR.plugins.widget#event-ready}),\r
+                * * focusing widget instance.\r
+                *\r
+                * This method is used by the default widget's command and is called\r
+                * after widget's dialog (if set) is closed. It may also be used in a\r
+                * customized process of widget creation and insertion.\r
+                *\r
+                *              widget.once( 'edit', function() {\r
+                *                      // Finalize creation only of not ready widgets.\r
+                *                      if ( widget.isReady() )\r
+                *                              return;\r
+                *\r
+                *                      // Cancel edit event to prevent automatic widget insertion.\r
+                *                      evt.cancel();\r
+                *\r
+                *                      CustomDialog.open( widget.data, function saveCallback( savedData ) {\r
+                *                              // Cache the container, because widget may be destroyed while saving data,\r
+                *                              // if this process will require some deep transformations.\r
+                *                              var container = widget.wrapper.getParent();\r
+                *\r
+                *                              widget.setData( savedData );\r
+                *\r
+                *                              // Widget will be retrieved from container and inserted into editor.\r
+                *                              editor.widgets.finalizeCreation( container );\r
+                *                      } );\r
+                *              } );\r
+                *\r
+                * @param {CKEDITOR.dom.element/CKEDITOR.dom.documentFragment} container The element\r
+                * or document fragment which contains widget wrapper. The container is used, so before\r
+                * finalizing creation the widget can be freely transformed (even destroyed and reinitialized).\r
+                */\r
+               finalizeCreation: function( container ) {\r
+                       var wrapper = container.getFirst();\r
+                       if ( wrapper && Widget.isDomWidgetWrapper( wrapper ) ) {\r
+                               this.editor.insertElement( wrapper );\r
+\r
+                               var widget = this.getByElement( wrapper );\r
+                               // Fire postponed #ready event.\r
+                               widget.ready = true;\r
+                               widget.fire( 'ready' );\r
+                               widget.focus();\r
+                       }\r
+               },\r
+\r
+               /**\r
+                * Finds a widget instance which contains a given element. The element will be the {@link CKEDITOR.plugins.widget#wrapper wrapper}\r
+                * of the returned widget or a descendant of this {@link CKEDITOR.plugins.widget#wrapper wrapper}.\r
+                *\r
+                *              editor.widgets.getByElement( someWidget.wrapper ); // -> someWidget\r
+                *              editor.widgets.getByElement( someWidget.parts.caption ); // -> someWidget\r
+                *\r
+                *              // Check wrapper only:\r
+                *              editor.widgets.getByElement( someWidget.wrapper, true ); // -> someWidget\r
+                *              editor.widgets.getByElement( someWidget.parts.caption, true ); // -> null\r
+                *\r
+                * @param {CKEDITOR.dom.element} element The element to be checked.\r
+                * @param {Boolean} [checkWrapperOnly] If set to `true`, the method will not check wrappers' descendants.\r
+                * @returns {CKEDITOR.plugins.widget} The widget instance or `null`.\r
+                */\r
+               getByElement: ( function() {\r
+                       var validWrapperElements = { div: 1, span: 1 };\r
+                       function getWidgetId( element ) {\r
+                               return element.is( validWrapperElements ) && element.data( 'cke-widget-id' );\r
+                       }\r
+\r
+                       return function( element, checkWrapperOnly ) {\r
+                               if ( !element )\r
+                                       return null;\r
+\r
+                               var id = getWidgetId( element );\r
+\r
+                               // There's no need to check element parents if element is a wrapper.\r
+                               if ( !checkWrapperOnly && !id ) {\r
+                                       var limit = this.editor.editable();\r
+\r
+                                       // Try to find a closest ascendant which is a widget wrapper.\r
+                                       do {\r
+                                               element = element.getParent();\r
+                                       } while ( element && !element.equals( limit ) && !( id = getWidgetId( element ) ) );\r
+                               }\r
+\r
+                               return this.instances[ id ] || null;\r
+                       };\r
+               } )(),\r
+\r
+               /**\r
+                * Initializes a widget on a given element if the widget has not been initialized on it yet.\r
+                *\r
+                * @param {CKEDITOR.dom.element} element The future widget element.\r
+                * @param {String/CKEDITOR.plugins.widget.definition} [widgetDef] Name of a widget or a widget definition.\r
+                * The widget definition should be previously registered by using the\r
+                * {@link CKEDITOR.plugins.widget.repository#add} method.\r
+                * @param [startupData] Widget startup data (has precedence over default one).\r
+                * @returns {CKEDITOR.plugins.widget} The widget instance or `null` if a widget could not be initialized on\r
+                * a given element.\r
+                */\r
+               initOn: function( element, widgetDef, startupData ) {\r
+                       if ( !widgetDef )\r
+                               widgetDef = this.registered[ element.data( 'widget' ) ];\r
+                       else if ( typeof widgetDef == 'string' )\r
+                               widgetDef = this.registered[ widgetDef ];\r
+\r
+                       if ( !widgetDef )\r
+                               return null;\r
+\r
+                       // Wrap element if still wasn't wrapped (was added during runtime by method that skips dataProcessor).\r
+                       var wrapper = this.wrapElement( element, widgetDef.name );\r
+\r
+                       if ( wrapper ) {\r
+                               // Check if widget wrapper is new (widget hasn't been initialized on it yet).\r
+                               // This class will be removed by widget constructor to avoid locking snapshot twice.\r
+                               if ( wrapper.hasClass( 'cke_widget_new' ) ) {\r
+                                       var widget = new Widget( this, this._.nextId++, element, widgetDef, startupData );\r
+\r
+                                       // Widget could be destroyed when initializing it.\r
+                                       if ( widget.isInited() ) {\r
+                                               this.instances[ widget.id ] = widget;\r
+\r
+                                               return widget;\r
+                                       } else {\r
+                                               return null;\r
+                                       }\r
+                               }\r
+\r
+                               // Widget already has been initialized, so try to get widget by element.\r
+                               // Note - it may happen that other instance will returned than the one created above,\r
+                               // if for example widget was destroyed and reinitialized.\r
+                               return this.getByElement( element );\r
+                       }\r
+\r
+                       // No wrapper means that there's no widget for this element.\r
+                       return null;\r
+               },\r
+\r
+               /**\r
+                * Initializes widgets on all elements which were wrapped by {@link #wrapElement} and\r
+                * have not been initialized yet.\r
+                *\r
+                * @param {CKEDITOR.dom.element} [container=editor.editable()] The container which will be checked for not\r
+                * initialized widgets. Defaults to editor's {@link CKEDITOR.editor#editable editable} element.\r
+                * @returns {CKEDITOR.plugins.widget[]} Array of widget instances which have been initialized.\r
+                * Note: Only first-level widgets are returned &mdash; without nested widgets.\r
+                */\r
+               initOnAll: function( container ) {\r
+                       var newWidgets = ( container || this.editor.editable() ).find( '.cke_widget_new' ),\r
+                               newInstances = [],\r
+                               instance;\r
+\r
+                       for ( var i = newWidgets.count(); i--; ) {\r
+                               instance = this.initOn( newWidgets.getItem( i ).getFirst( Widget.isDomWidgetElement ) );\r
+                               if ( instance )\r
+                                       newInstances.push( instance );\r
+                       }\r
+\r
+                       return newInstances;\r
+               },\r
+\r
+               /**\r
+                * Allows to listen to events on specific types of widgets, even if they are not created yet.\r
+                *\r
+                * Please note that this method inherits parameters from the {@link CKEDITOR.event#method-on} method with one\r
+                * extra parameter at the beginning which is the widget name.\r
+                *\r
+                *              editor.widgets.onWidget( 'image', 'action', function( evt ) {\r
+                *                      // Event `action` occurs on `image` widget.\r
+                *              } );\r
+                *\r
+                * @since 4.5\r
+                * @param {String} widgetName\r
+                * @param {String} eventName\r
+                * @param {Function} listenerFunction\r
+                * @param {Object} [scopeObj]\r
+                * @param {Object} [listenerData]\r
+                * @param {Number} [priority=10]\r
+                */\r
+               onWidget: function( widgetName ) {\r
+                       var args = Array.prototype.slice.call( arguments );\r
+\r
+                       args.shift();\r
+\r
+                       for ( var i in this.instances ) {\r
+                               var instance = this.instances[ i ];\r
+\r
+                               if ( instance.name == widgetName ) {\r
+                                       instance.on.apply( instance, args );\r
+                               }\r
+                       }\r
+\r
+                       this.on( 'instanceCreated', function( evt ) {\r
+                               var widget = evt.data;\r
+\r
+                               if ( widget.name == widgetName ) {\r
+                                       widget.on.apply( widget, args );\r
+                               }\r
+                       } );\r
+               },\r
+\r
+               /**\r
+                * Parses element classes string and returns an object\r
+                * whose keys contain class names. Skips all `cke_*` classes.\r
+                *\r
+                * This method is used by the {@link CKEDITOR.plugins.widget#getClasses} method and\r
+                * may be used when overriding that method.\r
+                *\r
+                * @since 4.4\r
+                * @param {String} classes String (value of `class` attribute).\r
+                * @returns {Object} Object containing classes or `null` if no classes found.\r
+                */\r
+               parseElementClasses: function( classes ) {\r
+                       if ( !classes )\r
+                               return null;\r
+\r
+                       classes = CKEDITOR.tools.trim( classes ).split( /\s+/ );\r
+\r
+                       var cl,\r
+                               obj = {},\r
+                               hasClasses = 0;\r
+\r
+                       while ( ( cl = classes.pop() ) ) {\r
+                               if ( cl.indexOf( 'cke_' ) == -1 )\r
+                                       obj[ cl ] = hasClasses = 1;\r
+                       }\r
+\r
+                       return hasClasses ? obj : null;\r
+               },\r
+\r
+               /**\r
+                * Wraps an element with a widget's non-editable container.\r
+                *\r
+                * If this method is called on an {@link CKEDITOR.htmlParser.element}, then it will\r
+                * also take care of fixing the DOM after wrapping (the wrapper may not be allowed in element's parent).\r
+                *\r
+                * @param {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} element The widget element to be wrapped.\r
+                * @param {String} [widgetName] The name of the widget definition. Defaults to element's `data-widget`\r
+                * attribute value.\r
+                * @returns {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} The wrapper element or `null` if\r
+                * the widget definition of this name is not registered.\r
+                */\r
+               wrapElement: function( element, widgetName ) {\r
+                       var wrapper = null,\r
+                               widgetDef,\r
+                               isInline;\r
+\r
+                       if ( element instanceof CKEDITOR.dom.element ) {\r
+                               widgetName = widgetName || element.data( 'widget' );\r
+                               widgetDef = this.registered[ widgetName ];\r
+\r
+                               if ( !widgetDef )\r
+                                       return null;\r
+\r
+                               // Do not wrap already wrapped element.\r
+                               wrapper = element.getParent();\r
+                               if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.data( 'cke-widget-wrapper' ) )\r
+                                       return wrapper;\r
+\r
+                               // If attribute isn't already set (e.g. for pasted widget), set it.\r
+                               if ( !element.hasAttribute( 'data-cke-widget-keep-attr' ) )\r
+                                       element.data( 'cke-widget-keep-attr', element.data( 'widget' ) ? 1 : 0 );\r
+\r
+                               element.data( 'widget', widgetName );\r
+\r
+                               isInline = isWidgetInline( widgetDef, element.getName() );\r
+\r
+                               wrapper = new CKEDITOR.dom.element( isInline ? 'span' : 'div' );\r
+                               wrapper.setAttributes( getWrapperAttributes( isInline, widgetName ) );\r
+\r
+                               wrapper.data( 'cke-display-name', widgetDef.pathName ? widgetDef.pathName : element.getName() );\r
+\r
+                               // Replace element unless it is a detached one.\r
+                               if ( element.getParent( true ) )\r
+                                       wrapper.replace( element );\r
+                               element.appendTo( wrapper );\r
+                       }\r
+                       else if ( element instanceof CKEDITOR.htmlParser.element ) {\r
+                               widgetName = widgetName || element.attributes[ 'data-widget' ];\r
+                               widgetDef = this.registered[ widgetName ];\r
+\r
+                               if ( !widgetDef )\r
+                                       return null;\r
+\r
+                               wrapper = element.parent;\r
+                               if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.attributes[ 'data-cke-widget-wrapper' ] )\r
+                                       return wrapper;\r
+\r
+                               // If attribute isn't already set (e.g. for pasted widget), set it.\r
+                               if ( !( 'data-cke-widget-keep-attr' in element.attributes ) )\r
+                                       element.attributes[ 'data-cke-widget-keep-attr' ] = element.attributes[ 'data-widget' ] ? 1 : 0;\r
+                               if ( widgetName )\r
+                                       element.attributes[ 'data-widget' ] = widgetName;\r
+\r
+                               isInline = isWidgetInline( widgetDef, element.name );\r
+\r
+                               wrapper = new CKEDITOR.htmlParser.element( isInline ? 'span' : 'div', getWrapperAttributes( isInline, widgetName ) );\r
+                               wrapper.attributes[ 'data-cke-display-name' ] = widgetDef.pathName ? widgetDef.pathName : element.name;\r
+\r
+                               var parent = element.parent,\r
+                                       index;\r
+\r
+                               // Don't detach already detached element.\r
+                               if ( parent ) {\r
+                                       index = element.getIndex();\r
+                                       element.remove();\r
+                               }\r
+\r
+                               wrapper.add( element );\r
+\r
+                               // Insert wrapper fixing DOM (splitting parents if wrapper is not allowed inside them).\r
+                               parent && insertElement( parent, index, wrapper );\r
+                       }\r
+\r
+                       return wrapper;\r
+               },\r
+\r
+               // Expose for tests.\r
+               _tests_createEditableFilter: createEditableFilter\r
+       };\r
+\r
+       CKEDITOR.event.implementOn( Repository.prototype );\r
+\r
+       /**\r
+        * An event fired when a widget instance is created, but before it is fully initialized.\r
+        *\r
+        * @event instanceCreated\r
+        * @param {CKEDITOR.plugins.widget} data The widget instance.\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget instance was destroyed.\r
+        *\r
+        * See also {@link CKEDITOR.plugins.widget#event-destroy}.\r
+        *\r
+        * @event instanceDestroyed\r
+        * @param {CKEDITOR.plugins.widget} data The widget instance.\r
+        */\r
+\r
+       /**\r
+        * An event fired to trigger the selection check.\r
+        *\r
+        * See the {@link #method-checkSelection} method.\r
+        *\r
+        * @event checkSelection\r
+        */\r
+\r
+       /**\r
+        * An event fired by the the {@link #method-checkWidgets} method.\r
+        *\r
+        * It can be canceled in order to stop the {@link #method-checkWidgets}\r
+        * method execution or the event listener can modify the method's options.\r
+        *\r
+        * @event checkWidgets\r
+        * @param [data]\r
+        * @param {Boolean} [data.initOnlyNew] Initialize widgets only on newly wrapped\r
+        * widget elements (those which still have the `cke_widget_new` class). When this option is\r
+        * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure)\r
+        * will not be reinitialized. This makes the check faster.\r
+        * @param {Boolean} [data.focusInited] If only one widget is initialized by\r
+        * the method, it will be focused.\r
+        */\r
+\r
+\r
+       /**\r
+        * An instance of a widget. Together with {@link CKEDITOR.plugins.widget.repository} these\r
+        * two classes constitute the core of the Widget System.\r
+        *\r
+        * Note that neither the repository nor the widget instances can be created by using their constructors.\r
+        * A repository instance is automatically set up by the Widget plugin and is accessible under\r
+        * {@link CKEDITOR.editor#widgets}, while widget instances are created and destroyed by the repository.\r
+        *\r
+        * To create a widget, first you need to {@link CKEDITOR.plugins.widget.repository#add register} its\r
+        * {@link CKEDITOR.plugins.widget.definition definition}:\r
+        *\r
+        *              editor.widgets.add( 'simplebox', {\r
+        *                      upcast: function( element ) {\r
+        *                              // Defines which elements will become widgets.\r
+        *                              if ( element.hasClass( 'simplebox' ) )\r
+        *                                      return true;\r
+        *                      },\r
+        *                      init: function() {\r
+        *                              // ...\r
+        *                      }\r
+        *              } );\r
+        *\r
+        * Once the widget definition is registered, widgets will be automatically\r
+        * created when loading data:\r
+        *\r
+        *              editor.setData( '<div class="simplebox">foo</div>', function() {\r
+        *                      console.log( editor.widgets.instances ); // -> An object containing one instance.\r
+        *              } );\r
+        *\r
+        * It is also possible to create instances during runtime by using a command\r
+        * (if a {@link CKEDITOR.plugins.widget.definition#template} property was defined):\r
+        *\r
+        *              // You can execute an automatically defined command to\r
+        *              // insert a new simplebox widget or edit the one currently focused.\r
+        *              editor.execCommand( 'simplebox' );\r
+        *\r
+        * Note: Since CKEditor 4.5 widget's `startupData` can be passed as the command argument:\r
+        *\r
+        *              editor.execCommand( 'simplebox', {\r
+        *                      startupData: {\r
+        *                              align: 'left'\r
+        *                      }\r
+        *              } );\r
+        *\r
+        * A widget can also be created in a completely custom way:\r
+        *\r
+        *              var element = editor.document.createElement( 'div' );\r
+        *              editor.insertElement( element );\r
+        *              var widget = editor.widgets.initOn( element, 'simplebox' );\r
+        *\r
+        * @since 4.3\r
+        * @class CKEDITOR.plugins.widget\r
+        * @mixins CKEDITOR.event\r
+        * @extends CKEDITOR.plugins.widget.definition\r
+        * @constructor Creates an instance of the widget class. Do not use it directly, but instead initialize widgets\r
+        * by using the {@link CKEDITOR.plugins.widget.repository#initOn} method or by the upcasting system.\r
+        * @param {CKEDITOR.plugins.widget.repository} widgetsRepo\r
+        * @param {Number} id Unique ID of this widget instance.\r
+        * @param {CKEDITOR.dom.element} element The widget element.\r
+        * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget's registered definition.\r
+        * @param [startupData] Initial widget data. This data object will overwrite the default data and\r
+        * the data loaded from the DOM.\r
+        */\r
+       function Widget( widgetsRepo, id, element, widgetDef, startupData ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               // Extend this widget with widgetDef-specific methods and properties.\r
+               CKEDITOR.tools.extend( this, widgetDef, {\r
+                       /**\r
+                        * The editor instance.\r
+                        *\r
+                        * @readonly\r
+                        * @property {CKEDITOR.editor}\r
+                        */\r
+                       editor: editor,\r
+\r
+                       /**\r
+                        * This widget's unique (per editor instance) ID.\r
+                        *\r
+                        * @readonly\r
+                        * @property {Number}\r
+                        */\r
+                       id: id,\r
+\r
+                       /**\r
+                        * Whether this widget is an inline widget (based on an inline element unless\r
+                        * forced otherwise by {@link CKEDITOR.plugins.widget.definition#inline}).\r
+                        *\r
+                        * **Note:** This option does not allow to turn a block element into an inline widget.\r
+                        * However, it makes it possible to turn an inline element into a block widget or to\r
+                        * force a correct type in case when automatic recognition fails.\r
+                        *\r
+                        * @readonly\r
+                        * @property {Boolean}\r
+                        */\r
+                       inline: element.getParent().getName() == 'span',\r
+\r
+                       /**\r
+                        * The widget element &mdash; the element on which the widget was initialized.\r
+                        *\r
+                        * @readonly\r
+                        * @property {CKEDITOR.dom.element} element\r
+                        */\r
+                       element: element,\r
+\r
+                       /**\r
+                        * Widget's data object.\r
+                        *\r
+                        * The data can only be set by using the {@link #setData} method.\r
+                        * Changes made to the data fire the {@link #event-data} event.\r
+                        *\r
+                        * @readonly\r
+                        */\r
+                       data: CKEDITOR.tools.extend( {}, typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults ),\r
+\r
+                       /**\r
+                        * Indicates if a widget is data-ready. Set to `true` when data from all sources\r
+                        * ({@link CKEDITOR.plugins.widget.definition#defaults}, set in the\r
+                        * {@link #init} method, loaded from the widget's element and startup data coming from the constructor)\r
+                        * are finally loaded. This is immediately followed by the first {@link #event-data}.\r
+                        *\r
+                        * @readonly\r
+                        */\r
+                       dataReady: false,\r
+\r
+                       /**\r
+                        * Whether a widget instance was initialized. This means that:\r
+                        *\r
+                        * * An instance was created,\r
+                        * * Its properties were set,\r
+                        * * The `init` method was executed.\r
+                        *\r
+                        * **Note**: The first {@link #event-data} event could not be fired yet which\r
+                        * means that the widget's DOM has not been set up yet. Wait for the {@link #event-ready}\r
+                        * event to be notified when a widget is fully initialized and ready.\r
+                        *\r
+                        * **Note**: Use the {@link #isInited} method to check whether a widget is initialized and\r
+                        * has not been destroyed.\r
+                        *\r
+                        * @readonly\r
+                        */\r
+                       inited: false,\r
+\r
+                       /**\r
+                        * Whether a widget instance is ready. This means that the widget is {@link #inited} and\r
+                        * that its DOM was finally set up.\r
+                        *\r
+                        * **Note:** Use the {@link #isReady} method to check whether a widget is ready and\r
+                        * has not been destroyed.\r
+                        *\r
+                        * @readonly\r
+                        */\r
+                       ready: false,\r
+\r
+                       // Revert what widgetDef could override (automatic #edit listener).\r
+                       edit: Widget.prototype.edit,\r
+\r
+                       /**\r
+                        * The nested editable element which is currently focused.\r
+                        *\r
+                        * @readonly\r
+                        * @property {CKEDITOR.plugins.widget.nestedEditable}\r
+                        */\r
+                       focusedEditable: null,\r
+\r
+                       /**\r
+                        * The widget definition from which this instance was created.\r
+                        *\r
+                        * @readonly\r
+                        * @property {CKEDITOR.plugins.widget.definition} definition\r
+                        */\r
+                       definition: widgetDef,\r
+\r
+                       /**\r
+                        * Link to the widget repository which created this instance.\r
+                        *\r
+                        * @readonly\r
+                        * @property {CKEDITOR.plugins.widget.repository} repository\r
+                        */\r
+                       repository: widgetsRepo,\r
+\r
+                       draggable: widgetDef.draggable !== false,\r
+\r
+                       // WAAARNING: Overwrite widgetDef's priv object, because otherwise violent unicorn's gonna visit you.\r
+                       _: {\r
+                               downcastFn: ( widgetDef.downcast && typeof widgetDef.downcast == 'string' ) ?\r
+                                       widgetDef.downcasts[ widgetDef.downcast ] : widgetDef.downcast\r
+                       }\r
+               }, true );\r
+\r
+               /**\r
+                * An object of widget component elements.\r
+                *\r
+                * For every `partName => selector` pair in {@link CKEDITOR.plugins.widget.definition#parts},\r
+                * one `partName => element` pair is added to this object during the widget initialization.\r
+                *\r
+                * @readonly\r
+                * @property {Object} parts\r
+                */\r
+\r
+               /**\r
+                * The template which will be used to create a new widget element (when the widget's command is executed).\r
+                * It will be populated with {@link #defaults default values}.\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.template} template\r
+                */\r
+\r
+               /**\r
+                * The widget wrapper &mdash; a non-editable `div` or `span` element (depending on {@link #inline})\r
+                * which is a parent of the {@link #element} and widget compontents like the drag handler and the {@link #mask}.\r
+                * It is the outermost widget element.\r
+                *\r
+                * @readonly\r
+                * @property {CKEDITOR.dom.element} wrapper\r
+                */\r
+\r
+               widgetsRepo.fire( 'instanceCreated', this );\r
+\r
+               setupWidget( this, widgetDef );\r
+\r
+               this.init && this.init();\r
+\r
+               // Finally mark widget as inited.\r
+               this.inited = true;\r
+\r
+               setupWidgetData( this, startupData );\r
+\r
+               // If at some point (e.g. in #data listener) widget hasn't been destroyed\r
+               // and widget is already attached to document then fire #ready.\r
+               if ( this.isInited() && editor.editable().contains( this.wrapper ) ) {\r
+                       this.ready = true;\r
+                       this.fire( 'ready' );\r
+               }\r
+       }\r
+\r
+       Widget.prototype = {\r
+               /**\r
+                * Adds a class to the widget element. This method is used by\r
+                * the {@link #applyStyle} method and should be overridden by widgets\r
+                * which should handle classes differently (e.g. add them to other elements).\r
+                *\r
+                * Since 4.6.0 this method also adds a corresponding class prefixed with {@link #WRAPPER_CLASS_PREFIX}\r
+                * to the widget wrapper element.\r
+                *\r
+                * **Note**: This method should not be used directly. Use the {@link #setData} method to\r
+                * set the `classes` property. Read more in the {@link #setData} documentation.\r
+                *\r
+                * See also: {@link #removeClass}, {@link #hasClass}, {@link #getClasses}.\r
+                *\r
+                * @since 4.4\r
+                * @param {String} className The class name to be added.\r
+                */\r
+               addClass: function( className ) {\r
+                       this.element.addClass( className );\r
+                       this.wrapper.addClass( Widget.WRAPPER_CLASS_PREFIX + className );\r
+               },\r
+\r
+               /**\r
+                * Applies the specified style to the widget. It is highly recommended to use the\r
+                * {@link CKEDITOR.editor#applyStyle} or {@link CKEDITOR.style#apply} methods instead of\r
+                * using this method directly, because unlike editor's and style's methods, this one\r
+                * does not perform any checks.\r
+                *\r
+                * By default this method handles only classes defined in the style. It clones existing\r
+                * classes which are stored in the {@link #property-data widget data}'s `classes` property,\r
+                * adds new classes, and calls the {@link #setData} method if at least one new class was added.\r
+                * Then, using the {@link #event-data} event listener widget applies modifications passing\r
+                * new classes to the {@link #addClass} method.\r
+                *\r
+                * If you need to handle classes differently than in the default way, you can override the\r
+                * {@link #addClass} and related methods. You can also handle other style properties than `classes`\r
+                * by overriding this method.\r
+                *\r
+                * See also: {@link #checkStyleActive}, {@link #removeStyle}.\r
+                *\r
+                * @since 4.4\r
+                * @param {CKEDITOR.style} style The custom widget style to be applied.\r
+                */\r
+               applyStyle: function( style ) {\r
+                       applyRemoveStyle( this, style, 1 );\r
+               },\r
+\r
+               /**\r
+                * Checks if the specified style is applied to this widget. It is highly recommended to use the\r
+                * {@link CKEDITOR.style#checkActive} method instead of using this method directly,\r
+                * because unlike style's method, this one does not perform any checks.\r
+                *\r
+                * By default this method handles only classes defined in the style and passes\r
+                * them to the {@link #hasClass} method. You can override these methods to handle classes\r
+                * differently or to handle more of the style properties.\r
+                *\r
+                * See also: {@link #applyStyle}, {@link #removeStyle}.\r
+                *\r
+                * @since 4.4\r
+                * @param {CKEDITOR.style} style The custom widget style to be checked.\r
+                * @returns {Boolean} Whether the style is applied to this widget.\r
+                */\r
+               checkStyleActive: function( style ) {\r
+                       var classes = getStyleClasses( style ),\r
+                               cl;\r
+\r
+                       if ( !classes )\r
+                               return false;\r
+\r
+                       while ( ( cl = classes.pop() ) ) {\r
+                               if ( !this.hasClass( cl ) )\r
+                                       return false;\r
+                       }\r
+                       return true;\r
+               },\r
+\r
+               /**\r
+                * Destroys this widget instance.\r
+                *\r
+                * Use {@link CKEDITOR.plugins.widget.repository#destroy} when possible instead of this method.\r
+                *\r
+                * This method fires the {#event-destroy} event.\r
+                *\r
+                * @param {Boolean} [offline] Whether a widget is offline (detached from the DOM tree) &mdash;\r
+                * in this case the DOM (attributes, classes, etc.) will not be cleaned up.\r
+                */\r
+               destroy: function( offline ) {\r
+                       this.fire( 'destroy' );\r
+\r
+                       if ( this.editables ) {\r
+                               for ( var name in this.editables )\r
+                                       this.destroyEditable( name, offline );\r
+                       }\r
+\r
+                       if ( !offline ) {\r
+                               if ( this.element.data( 'cke-widget-keep-attr' ) == '0' )\r
+                                       this.element.removeAttribute( 'data-widget' );\r
+                               this.element.removeAttributes( [ 'data-cke-widget-data', 'data-cke-widget-keep-attr' ] );\r
+                               this.element.removeClass( 'cke_widget_element' );\r
+                               this.element.replace( this.wrapper );\r
+                       }\r
+\r
+                       this.wrapper = null;\r
+               },\r
+\r
+               /**\r
+                * Destroys a nested editable and all nested widgets.\r
+                *\r
+                * @param {String} editableName Nested editable name.\r
+                * @param {Boolean} [offline] See {@link #method-destroy} method.\r
+                */\r
+               destroyEditable: function( editableName, offline ) {\r
+                       var editable = this.editables[ editableName ];\r
+\r
+                       editable.removeListener( 'focus', onEditableFocus );\r
+                       editable.removeListener( 'blur', onEditableBlur );\r
+                       this.editor.focusManager.remove( editable );\r
+\r
+                       if ( !offline ) {\r
+                               this.repository.destroyAll( false, editable );\r
+                               editable.removeClass( 'cke_widget_editable' );\r
+                               editable.removeClass( 'cke_widget_editable_focused' );\r
+                               editable.removeAttributes( [ 'contenteditable', 'data-cke-widget-editable', 'data-cke-enter-mode' ] );\r
+                       }\r
+\r
+                       delete this.editables[ editableName ];\r
+               },\r
+\r
+               /**\r
+                * Starts widget editing.\r
+                *\r
+                * This method fires the {@link CKEDITOR.plugins.widget#event-edit} event\r
+                * which may be canceled in order to prevent it from opening a dialog window.\r
+                *\r
+                * The dialog window name is obtained from the event's data `dialog` property or\r
+                * from {@link CKEDITOR.plugins.widget.definition#dialog}.\r
+                *\r
+                * @returns {Boolean} Returns `true` if a dialog window was opened.\r
+                */\r
+               edit: function() {\r
+                       var evtData = { dialog: this.dialog },\r
+                               that = this;\r
+\r
+                       // Edit event was blocked or there's no dialog to be automatically opened.\r
+                       if ( this.fire( 'edit', evtData ) === false || !evtData.dialog )\r
+                               return false;\r
+\r
+                       this.editor.openDialog( evtData.dialog, function( dialog ) {\r
+                               var showListener,\r
+                                       okListener;\r
+\r
+                               // Allow to add a custom dialog handler.\r
+                               if ( that.fire( 'dialog', dialog ) === false )\r
+                                       return;\r
+\r
+                               showListener = dialog.on( 'show', function() {\r
+                                       dialog.setupContent( that );\r
+                               } );\r
+\r
+                               okListener = dialog.on( 'ok', function() {\r
+                                       // Commit dialog's fields, but prevent from\r
+                                       // firing data event for every field. Fire only one,\r
+                                       // bulk event at the end.\r
+                                       var dataChanged,\r
+                                               dataListener = that.on( 'data', function( evt ) {\r
+                                                       dataChanged = 1;\r
+                                                       evt.cancel();\r
+                                               }, null, null, 0 );\r
+\r
+                                       // Create snapshot preceeding snapshot with changed widget...\r
+                                       // TODO it should not be required, but it is and I found similar\r
+                                       // code in dialog#ok listener in dialog/plugin.js.\r
+                                       that.editor.fire( 'saveSnapshot' );\r
+                                       dialog.commitContent( that );\r
+\r
+                                       dataListener.removeListener();\r
+                                       if ( dataChanged ) {\r
+                                               that.fire( 'data', that.data );\r
+                                               that.editor.fire( 'saveSnapshot' );\r
+                                       }\r
+                               } );\r
+\r
+                               dialog.once( 'hide', function() {\r
+                                       showListener.removeListener();\r
+                                       okListener.removeListener();\r
+                               } );\r
+                       } );\r
+\r
+                       return true;\r
+               },\r
+\r
+               /**\r
+                * Returns widget element classes parsed to an object. This method\r
+                * is used to populate the `classes` property of widget's {@link #property-data}.\r
+                *\r
+                * This method reuses {@link CKEDITOR.plugins.widget.repository#parseElementClasses}.\r
+                * It should be overriden if a widget should handle classes differently (e.g. on other elements).\r
+                *\r
+                * See also: {@link #removeClass}, {@link #addClass}, {@link #hasClass}.\r
+                *\r
+                * @since 4.4\r
+                * @returns {Object}\r
+                */\r
+               getClasses: function() {\r
+                       return this.repository.parseElementClasses( this.element.getAttribute( 'class' ) );\r
+               },\r
+\r
+               /**\r
+                * Checks if the widget element has specified class. This method is used by\r
+                * the {@link #checkStyleActive} method and should be overriden by widgets\r
+                * which should handle classes differently (e.g. on other elements).\r
+                *\r
+                * See also: {@link #removeClass}, {@link #addClass}, {@link #getClasses}.\r
+                *\r
+                * @since 4.4\r
+                * @param {String} className The class to be checked.\r
+                * @param {Boolean} Whether a widget has specified class.\r
+                */\r
+               hasClass: function( className ) {\r
+                       return this.element.hasClass( className );\r
+               },\r
+\r
+               /**\r
+                * Initializes a nested editable.\r
+                *\r
+                * **Note**: Only elements from {@link CKEDITOR.dtd#$editable} may become editables.\r
+                *\r
+                * @param {String} editableName The nested editable name.\r
+                * @param {CKEDITOR.plugins.widget.nestedEditable.definition} definition The definition of the nested editable.\r
+                * @returns {Boolean} Whether an editable was successfully initialized.\r
+                */\r
+               initEditable: function( editableName, definition ) {\r
+                       // Don't fetch just first element which matched selector but look for a correct one. (http://dev.ckeditor.com/ticket/13334)\r
+                       var editable = this._findOneNotNested( definition.selector );\r
+\r
+                       if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) {\r
+                               editable = new NestedEditable( this.editor, editable, {\r
+                                       filter: createEditableFilter.call( this.repository, this.name, editableName, definition )\r
+                               } );\r
+                               this.editables[ editableName ] = editable;\r
+\r
+                               editable.setAttributes( {\r
+                                       contenteditable: 'true',\r
+                                       'data-cke-widget-editable': editableName,\r
+                                       'data-cke-enter-mode': editable.enterMode\r
+                               } );\r
+\r
+                               if ( editable.filter )\r
+                                       editable.data( 'cke-filter', editable.filter.id );\r
+\r
+                               editable.addClass( 'cke_widget_editable' );\r
+                               // This class may be left when d&ding widget which\r
+                               // had focused editable. Clean this class here, not in\r
+                               // cleanUpWidgetElement for performance and code size reasons.\r
+                               editable.removeClass( 'cke_widget_editable_focused' );\r
+\r
+                               if ( definition.pathName )\r
+                                       editable.data( 'cke-display-name', definition.pathName );\r
+\r
+                               this.editor.focusManager.add( editable );\r
+                               editable.on( 'focus', onEditableFocus, this );\r
+                               CKEDITOR.env.ie && editable.on( 'blur', onEditableBlur, this );\r
+\r
+                               // Finally, process editable's data. This data wasn't processed when loading\r
+                               // editor's data, becuase they need to be processed separately, with its own filters and settings.\r
+                               editable._.initialSetData = true;\r
+                               editable.setData( editable.getHtml() );\r
+\r
+                               return true;\r
+                       }\r
+\r
+                       return false;\r
+               },\r
+\r
+               /**\r
+                * Looks inside wrapper element to find a node that\r
+                * matches given selector and is not nested in other widget. (http://dev.ckeditor.com/ticket/13334)\r
+                *\r
+                * @since 4.5\r
+                * @private\r
+                * @param {String} selector Selector to match.\r
+                * @returns {CKEDITOR.dom.element} Matched element or `null` if a node has not been found.\r
+                */\r
+               _findOneNotNested: function( selector ) {\r
+                       var matchedElements = this.wrapper.find( selector ),\r
+                               match,\r
+                               closestWrapper;\r
+\r
+                       for ( var i = 0; i < matchedElements.count(); i++ ) {\r
+                               match = matchedElements.getItem( i );\r
+                               closestWrapper = match.getAscendant( Widget.isDomWidgetWrapper );\r
+\r
+                               // The closest ascendant-wrapper of this match defines to which widget\r
+                               // this match belongs. If the ascendant is this widget's wrapper\r
+                               // it means that the match is not nested in other widget.\r
+                               if ( this.wrapper.equals( closestWrapper ) ) {\r
+                                       return match;\r
+                               }\r
+                       }\r
+\r
+                       return null;\r
+               },\r
+\r
+               /**\r
+                * Checks if a widget has already been initialized and has not been destroyed yet.\r
+                *\r
+                * See {@link #inited} for more details.\r
+                *\r
+                * @returns {Boolean}\r
+                */\r
+               isInited: function() {\r
+                       return !!( this.wrapper && this.inited );\r
+               },\r
+\r
+               /**\r
+                * Checks if a widget is ready and has not been destroyed yet.\r
+                *\r
+                * See {@link #property-ready} for more details.\r
+                *\r
+                * @returns {Boolean}\r
+                */\r
+               isReady: function() {\r
+                       return this.isInited() && this.ready;\r
+               },\r
+\r
+               /**\r
+                * Focuses a widget by selecting it.\r
+                */\r
+               focus: function() {\r
+                       var sel = this.editor.getSelection();\r
+\r
+                       // Fake the selection before focusing editor, to avoid unpreventable viewports scrolling\r
+                       // on Webkit/Blink/IE which is done because there's no selection or selection was somewhere else than widget.\r
+                       if ( sel ) {\r
+                               var isDirty = this.editor.checkDirty();\r
+\r
+                               sel.fake( this.wrapper );\r
+\r
+                               !isDirty && this.editor.resetDirty();\r
+                       }\r
+\r
+                       // Always focus editor (not only when focusManger.hasFocus is false) (because of http://dev.ckeditor.com/ticket/10483).\r
+                       this.editor.focus();\r
+               },\r
+\r
+               /**\r
+                * Removes a class from the widget element. This method is used by\r
+                * the {@link #removeStyle} method and should be overriden by widgets\r
+                * which should handle classes differently (e.g. on other elements).\r
+                *\r
+                * **Note**: This method should not be used directly. Use the {@link #setData} method to\r
+                * set the `classes` property. Read more in the {@link #setData} documentation.\r
+                *\r
+                * See also: {@link #hasClass}, {@link #addClass}.\r
+                *\r
+                * @since 4.4\r
+                * @param {String} className The class to be removed.\r
+                */\r
+               removeClass: function( className ) {\r
+                       this.element.removeClass( className );\r
+                       this.wrapper.removeClass( Widget.WRAPPER_CLASS_PREFIX + className );\r
+               },\r
+\r
+               /**\r
+                * Removes the specified style from the widget. It is highly recommended to use the\r
+                * {@link CKEDITOR.editor#removeStyle} or {@link CKEDITOR.style#remove} methods instead of\r
+                * using this method directly, because unlike editor's and style's methods, this one\r
+                * does not perform any checks.\r
+                *\r
+                * Read more about how applying/removing styles works in the {@link #applyStyle} method documentation.\r
+                *\r
+                * See also {@link #checkStyleActive}, {@link #applyStyle}, {@link #getClasses}.\r
+                *\r
+                * @since 4.4\r
+                * @param {CKEDITOR.style} style The custom widget style to be removed.\r
+                */\r
+               removeStyle: function( style ) {\r
+                       applyRemoveStyle( this, style, 0 );\r
+               },\r
+\r
+               /**\r
+                * Sets widget value(s) in the {@link #property-data} object.\r
+                * If the given value(s) modifies current ones, the {@link #event-data} event is fired.\r
+                *\r
+                *              this.setData( 'align', 'left' );\r
+                *              this.data.align; // -> 'left'\r
+                *\r
+                *              this.setData( { align: 'right', opened: false } );\r
+                *              this.data.align; // -> 'right'\r
+                *              this.data.opened; // -> false\r
+                *\r
+                * Set values are stored in {@link #element}'s attribute (`data-cke-widget-data`),\r
+                * in a JSON string, therefore {@link #property-data} should contain\r
+                * only serializable data.\r
+                *\r
+                * **Note:** A special data property, `classes`, exists. It contains an object with\r
+                * classes which were returned by the {@link #getClasses} method during the widget initialization.\r
+                * This property is then used by the {@link #applyStyle} and {@link #removeStyle} methods.\r
+                * When it is changed (the reference to object must be changed!), the widget updates its classes by\r
+                * using the {@link #addClass} and {@link #removeClass} methods.\r
+                *\r
+                *              // Adding a new class.\r
+                *              var classes = CKEDITOR.tools.clone( widget.data.classes );\r
+                *              classes.newClass = 1;\r
+                *              widget.setData( 'classes', classes );\r
+                *\r
+                *              // Removing a class.\r
+                *              var classes = CKEDITOR.tools.clone( widget.data.classes );\r
+                *              delete classes.newClass;\r
+                *              widget.setData( 'classes', classes );\r
+                *\r
+                * @param {String/Object} keyOrData\r
+                * @param {Object} value\r
+                * @chainable\r
+                */\r
+               setData: function( key, value ) {\r
+                       var data = this.data,\r
+                               modified = 0;\r
+\r
+                       if ( typeof key == 'string' ) {\r
+                               if ( data[ key ] !== value ) {\r
+                                       data[ key ] = value;\r
+                                       modified = 1;\r
+                               }\r
+                       }\r
+                       else {\r
+                               var newData = key;\r
+\r
+                               for ( key in newData ) {\r
+                                       if ( data[ key ] !== newData[ key ] ) {\r
+                                               modified = 1;\r
+                                               data[ key ] = newData[ key ];\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // Block firing data event and overwriting data element before setupWidgetData is executed.\r
+                       if ( modified && this.dataReady ) {\r
+                               writeDataToElement( this );\r
+                               this.fire( 'data', data );\r
+                       }\r
+\r
+                       return this;\r
+               },\r
+\r
+               /**\r
+                * Changes the widget's focus state. This method is executed automatically after\r
+                * a widget was focused by the {@link #method-focus} method or the selection was moved\r
+                * out of the widget.\r
+                *\r
+                * This is a low-level method which is not integrated with e.g. the undo manager.\r
+                * Use the {@link #method-focus} method instead.\r
+                *\r
+                * @param {Boolean} selected Whether to select or deselect this widget.\r
+                * @chainable\r
+                */\r
+               setFocused: function( focused ) {\r
+                       this.wrapper[ focused ? 'addClass' : 'removeClass' ]( 'cke_widget_focused' );\r
+                       this.fire( focused ? 'focus' : 'blur' );\r
+                       return this;\r
+               },\r
+\r
+               /**\r
+                * Changes the widget's select state. This method is executed automatically after\r
+                * a widget was selected by the {@link #method-focus} method or the selection\r
+                * was moved out of the widget.\r
+                *\r
+                * This is a low-level method which is not integrated with e.g. the undo manager.\r
+                * Use the {@link #method-focus} method instead or simply change the selection.\r
+                *\r
+                * @param {Boolean} selected Whether to select or deselect this widget.\r
+                * @chainable\r
+                */\r
+               setSelected: function( selected ) {\r
+                       this.wrapper[ selected ? 'addClass' : 'removeClass' ]( 'cke_widget_selected' );\r
+                       this.fire(  selected ? 'select' : 'deselect' );\r
+                       return this;\r
+               },\r
+\r
+               /**\r
+                * Repositions drag handler according to the widget's element position. Should be called from events, like mouseover.\r
+                */\r
+               updateDragHandlerPosition: function() {\r
+                       var editor = this.editor,\r
+                               domElement = this.element.$,\r
+                               oldPos = this._.dragHandlerOffset,\r
+                               newPos = {\r
+                                       x: domElement.offsetLeft,\r
+                                       y: domElement.offsetTop - DRAG_HANDLER_SIZE\r
+                               };\r
+\r
+                       if ( oldPos && newPos.x == oldPos.x && newPos.y == oldPos.y )\r
+                               return;\r
+\r
+                       // We need to make sure that dirty state is not changed (http://dev.ckeditor.com/ticket/11487).\r
+                       var initialDirty = editor.checkDirty();\r
+\r
+                       editor.fire( 'lockSnapshot' );\r
+                       this.dragHandlerContainer.setStyles( {\r
+                               top: newPos.y + 'px',\r
+                               left: newPos.x + 'px',\r
+                               display: 'block'\r
+                       } );\r
+                       editor.fire( 'unlockSnapshot' );\r
+                       !initialDirty && editor.resetDirty();\r
+\r
+                       this._.dragHandlerOffset = newPos;\r
+               }\r
+       };\r
+\r
+       CKEDITOR.event.implementOn( Widget.prototype );\r
+\r
+       /**\r
+        * Gets the {@link #isDomNestedEditable nested editable}\r
+        * (returned as a {@link CKEDITOR.dom.element}, not as a {@link CKEDITOR.plugins.widget.nestedEditable})\r
+        * closest to the `node` or the `node` if it is a nested editable itself.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.element} guard Stop ancestor search on this node (usually editor's editable).\r
+        * @param {CKEDITOR.dom.node} node Start the search from this node.\r
+        * @returns {CKEDITOR.dom.element/null} Element or `null` if not found.\r
+        */\r
+       Widget.getNestedEditable = function( guard, node ) {\r
+               if ( !node || node.equals( guard ) )\r
+                       return null;\r
+\r
+               if ( Widget.isDomNestedEditable( node ) )\r
+                       return node;\r
+\r
+               return Widget.getNestedEditable( guard, node.getParent() );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a widget's drag handle element.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.node} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isDomDragHandler = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-drag-handler' );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a container of the widget's drag handle element.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.node} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isDomDragHandlerContainer = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_widget_drag_handler_container' );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#editables nested editable}.\r
+        * Note that this function only checks whether it is the right element, not whether\r
+        * the passed `node` is an instance of {@link CKEDITOR.plugins.widget.nestedEditable}.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.node} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isDomNestedEditable = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-editable' );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.node} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isDomWidgetElement = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-widget' );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.dom.element} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isDomWidgetWrapper = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-wrapper' );\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.htmlParser.node} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isParserWidgetElement = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-widget' ];\r
+       };\r
+\r
+       /**\r
+        * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}.\r
+        *\r
+        * @since 4.5\r
+        * @static\r
+        * @param {CKEDITOR.htmlParser.element} node\r
+        * @returns {Boolean}\r
+        */\r
+       Widget.isParserWidgetWrapper = function( node ) {\r
+               return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-cke-widget-wrapper' ];\r
+       };\r
+\r
+       /**\r
+        * Prefix added to wrapper classes. Each class added to the widget element by the {@link #addClass}\r
+        * method will also be added to the wrapper prefixed with it.\r
+        *\r
+        * @since 4.6.0\r
+        * @static\r
+        * @readonly\r
+        * @property {String} [='cke_widget_wrapper_']\r
+        */\r
+       Widget.WRAPPER_CLASS_PREFIX = 'cke_widget_wrapper_';\r
+\r
+       /**\r
+        * An event fired when a widget is ready (fully initialized). This event is fired after:\r
+        *\r
+        * * {@link #init} is called,\r
+        * * The first {@link #event-data} event is fired,\r
+        * * A widget is attached to the document.\r
+        *\r
+        * Therefore, in case of widget creation with a command which opens a dialog window, this event\r
+        * will be delayed after the dialog window is closed and the widget is finally inserted into the document.\r
+        *\r
+        * **Note**: If your widget does not use automatic dialog window binding (i.e. you open the dialog window manually)\r
+        * or another situation in which the widget wrapper is not attached to document at the time when it is\r
+        * initialized occurs, you need to take care of firing {@link #event-ready} yourself.\r
+        *\r
+        * See also {@link #property-ready} and {@link #property-inited} properties, and\r
+        * {@link #isReady} and {@link #isInited} methods.\r
+        *\r
+        * @event ready\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is about to be destroyed, but before it is\r
+        * fully torn down.\r
+        *\r
+        * @event destroy\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is focused.\r
+        *\r
+        * Widget can be focused by executing {@link #method-focus}.\r
+        *\r
+        * @event focus\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is blurred.\r
+        *\r
+        * @event blur\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is selected.\r
+        *\r
+        * @event select\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is deselected.\r
+        *\r
+        * @event deselect\r
+        */\r
+\r
+       /**\r
+        * An event fired by the {@link #method-edit} method. It can be canceled\r
+        * in order to stop the default action (opening a dialog window and/or\r
+        * {@link CKEDITOR.plugins.widget.repository#finalizeCreation finalizing widget creation}).\r
+        *\r
+        * @event edit\r
+        * @param data\r
+        * @param {String} data.dialog Defaults to {@link CKEDITOR.plugins.widget.definition#dialog}\r
+        * and can be changed or set by the listener.\r
+        */\r
+\r
+       /**\r
+        * An event fired when a dialog window for widget editing is opened.\r
+        * This event can be canceled in order to handle the editing dialog in a custom manner.\r
+        *\r
+        * @event dialog\r
+        * @param {CKEDITOR.dialog} data The opened dialog window instance.\r
+        */\r
+\r
+       /**\r
+        * An event fired when a key is pressed on a focused widget.\r
+        * This event is forwarded from the {@link CKEDITOR.editor#key} event and\r
+        * has the ability to block editor keystrokes if it is canceled.\r
+        *\r
+        * @event key\r
+        * @param data\r
+        * @param {Number} data.keyCode A number representing the key code (or combination).\r
+        */\r
+\r
+       /**\r
+        * An event fired when a widget is double clicked.\r
+        *\r
+        * **Note:** If a default editing action is executed on double click (i.e. a widget has a\r
+        * {@link CKEDITOR.plugins.widget.definition#dialog dialog} defined and the {@link #event-doubleclick} event was not\r
+        * canceled), this event will be automatically canceled, so a listener added with the default priority (10)\r
+        * will not be executed. Use a listener with low priority (e.g. 5) to be sure that it will be executed.\r
+        *\r
+        *              widget.on( 'doubleclick', function( evt ) {\r
+        *                      console.log( 'widget#doubleclick' );\r
+        *              }, null, null, 5 );\r
+        *\r
+        * If your widget handles double click in a special way (so the default editing action is not executed),\r
+        * make sure you cancel this event, because otherwise it will be propagated to {@link CKEDITOR.editor#doubleclick}\r
+        * and another feature may step in (e.g. a Link dialog window may be opened if your widget was inside a link).\r
+        *\r
+        * @event doubleclick\r
+        * @param data\r
+        * @param {CKEDITOR.dom.element} data.element The double-clicked element.\r
+        */\r
+\r
+       /**\r
+        * An event fired when the context menu is opened for a widget.\r
+        *\r
+        * @event contextMenu\r
+        * @param data The object containing context menu options to be added\r
+        * for this widget. See {@link CKEDITOR.plugins.contextMenu#addListener}.\r
+        */\r
+\r
+       /**\r
+        * An event fired when the widget data changed. See the {@link #setData} method and the {@link #property-data} property.\r
+        *\r
+        * @event data\r
+        */\r
+\r
+\r
+\r
+       /**\r
+        * The wrapper class for editable elements inside widgets.\r
+        *\r
+        * Do not use directly. Use {@link CKEDITOR.plugins.widget.definition#editables} or\r
+        * {@link CKEDITOR.plugins.widget#initEditable}.\r
+        *\r
+        * @class CKEDITOR.plugins.widget.nestedEditable\r
+        * @extends CKEDITOR.dom.element\r
+        * @constructor\r
+        * @param {CKEDITOR.editor} editor\r
+        * @param {CKEDITOR.dom.element} element\r
+        * @param config\r
+        * @param {CKEDITOR.filter} [config.filter]\r
+        */\r
+       function NestedEditable( editor, element, config ) {\r
+               // Call the base constructor.\r
+               CKEDITOR.dom.element.call( this, element.$ );\r
+               this.editor = editor;\r
+               this._ = {};\r
+               var filter = this.filter = config.filter;\r
+\r
+               // If blockless editable - always use BR mode.\r
+               if ( !CKEDITOR.dtd[ this.getName() ].p )\r
+                       this.enterMode = this.shiftEnterMode = CKEDITOR.ENTER_BR;\r
+               else {\r
+                       this.enterMode = filter ? filter.getAllowedEnterMode( editor.enterMode ) : editor.enterMode;\r
+                       this.shiftEnterMode = filter ? filter.getAllowedEnterMode( editor.shiftEnterMode, true ) : editor.shiftEnterMode;\r
+               }\r
+       }\r
+\r
+       NestedEditable.prototype = CKEDITOR.tools.extend( CKEDITOR.tools.prototypedCopy( CKEDITOR.dom.element.prototype ), {\r
+               /**\r
+                * Sets the editable data. The data will be passed through the {@link CKEDITOR.editor#dataProcessor}\r
+                * and the {@link CKEDITOR.editor#filter}. This ensures that the data was filtered and prepared to be\r
+                * edited like the {@link CKEDITOR.editor#method-setData editor data}.\r
+                *\r
+                * Before content is changed, all nested widgets are destroyed. Afterwards, after new content is loaded,\r
+                * all nested widgets are initialized.\r
+                *\r
+                * @param {String} data\r
+                */\r
+               setData: function( data ) {\r
+                       // For performance reasons don't call destroyAll when initializing a nested editable,\r
+                       // because there are no widgets inside.\r
+                       if ( !this._.initialSetData ) {\r
+                               // Destroy all nested widgets before setting data.\r
+                               this.editor.widgets.destroyAll( false, this );\r
+                       }\r
+                       this._.initialSetData = false;\r
+\r
+                       data = this.editor.dataProcessor.toHtml( data, {\r
+                               context: this.getName(),\r
+                               filter: this.filter,\r
+                               enterMode: this.enterMode\r
+                       } );\r
+                       this.setHtml( data );\r
+\r
+                       this.editor.widgets.initOnAll( this );\r
+               },\r
+\r
+               /**\r
+                * Gets the editable data. Like {@link #setData}, this method will process and filter the data.\r
+                *\r
+                * @returns {String}\r
+                */\r
+               getData: function() {\r
+                       return this.editor.dataProcessor.toDataFormat( this.getHtml(), {\r
+                               context: this.getName(),\r
+                               filter: this.filter,\r
+                               enterMode: this.enterMode\r
+                       } );\r
+               }\r
+       } );\r
+\r
+       /**\r
+        * The editor instance.\r
+        *\r
+        * @readonly\r
+        * @property {CKEDITOR.editor} editor\r
+        */\r
+\r
+       /**\r
+        * The filter instance if allowed content rules were defined.\r
+        *\r
+        * @readonly\r
+        * @property {CKEDITOR.filter} filter\r
+        */\r
+\r
+       /**\r
+        * The enter mode active in this editable.\r
+        * It is determined from editable's name (whether it is a blockless editable),\r
+        * its allowed content rules (if defined) and the default editor's mode.\r
+        *\r
+        * @readonly\r
+        * @property {Number} enterMode\r
+        */\r
+\r
+       /**\r
+        * The shift enter move active in this editable.\r
+        *\r
+        * @readonly\r
+        * @property {Number} shiftEnterMode\r
+        */\r
+\r
+\r
+       //\r
+       // REPOSITORY helpers -----------------------------------------------------\r
+       //\r
+\r
+       function addWidgetButtons( editor ) {\r
+               var widgets = editor.widgets.registered,\r
+                       widget,\r
+                       widgetName,\r
+                       widgetButton;\r
+\r
+               for ( widgetName in widgets ) {\r
+                       widget = widgets[ widgetName ];\r
+\r
+                       // Create button if defined.\r
+                       widgetButton = widget.button;\r
+                       if ( widgetButton && editor.ui.addButton ) {\r
+                               editor.ui.addButton( CKEDITOR.tools.capitalize( widget.name, true ), {\r
+                                       label: widgetButton,\r
+                                       command: widget.name,\r
+                                       toolbar: 'insert,10'\r
+                               } );\r
+                       }\r
+               }\r
+       }\r
+\r
+       // Create a command creating and editing widget.\r
+       //\r
+       // @param editor\r
+       // @param {CKEDITOR.plugins.widget.definition} widgetDef\r
+       function addWidgetCommand( editor, widgetDef ) {\r
+               editor.addCommand( widgetDef.name, {\r
+                       exec: function( editor, commandData ) {\r
+                               var focused = editor.widgets.focused;\r
+                               // If a widget of the same type is focused, start editing.\r
+                               if ( focused && focused.name == widgetDef.name )\r
+                                       focused.edit();\r
+                               // Otherwise...\r
+                               // ... use insert method is was defined.\r
+                               else if ( widgetDef.insert )\r
+                                       widgetDef.insert();\r
+                               // ... or create a brand-new widget from template.\r
+                               else if ( widgetDef.template ) {\r
+                                       var defaults = typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults,\r
+                                               element = CKEDITOR.dom.element.createFromHtml( widgetDef.template.output( defaults ) ),\r
+                                               instance,\r
+                                               wrapper = editor.widgets.wrapElement( element, widgetDef.name ),\r
+                                               temp = new CKEDITOR.dom.documentFragment( wrapper.getDocument() );\r
+\r
+                                       // Append wrapper to a temporary document. This will unify the environment\r
+                                       // in which #data listeners work when creating and editing widget.\r
+                                       temp.append( wrapper );\r
+                                       instance = editor.widgets.initOn( element, widgetDef, commandData && commandData.startupData );\r
+\r
+                                       // Instance could be destroyed during initialization.\r
+                                       // In this case finalize creation if some new widget\r
+                                       // was left in temporary document fragment.\r
+                                       if ( !instance ) {\r
+                                               finalizeCreation();\r
+                                               return;\r
+                                       }\r
+\r
+                                       // Listen on edit to finalize widget insertion.\r
+                                       //\r
+                                       // * If dialog was set, then insert widget after dialog was successfully saved or destroy this\r
+                                       // temporary instance.\r
+                                       // * If dialog wasn't set and edit wasn't canceled, insert widget.\r
+                                       var editListener = instance.once( 'edit', function( evt ) {\r
+                                               if ( evt.data.dialog ) {\r
+                                                       instance.once( 'dialog', function( evt ) {\r
+                                                               var dialog = evt.data,\r
+                                                                       okListener,\r
+                                                                       cancelListener;\r
+\r
+                                                               // Finalize creation AFTER (20) new data was set.\r
+                                                               okListener = dialog.once( 'ok', finalizeCreation, null, null, 20 );\r
+\r
+                                                               cancelListener = dialog.once( 'cancel', function( evt ) {\r
+                                                                       if ( !( evt.data && evt.data.hide === false ) ) {\r
+                                                                               editor.widgets.destroy( instance, true );\r
+                                                                       }\r
+                                                               } );\r
+\r
+                                                               dialog.once( 'hide', function() {\r
+                                                                       okListener.removeListener();\r
+                                                                       cancelListener.removeListener();\r
+                                                               } );\r
+                                                       } );\r
+                                               } else {\r
+                                                       // Dialog hasn't been set, so insert widget now.\r
+                                                       finalizeCreation();\r
+                                               }\r
+                                       }, null, null, 999 );\r
+\r
+                                       instance.edit();\r
+\r
+                                       // Remove listener in case someone canceled it before this\r
+                                       // listener was executed.\r
+                                       editListener.removeListener();\r
+                               }\r
+\r
+                               function finalizeCreation() {\r
+                                       editor.widgets.finalizeCreation( temp );\r
+                               }\r
+                       },\r
+\r
+                       allowedContent: widgetDef.allowedContent,\r
+                       requiredContent: widgetDef.requiredContent,\r
+                       contentForms: widgetDef.contentForms,\r
+                       contentTransformations: widgetDef.contentTransformations\r
+               } );\r
+       }\r
+\r
+       function addWidgetProcessors( widgetsRepo, widgetDef ) {\r
+               var upcast = widgetDef.upcast,\r
+                       upcasts,\r
+                       priority = widgetDef.upcastPriority || 10;\r
+\r
+               if ( !upcast )\r
+                       return;\r
+\r
+               // Multiple upcasts defined in string.\r
+               if ( typeof upcast == 'string' ) {\r
+                       upcasts = upcast.split( ',' );\r
+                       while ( upcasts.length ) {\r
+                               addUpcast( widgetDef.upcasts[ upcasts.pop() ], widgetDef.name, priority );\r
+                       }\r
+               }\r
+               // Single rule which is automatically activated.\r
+               else {\r
+                       addUpcast( upcast, widgetDef.name, priority );\r
+               }\r
+\r
+               function addUpcast( upcast, name, priority ) {\r
+                       // Find index of the first higher (in terms of value) priority upcast.\r
+                       var index = CKEDITOR.tools.getIndex( widgetsRepo._.upcasts, function( element ) {\r
+                               return element[ 2 ] > priority;\r
+                       } );\r
+                       // Add at the end if it is the highest priority so far.\r
+                       if ( index < 0 ) {\r
+                               index = widgetsRepo._.upcasts.length;\r
+                       }\r
+\r
+                       widgetsRepo._.upcasts.splice( index, 0, [ upcast, name, priority ] );\r
+               }\r
+       }\r
+\r
+       function blurWidget( widgetsRepo, widget ) {\r
+               widgetsRepo.focused = null;\r
+\r
+               if ( widget.isInited() ) {\r
+                       var isDirty = widget.editor.checkDirty();\r
+\r
+                       // Widget could be destroyed in the meantime - e.g. data could be set.\r
+                       widgetsRepo.fire( 'widgetBlurred', { widget: widget } );\r
+                       widget.setFocused( false );\r
+\r
+                       !isDirty && widget.editor.resetDirty();\r
+               }\r
+       }\r
+\r
+       function checkWidgets( evt ) {\r
+               var options = evt.data;\r
+\r
+               if ( this.editor.mode != 'wysiwyg' )\r
+                       return;\r
+\r
+               var editable = this.editor.editable(),\r
+                       instances = this.instances,\r
+                       newInstances, i, count, wrapper, notYetInitialized;\r
+\r
+               if ( !editable )\r
+                       return;\r
+\r
+               // Remove widgets which have no corresponding elements in DOM.\r
+               for ( i in instances ) {\r
+                       // http://dev.ckeditor.com/ticket/13410 Remove widgets that are ready. This prevents from destroying widgets that are during loading process.\r
+                       if ( instances[ i ].isReady() && !editable.contains( instances[ i ].wrapper ) )\r
+                               this.destroy( instances[ i ], true );\r
+               }\r
+\r
+               // Init on all (new) if initOnlyNew option was passed.\r
+               if ( options && options.initOnlyNew )\r
+                       newInstances = this.initOnAll();\r
+               else {\r
+                       var wrappers = editable.find( '.cke_widget_wrapper' );\r
+                       newInstances = [];\r
+\r
+                       // Create widgets on existing wrappers if they do not exists.\r
+                       for ( i = 0, count = wrappers.count(); i < count; i++ ) {\r
+                               wrapper = wrappers.getItem( i );\r
+                               notYetInitialized = !this.getByElement( wrapper, true );\r
+\r
+                               // Check if:\r
+                               // * there's no instance for this widget\r
+                               // * wrapper is not inside some temporary element like copybin (http://dev.ckeditor.com/ticket/11088)\r
+                               // * it was a nested widget's wrapper which has been detached from DOM,\r
+                               // when nested editable has been initialized (it overwrites its innerHTML\r
+                               // and initializes nested widgets).\r
+                               if ( notYetInitialized && !findParent( wrapper, isDomTemp ) && editable.contains( wrapper ) ) {\r
+                                       // Add cke_widget_new class because otherwise\r
+                                       // widget will not be created on such wrapper.\r
+                                       wrapper.addClass( 'cke_widget_new' );\r
+                                       newInstances.push( this.initOn( wrapper.getFirst( Widget.isDomWidgetElement ) ) );\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // If only single widget was initialized and focusInited was passed, focus it.\r
+               if ( options && options.focusInited && newInstances.length == 1 )\r
+                       newInstances[ 0 ].focus();\r
+       }\r
+\r
+       // Unwraps widget element and clean up element.\r
+       //\r
+       // This function is used to clean up pasted widgets.\r
+       // It should have similar result to widget#destroy plus\r
+       // some additional adjustments, specific for pasting.\r
+       //\r
+       // @param {CKEDITOR.htmlParser.element} el\r
+       function cleanUpWidgetElement( el ) {\r
+               var parent = el.parent;\r
+               if ( parent.type == CKEDITOR.NODE_ELEMENT && parent.attributes[ 'data-cke-widget-wrapper' ] )\r
+                       parent.replaceWith( el );\r
+       }\r
+\r
+       // Similar to cleanUpWidgetElement, but works on DOM and finds\r
+       // widget elements by its own.\r
+       //\r
+       // Unlike cleanUpWidgetElement it will wrap element back.\r
+       //\r
+       // @param {CKEDITOR.dom.element} container\r
+       function cleanUpAllWidgetElements( widgetsRepo, container ) {\r
+               var wrappers = container.find( '.cke_widget_wrapper' ),\r
+                       wrapper, element,\r
+                       i = 0,\r
+                       l = wrappers.count();\r
+\r
+               for ( ; i < l; ++i ) {\r
+                       wrapper = wrappers.getItem( i );\r
+                       element = wrapper.getFirst( Widget.isDomWidgetElement );\r
+                       // If wrapper contains widget element - unwrap it and wrap again.\r
+                       if ( element.type == CKEDITOR.NODE_ELEMENT && element.data( 'widget' ) ) {\r
+                               element.replace( wrapper );\r
+                               widgetsRepo.wrapElement( element );\r
+                       } else {\r
+                               // Otherwise - something is wrong... clean this up.\r
+                               wrapper.remove();\r
+                       }\r
+               }\r
+       }\r
+\r
+       // Creates {@link CKEDITOR.filter} instance for given widget, editable and rules.\r
+       //\r
+       // Once filter for widget-editable pair is created it is cached, so the same instance\r
+       // will be returned when method is executed again.\r
+       //\r
+       // @param {String} widgetName\r
+       // @param {String} editableName\r
+       // @param {CKEDITOR.plugins.widget.nestedEditableDefinition} editableDefinition The nested editable definition.\r
+       // @returns {CKEDITOR.filter} Filter instance or `null` if rules are not defined.\r
+       // @context CKEDITOR.plugins.widget.repository\r
+       function createEditableFilter( widgetName, editableName, editableDefinition ) {\r
+               if ( !editableDefinition.allowedContent && !editableDefinition.disallowedContent )\r
+                       return null;\r
+\r
+               var editables = this._.filters[ widgetName ];\r
+\r
+               if ( !editables )\r
+                       this._.filters[ widgetName ] = editables = {};\r
+\r
+               var filter = editables[ editableName ];\r
+\r
+               if ( !filter ) {\r
+                       filter = editableDefinition.allowedContent ? new CKEDITOR.filter( editableDefinition.allowedContent ) : this.editor.filter.clone();\r
+\r
+                       editables[ editableName ] = filter;\r
+\r
+                       if ( editableDefinition.disallowedContent ) {\r
+                               filter.disallow( editableDefinition.disallowedContent );\r
+                       }\r
+               }\r
+\r
+               return filter;\r
+       }\r
+\r
+       // Creates an iterator function which when executed on all\r
+       // elements in DOM tree will gather elements that should be wrapped\r
+       // and initialized as widgets.\r
+       function createUpcastIterator( widgetsRepo ) {\r
+               var toBeWrapped = [],\r
+                       upcasts = widgetsRepo._.upcasts,\r
+                       upcastCallbacks = widgetsRepo._.upcastCallbacks;\r
+\r
+               return {\r
+                       toBeWrapped: toBeWrapped,\r
+\r
+                       iterator: function( element ) {\r
+                               var upcast, upcasted,\r
+                                       data,\r
+                                       i,\r
+                                       upcastsLength,\r
+                                       upcastCallbacksLength;\r
+\r
+                               // Wrapper found - find widget element, add it to be\r
+                               // cleaned up (unwrapped) and wrapped and stop iterating in this branch.\r
+                               if ( 'data-cke-widget-wrapper' in element.attributes ) {\r
+                                       element = element.getFirst( Widget.isParserWidgetElement );\r
+\r
+                                       if ( element )\r
+                                               toBeWrapped.push( [ element ] );\r
+\r
+                                       // Do not iterate over descendants.\r
+                                       return false;\r
+                               }\r
+                               // Widget element found - add it to be cleaned up (just in case)\r
+                               // and wrapped and stop iterating in this branch.\r
+                               else if ( 'data-widget' in element.attributes ) {\r
+                                       toBeWrapped.push( [ element ] );\r
+\r
+                                       // Do not iterate over descendants.\r
+                                       return false;\r
+                               }\r
+                               else if ( ( upcastsLength = upcasts.length ) ) {\r
+                                       // Ignore elements with data-cke-widget-upcasted to avoid multiple upcasts (http://dev.ckeditor.com/ticket/11533).\r
+                                       // Do not iterate over descendants.\r
+                                       if ( element.attributes[ 'data-cke-widget-upcasted' ] )\r
+                                               return false;\r
+\r
+                                       // Check element with upcast callbacks first.\r
+                                       // If any of them return false abort upcasting.\r
+                                       for ( i = 0, upcastCallbacksLength = upcastCallbacks.length; i < upcastCallbacksLength; ++i ) {\r
+                                               if ( upcastCallbacks[ i ]( element ) === false )\r
+                                                       return;\r
+                                               // Return nothing in order to continue iterating over ascendants.\r
+                                               // See http://dev.ckeditor.com/ticket/11186#comment:6\r
+                                       }\r
+\r
+                                       for ( i = 0; i < upcastsLength; ++i ) {\r
+                                               upcast = upcasts[ i ];\r
+                                               data = {};\r
+\r
+                                               if ( ( upcasted = upcast[ 0 ]( element, data ) ) ) {\r
+                                                       // If upcast function returned element, upcast this one.\r
+                                                       // It can be e.g. a new element wrapping the original one.\r
+                                                       if ( upcasted instanceof CKEDITOR.htmlParser.element )\r
+                                                               element = upcasted;\r
+\r
+                                                       // Set initial data attr with data from upcast method.\r
+                                                       element.attributes[ 'data-cke-widget-data' ] = encodeURIComponent( JSON.stringify( data ) );\r
+                                                       element.attributes[ 'data-cke-widget-upcasted' ] = 1;\r
+\r
+                                                       toBeWrapped.push( [ element, upcast[ 1 ] ] );\r
+\r
+                                                       // Do not iterate over descendants.\r
+                                                       return false;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               };\r
+       }\r
+\r
+       // Finds a first parent that matches query.\r
+       //\r
+       // @param {CKEDITOR.dom.element} element\r
+       // @param {Function} query\r
+       function findParent( element, query ) {\r
+               var parent = element;\r
+\r
+               while ( ( parent = parent.getParent() ) ) {\r
+                       if ( query( parent ) )\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       function getWrapperAttributes( inlineWidget, name ) {\r
+               return {\r
+                       // tabindex="-1" means that it can receive focus by code.\r
+                       tabindex: -1,\r
+                       contenteditable: 'false',\r
+                       'data-cke-widget-wrapper': 1,\r
+                       'data-cke-filter': 'off',\r
+                       // Class cke_widget_new marks widgets which haven't been initialized yet.\r
+                       'class': 'cke_widget_wrapper cke_widget_new cke_widget_' +\r
+                               ( inlineWidget ? 'inline' : 'block' ) +\r
+                               ( name ? ' cke_widget_' + name : '' )\r
+               };\r
+       }\r
+\r
+       // Inserts element at given index.\r
+       // It will check DTD and split ancestor elements up to the first\r
+       // that can contain this element.\r
+       //\r
+       // @param {CKEDITOR.htmlParser.element} parent\r
+       // @param {Number} index\r
+       // @param {CKEDITOR.htmlParser.element} element\r
+       function insertElement( parent, index, element ) {\r
+               // Do not split doc fragment...\r
+               if ( parent.type == CKEDITOR.NODE_ELEMENT ) {\r
+                       var parentAllows = CKEDITOR.dtd[ parent.name ];\r
+                       // Parent element is known (included in DTD) and cannot contain\r
+                       // this element.\r
+                       if ( parentAllows && !parentAllows[ element.name ] ) {\r
+                               var parent2 = parent.split( index ),\r
+                                       parentParent = parent.parent;\r
+\r
+                               // Element will now be inserted at right parent's index.\r
+                               index = parent2.getIndex();\r
+\r
+                               // If left part of split is empty - remove it.\r
+                               if ( !parent.children.length ) {\r
+                                       index -= 1;\r
+                                       parent.remove();\r
+                               }\r
+\r
+                               // If right part of split is empty - remove it.\r
+                               if ( !parent2.children.length )\r
+                                       parent2.remove();\r
+\r
+                               // Try inserting as grandpas' children.\r
+                               return insertElement( parentParent, index, element );\r
+                       }\r
+               }\r
+\r
+               // Finally we can add this element.\r
+               parent.add( element, index );\r
+       }\r
+\r
+       // Checks whether for the given widget definition and element widget should be created in inline or block mode.\r
+       //\r
+       // See also: {@link CKEDITOR.plugins.widget.definition#inline} and {@link CKEDITOR.plugins.widget#element}.\r
+       //\r
+       // @param {CKEDITOR.plugins.widget.definition} widgetDef The widget definition.\r
+       // @param {String} elementName The name of the widget element.\r
+       // @returns {Boolean}\r
+       function isWidgetInline( widgetDef, elementName ) {\r
+               return typeof widgetDef.inline == 'boolean' ? widgetDef.inline : !!CKEDITOR.dtd.$inline[ elementName ];\r
+       }\r
+\r
+       // @param {CKEDITOR.dom.element}\r
+       // @returns {Boolean}\r
+       function isDomTemp( element ) {\r
+               return element.hasAttribute( 'data-cke-temp' );\r
+       }\r
+\r
+       function onEditableKey( widget, keyCode ) {\r
+               var focusedEditable = widget.focusedEditable,\r
+                       range;\r
+\r
+               // CTRL+A.\r
+               if ( keyCode == CKEDITOR.CTRL + 65 ) {\r
+                       var bogus = focusedEditable.getBogus();\r
+\r
+                       range = widget.editor.createRange();\r
+                       range.selectNodeContents( focusedEditable );\r
+                       // Exclude bogus if exists.\r
+                       if ( bogus )\r
+                               range.setEndAt( bogus, CKEDITOR.POSITION_BEFORE_START );\r
+\r
+                       range.select();\r
+                       // Cancel event - block default.\r
+                       return false;\r
+               }\r
+               // DEL or BACKSPACE.\r
+               else if ( keyCode == 8 || keyCode == 46 ) {\r
+                       var ranges = widget.editor.getSelection().getRanges();\r
+\r
+                       range = ranges[ 0 ];\r
+\r
+                       // Block del or backspace if at editable's boundary.\r
+                       return !( ranges.length == 1 && range.collapsed &&\r
+                               range.checkBoundaryOfElement( focusedEditable, CKEDITOR[ keyCode == 8 ? 'START' : 'END' ] ) );\r
+               }\r
+       }\r
+\r
+       function setFocusedEditable( widgetsRepo, widget, editableElement, offline ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               editor.fire( 'lockSnapshot' );\r
+\r
+               if ( editableElement ) {\r
+                       var editableName = editableElement.data( 'cke-widget-editable' ),\r
+                               editableInstance = widget.editables[ editableName ];\r
+\r
+                       widgetsRepo.widgetHoldingFocusedEditable = widget;\r
+                       widget.focusedEditable = editableInstance;\r
+                       editableElement.addClass( 'cke_widget_editable_focused' );\r
+\r
+                       if ( editableInstance.filter )\r
+                               editor.setActiveFilter( editableInstance.filter );\r
+                       editor.setActiveEnterMode( editableInstance.enterMode, editableInstance.shiftEnterMode );\r
+               } else {\r
+                       if ( !offline )\r
+                               widget.focusedEditable.removeClass( 'cke_widget_editable_focused' );\r
+\r
+                       widget.focusedEditable = null;\r
+                       widgetsRepo.widgetHoldingFocusedEditable = null;\r
+                       editor.setActiveFilter( null );\r
+                       editor.setActiveEnterMode( null, null );\r
+               }\r
+\r
+               editor.fire( 'unlockSnapshot' );\r
+       }\r
+\r
+       function setupContextMenu( editor ) {\r
+               if ( !editor.contextMenu )\r
+                       return;\r
+\r
+               editor.contextMenu.addListener( function( element ) {\r
+                       var widget = editor.widgets.getByElement( element, true );\r
+\r
+                       if ( widget )\r
+                               return widget.fire( 'contextMenu', {} );\r
+               } );\r
+       }\r
+\r
+       // And now we've got two problems - original problem and RegExp.\r
+       // Some softeners:\r
+       // * FF tends to copy all blocks up to the copybin container.\r
+       // * IE tends to copy only the copybin, without its container.\r
+       // * We use spans on IE and blockless editors, but divs in other cases.\r
+       var pasteReplaceRegex = new RegExp(\r
+               '^' +\r
+               '(?:<(?:div|span)(?: data-cke-temp="1")?(?: id="cke_copybin")?(?: data-cke-temp="1")?>)?' +\r
+                       '(?:<(?:div|span)(?: style="[^"]+")?>)?' +\r
+                               '<span [^>]*data-cke-copybin-start="1"[^>]*>.?</span>([\\s\\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?</span>' +\r
+                       '(?:</(?:div|span)>)?' +\r
+               '(?:</(?:div|span)>)?' +\r
+               '$',\r
+               // IE8 prefers uppercase when browsers stick to lowercase HTML (http://dev.ckeditor.com/ticket/13460).\r
+               'i'\r
+       );\r
+\r
+       function pasteReplaceFn( match, wrapperHtml ) {\r
+               // Avoid polluting pasted data with any whitspaces,\r
+               // what's going to break check whether only one widget was pasted.\r
+               return CKEDITOR.tools.trim( wrapperHtml );\r
+       }\r
+\r
+       function setupDragAndDrop( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor,\r
+                       lineutils = CKEDITOR.plugins.lineutils;\r
+\r
+               // These listeners handle inline and block widgets drag and drop.\r
+               // The only thing we need to do to make block widgets custom drag and drop functionality\r
+               // is to fire those events with the right properties (like the target which must be the drag handle).\r
+               editor.on( 'dragstart', function( evt ) {\r
+                       var target = evt.data.target;\r
+\r
+                       if ( Widget.isDomDragHandler( target ) ) {\r
+                               var widget = widgetsRepo.getByElement( target );\r
+\r
+                               evt.data.dataTransfer.setData( 'cke/widget-id', widget.id );\r
+\r
+                               // IE needs focus.\r
+                               editor.focus();\r
+\r
+                               // and widget need to be focused on drag start (http://dev.ckeditor.com/ticket/12172#comment:10).\r
+                               widget.focus();\r
+                       }\r
+               } );\r
+\r
+               editor.on( 'drop', function( evt ) {\r
+                       var dataTransfer = evt.data.dataTransfer,\r
+                               id = dataTransfer.getData( 'cke/widget-id' ),\r
+                               transferType = dataTransfer.getTransferType( editor ),\r
+                               dragRange = editor.createRange(),\r
+                               sourceWidget;\r
+\r
+                       // Disable cross-editor drag & drop for widgets - http://dev.ckeditor.com/ticket/13599.\r
+                       if ( id !== '' && transferType === CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) {\r
+                               evt.cancel();\r
+                               return;\r
+                       }\r
+\r
+                       if ( id === '' || transferType != CKEDITOR.DATA_TRANSFER_INTERNAL ) {\r
+                               return;\r
+                       }\r
+\r
+                       sourceWidget = widgetsRepo.instances[ id ];\r
+                       if ( !sourceWidget ) {\r
+                               return;\r
+                       }\r
+\r
+                       dragRange.setStartBefore( sourceWidget.wrapper );\r
+                       dragRange.setEndAfter( sourceWidget.wrapper );\r
+                       evt.data.dragRange = dragRange;\r
+\r
+                       // [IE8-9] Reset state of the clipboard#fixSplitNodesAfterDrop fix because by setting evt.data.dragRange\r
+                       // (see above) after drop happened we do not need it. That fix is needed only if dragRange was created\r
+                       // before drop (before text node was split).\r
+                       delete CKEDITOR.plugins.clipboard.dragStartContainerChildCount;\r
+                       delete CKEDITOR.plugins.clipboard.dragEndContainerChildCount;\r
+\r
+                       evt.data.dataTransfer.setData( 'text/html', editor.editable().getHtmlFromRange( dragRange ).getHtml() );\r
+                       editor.widgets.destroy( sourceWidget, true );\r
+               } );\r
+\r
+               editor.on( 'contentDom', function() {\r
+                       var editable = editor.editable();\r
+\r
+                       // Register Lineutils's utilities as properties of repo.\r
+                       CKEDITOR.tools.extend( widgetsRepo, {\r
+                               finder: new lineutils.finder( editor, {\r
+                                       lookups: {\r
+                                               // Element is block but not list item and not in nested editable.\r
+                                               'default': function( el ) {\r
+                                                       if ( el.is( CKEDITOR.dtd.$listItem ) )\r
+                                                               return;\r
+\r
+                                                       if ( !el.is( CKEDITOR.dtd.$block ) )\r
+                                                               return;\r
+\r
+                                                       // Allow drop line inside, but never before or after nested editable (http://dev.ckeditor.com/ticket/12006).\r
+                                                       if ( Widget.isDomNestedEditable( el ) )\r
+                                                               return;\r
+\r
+                                                       // Do not allow droping inside the widget being dragged (http://dev.ckeditor.com/ticket/13397).\r
+                                                       if ( widgetsRepo._.draggedWidget.wrapper.contains( el ) ) {\r
+                                                               return;\r
+                                                       }\r
+\r
+                                                       // If element is nested editable, make sure widget can be dropped there (http://dev.ckeditor.com/ticket/12006).\r
+                                                       var nestedEditable = Widget.getNestedEditable( editable, el );\r
+                                                       if ( nestedEditable ) {\r
+                                                               var draggedWidget = widgetsRepo._.draggedWidget;\r
+\r
+                                                               // Don't let the widget to be dropped into its own nested editable.\r
+                                                               if ( widgetsRepo.getByElement( nestedEditable ) == draggedWidget )\r
+                                                                       return;\r
+\r
+                                                               var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ],\r
+                                                                       draggedRequiredContent = draggedWidget.requiredContent;\r
+\r
+                                                               // There will be no relation if the filter of nested editable does not allow\r
+                                                               // requiredContent of dragged widget.\r
+                                                               if ( filter && draggedRequiredContent && !filter.check( draggedRequiredContent ) )\r
+                                                                       return;\r
+                                                       }\r
+\r
+                                                       return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER;\r
+                                               }\r
+                                       }\r
+                               } ),\r
+                               locator: new lineutils.locator( editor ),\r
+                               liner: new lineutils.liner( editor, {\r
+                                       lineStyle: {\r
+                                               cursor: 'move !important',\r
+                                               'border-top-color': '#666'\r
+                                       },\r
+                                       tipLeftStyle: {\r
+                                               'border-left-color': '#666'\r
+                                       },\r
+                                       tipRightStyle: {\r
+                                               'border-right-color': '#666'\r
+                                       }\r
+                               } )\r
+                       }, true );\r
+               } );\r
+       }\r
+\r
+       // Setup mouse observer which will trigger:\r
+       // * widget focus on widget click,\r
+       // * widget#doubleclick forwarded from editor#doubleclick.\r
+       function setupMouseObserver( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               editor.on( 'contentDom', function() {\r
+                       var editable = editor.editable(),\r
+                               evtRoot = editable.isInline() ? editable : editor.document,\r
+                               widget,\r
+                               mouseDownOnDragHandler;\r
+\r
+                       editable.attachListener( evtRoot, 'mousedown', function( evt ) {\r
+                               var target = evt.data.getTarget();\r
+\r
+                               // Clicking scrollbar in Chrome will invoke event with target object of document type (#663).\r
+                               // In IE8 the target object will be empty (http://dev.ckeditor.com/ticket/10887).\r
+                               // We need to check if target is a proper element.\r
+                               widget = ( target instanceof CKEDITOR.dom.element ) ? widgetsRepo.getByElement( target ) : null;\r
+\r
+                               mouseDownOnDragHandler = 0; // Reset.\r
+\r
+                               // Widget was clicked, but not editable nested in it.\r
+                               if ( widget ) {\r
+                                       // Ignore mousedown on drag and drop handler if the widget is inline.\r
+                                       // Block widgets are handled by Lineutils.\r
+                                       if ( widget.inline && target.type == CKEDITOR.NODE_ELEMENT && target.hasAttribute( 'data-cke-widget-drag-handler' ) ) {\r
+                                               mouseDownOnDragHandler = 1;\r
+\r
+                                               // When drag handler is pressed we have to clear current selection if it wasn't already on this widget.\r
+                                               // Otherwise, the selection may be in a fillingChar, which prevents dragging a widget. (http://dev.ckeditor.com/ticket/13284, see comment 8 and 9.)\r
+                                               if ( widgetsRepo.focused != widget )\r
+                                                       editor.getSelection().removeAllRanges();\r
+\r
+                                               return;\r
+                                       }\r
+\r
+                                       if ( !Widget.getNestedEditable( widget.wrapper, target ) ) {\r
+                                               evt.data.preventDefault();\r
+                                               if ( !CKEDITOR.env.ie )\r
+                                                       widget.focus();\r
+                                       } else {\r
+                                               // Reset widget so mouseup listener is not confused.\r
+                                               widget = null;\r
+                                       }\r
+                               }\r
+                       } );\r
+\r
+                       // Focus widget on mouseup if mousedown was fired on drag handler.\r
+                       // Note: mouseup won't be fired at all if widget was dragged and dropped, so\r
+                       // this code will be executed only when drag handler was clicked.\r
+                       editable.attachListener( evtRoot, 'mouseup', function() {\r
+                               // Check if widget is not destroyed (if widget is destroyed the wrapper will be null).\r
+                               if ( mouseDownOnDragHandler && widget && widget.wrapper ) {\r
+                                       mouseDownOnDragHandler = 0;\r
+                                       widget.focus();\r
+                               }\r
+                       } );\r
+\r
+                       // On IE it is not enough to block mousedown. If widget wrapper (element with\r
+                       // contenteditable=false attribute) is clicked directly (it is a target),\r
+                       // then after mouseup/click IE will select that element.\r
+                       // It is not possible to prevent that default action,\r
+                       // so we force fake selection after everything happened.\r
+                       if ( CKEDITOR.env.ie ) {\r
+                               editable.attachListener( evtRoot, 'mouseup', function() {\r
+                                       setTimeout( function() {\r
+                                               // Check if widget is not destroyed (if widget is destroyed the wrapper will be null) and\r
+                                               // in editable contains widget (it could be dragged and removed).\r
+                                               if ( widget && widget.wrapper && editable.contains( widget.wrapper ) ) {\r
+                                                       widget.focus();\r
+                                                       widget = null;\r
+                                               }\r
+                                       } );\r
+                               } );\r
+                       }\r
+               } );\r
+\r
+               editor.on( 'doubleclick', function( evt ) {\r
+                       var widget = widgetsRepo.getByElement( evt.data.element );\r
+\r
+                       // Not in widget or in nested editable.\r
+                       if ( !widget || Widget.getNestedEditable( widget.wrapper, evt.data.element ) )\r
+                               return;\r
+\r
+                       return widget.fire( 'doubleclick', { element: evt.data.element } );\r
+               }, null, null, 1 );\r
+       }\r
+\r
+       // Setup editor#key observer which will forward it\r
+       // to focused widget.\r
+       function setupKeyboardObserver( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               editor.on( 'key', function( evt ) {\r
+                       var focused = widgetsRepo.focused,\r
+                               widgetHoldingFocusedEditable = widgetsRepo.widgetHoldingFocusedEditable,\r
+                               ret;\r
+\r
+                       if ( focused )\r
+                               ret = focused.fire( 'key', { keyCode: evt.data.keyCode } );\r
+                       else if ( widgetHoldingFocusedEditable )\r
+                               ret = onEditableKey( widgetHoldingFocusedEditable, evt.data.keyCode );\r
+\r
+                       return ret;\r
+               }, null, null, 1 );\r
+       }\r
+\r
+       // Setup copybin on native copy and cut events in order to handle copy and cut commands\r
+       // if user accepted security alert on IEs.\r
+       // Note: when copying or cutting using keystroke, copySingleWidget will be first executed\r
+       // by the keydown listener. Conflict between two calls will be resolved by copy_bin existence check.\r
+       function setupNativeCutAndCopy( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               editor.on( 'contentDom', function() {\r
+                       var editable = editor.editable();\r
+\r
+                       editable.attachListener( editable, 'copy', eventListener );\r
+                       editable.attachListener( editable, 'cut', eventListener );\r
+               } );\r
+\r
+               function eventListener( evt ) {\r
+                       if ( widgetsRepo.focused )\r
+                               copySingleWidget( widgetsRepo.focused, evt.name == 'cut' );\r
+               }\r
+       }\r
+\r
+       // Setup selection observer which will trigger:\r
+       // * widget select & focus on selection change,\r
+       // * nested editable focus (related properites and classes) on selection change,\r
+       // * deselecting and blurring all widgets on data,\r
+       // * blurring widget on editor blur.\r
+       function setupSelectionObserver( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor;\r
+\r
+               editor.on( 'selectionCheck', function() {\r
+                       widgetsRepo.fire( 'checkSelection' );\r
+               } );\r
+\r
+               widgetsRepo.on( 'checkSelection', widgetsRepo.checkSelection, widgetsRepo );\r
+\r
+               editor.on( 'selectionChange', function( evt ) {\r
+                       var nestedEditable = Widget.getNestedEditable( editor.editable(), evt.data.selection.getStartElement() ),\r
+                               newWidget = nestedEditable && widgetsRepo.getByElement( nestedEditable ),\r
+                               oldWidget = widgetsRepo.widgetHoldingFocusedEditable;\r
+\r
+                       if ( oldWidget ) {\r
+                               if ( oldWidget !== newWidget || !oldWidget.focusedEditable.equals( nestedEditable ) ) {\r
+                                       setFocusedEditable( widgetsRepo, oldWidget, null );\r
+\r
+                                       if ( newWidget && nestedEditable )\r
+                                               setFocusedEditable( widgetsRepo, newWidget, nestedEditable );\r
+                               }\r
+                       }\r
+                       // It may happen that there's no widget even if editable was found -\r
+                       // e.g. if selection was automatically set in editable although widget wasn't initialized yet.\r
+                       else if ( newWidget && nestedEditable ) {\r
+                               setFocusedEditable( widgetsRepo, newWidget, nestedEditable );\r
+                       }\r
+               } );\r
+\r
+               // Invalidate old widgets early - immediately on dataReady.\r
+               editor.on( 'dataReady', function() {\r
+                       // Deselect and blur all widgets.\r
+                       stateUpdater( widgetsRepo ).commit();\r
+               } );\r
+\r
+               editor.on( 'blur', function() {\r
+                       var widget;\r
+\r
+                       if ( ( widget = widgetsRepo.focused ) )\r
+                               blurWidget( widgetsRepo, widget );\r
+\r
+                       if ( ( widget = widgetsRepo.widgetHoldingFocusedEditable ) )\r
+                               setFocusedEditable( widgetsRepo, widget, null );\r
+               } );\r
+       }\r
+\r
+       // Set up actions like:\r
+       // * processing in toHtml/toDataFormat,\r
+       // * pasting handling,\r
+       // * insertion handling,\r
+       // * editable reload handling (setData, mode switch, undo/redo),\r
+       // * DOM invalidation handling,\r
+       // * widgets checks.\r
+       function setupWidgetsLifecycle( widgetsRepo ) {\r
+               setupWidgetsLifecycleStart( widgetsRepo );\r
+               setupWidgetsLifecycleEnd( widgetsRepo );\r
+\r
+               widgetsRepo.on( 'checkWidgets', checkWidgets );\r
+               widgetsRepo.editor.on( 'contentDomInvalidated', widgetsRepo.checkWidgets, widgetsRepo );\r
+       }\r
+\r
+       function setupWidgetsLifecycleEnd( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor,\r
+                       downcastingSessions = {};\r
+\r
+               // Listen before htmlDP#htmlFilter is applied to cache all widgets, because we'll\r
+               // loose data-cke-* attributes.\r
+               editor.on( 'toDataFormat', function( evt ) {\r
+                       // To avoid conflicts between htmlDP#toDF calls done at the same time\r
+                       // (e.g. nestedEditable#getData called during downcasting some widget)\r
+                       // mark every toDataFormat event chain with the downcasting session id.\r
+                       var id = CKEDITOR.tools.getNextNumber(),\r
+                               toBeDowncasted = [];\r
+                       evt.data.downcastingSessionId = id;\r
+                       downcastingSessions[ id ] = toBeDowncasted;\r
+\r
+                       evt.data.dataValue.forEach( function( element ) {\r
+                               var attrs = element.attributes,\r
+                                       widget, widgetElement;\r
+\r
+                               // Wrapper.\r
+                               // Perform first part of downcasting (cleanup) and cache widgets,\r
+                               // because after applying DP's filter all data-cke-* attributes will be gone.\r
+                               if ( 'data-cke-widget-id' in attrs ) {\r
+                                       widget = widgetsRepo.instances[ attrs[ 'data-cke-widget-id' ] ];\r
+                                       if ( widget ) {\r
+                                               widgetElement = element.getFirst( Widget.isParserWidgetElement );\r
+                                               toBeDowncasted.push( {\r
+                                                       wrapper: element,\r
+                                                       element: widgetElement,\r
+                                                       widget: widget,\r
+                                                       editables: {}\r
+                                               } );\r
+\r
+                                               // If widget did not have data-cke-widget attribute before upcasting remove it.\r
+                                               if ( widgetElement.attributes[ 'data-cke-widget-keep-attr' ] != '1' )\r
+                                                       delete widgetElement.attributes[ 'data-widget' ];\r
+                                       }\r
+                               }\r
+                               // Nested editable.\r
+                               else if ( 'data-cke-widget-editable' in attrs ) {\r
+                                       // Save the reference to this nested editable in the closest widget to be downcasted.\r
+                                       // Nested editables are downcasted in the successive toDataFormat to create an opportunity\r
+                                       // for dataFilter's "excludeNestedEditable" option to do its job (that option relies on\r
+                                       // contenteditable="true" attribute) (http://dev.ckeditor.com/ticket/11372).\r
+                                       toBeDowncasted[ toBeDowncasted.length - 1 ].editables[ attrs[ 'data-cke-widget-editable' ] ] = element;\r
+\r
+                                       // Don't check children - there won't be next wrapper or nested editable which we\r
+                                       // should process in this session.\r
+                                       return false;\r
+                               }\r
+                       }, CKEDITOR.NODE_ELEMENT, true );\r
+               }, null, null, 8 );\r
+\r
+               // Listen after dataProcessor.htmlFilter and ACF were applied\r
+               // so wrappers securing widgets' contents are removed after all filtering was done.\r
+               editor.on( 'toDataFormat', function( evt ) {\r
+                       // Ignore some unmarked sessions.\r
+                       if ( !evt.data.downcastingSessionId )\r
+                               return;\r
+\r
+                       var toBeDowncasted = downcastingSessions[ evt.data.downcastingSessionId ],\r
+                               toBe, widget, widgetElement, retElement, editableElement, e;\r
+\r
+                       while ( ( toBe = toBeDowncasted.shift() ) ) {\r
+                               widget = toBe.widget;\r
+                               widgetElement = toBe.element;\r
+                               retElement = widget._.downcastFn && widget._.downcastFn.call( widget, widgetElement );\r
+\r
+                               // Replace nested editables' content with their output data.\r
+                               for ( e in toBe.editables ) {\r
+                                       editableElement = toBe.editables[ e ];\r
+\r
+                                       delete editableElement.attributes.contenteditable;\r
+                                       editableElement.setHtml( widget.editables[ e ].getData() );\r
+                               }\r
+\r
+                               // Returned element always defaults to widgetElement.\r
+                               if ( !retElement )\r
+                                       retElement = widgetElement;\r
+\r
+                               toBe.wrapper.replaceWith( retElement );\r
+                       }\r
+               }, null, null, 13 );\r
+\r
+\r
+               editor.on( 'contentDomUnload', function() {\r
+                       widgetsRepo.destroyAll( true );\r
+               } );\r
+       }\r
+\r
+       function setupWidgetsLifecycleStart( widgetsRepo ) {\r
+               var editor = widgetsRepo.editor,\r
+                       processedWidgetOnly,\r
+                       snapshotLoaded;\r
+\r
+               // Listen after ACF (so data are filtered),\r
+               // but before dataProcessor.dataFilter was applied (so we can secure widgets' internals).\r
+               editor.on( 'toHtml', function( evt ) {\r
+                       var upcastIterator = createUpcastIterator( widgetsRepo ),\r
+                               toBeWrapped;\r
+\r
+                       evt.data.dataValue.forEach( upcastIterator.iterator, CKEDITOR.NODE_ELEMENT, true );\r
+\r
+                       // Clean up and wrap all queued elements.\r
+                       while ( ( toBeWrapped = upcastIterator.toBeWrapped.pop() ) ) {\r
+                               cleanUpWidgetElement( toBeWrapped[ 0 ] );\r
+                               widgetsRepo.wrapElement( toBeWrapped[ 0 ], toBeWrapped[ 1 ] );\r
+                       }\r
+\r
+                       // Used to determine whether only widget was pasted.\r
+                       if ( evt.data.protectedWhitespaces ) {\r
+                               // Whitespaces are protected by wrapping content with spans. Take the middle node only.\r
+                               processedWidgetOnly = evt.data.dataValue.children.length == 3 &&\r
+                                       Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 1 ] );\r
+                       } else {\r
+                               processedWidgetOnly = evt.data.dataValue.children.length == 1 &&\r
+                                       Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] );\r
+                       }\r
+               }, null, null, 8 );\r
+\r
+               editor.on( 'dataReady', function() {\r
+                       // Clean up all widgets loaded from snapshot.\r
+                       if ( snapshotLoaded )\r
+                               cleanUpAllWidgetElements( widgetsRepo, editor.editable() );\r
+                       snapshotLoaded = 0;\r
+\r
+                       // Some widgets were destroyed on contentDomUnload,\r
+                       // some on loadSnapshot, but that does not include\r
+                       // e.g. setHtml on inline editor or widgets removed just\r
+                       // before setting data.\r
+                       widgetsRepo.destroyAll( true );\r
+                       widgetsRepo.initOnAll();\r
+               } );\r
+\r
+               // Set flag so dataReady will know that additional\r
+               // cleanup is needed, because snapshot containing widgets was loaded.\r
+               editor.on( 'loadSnapshot', function( evt ) {\r
+                       // Primitive but sufficient check which will prevent from executing\r
+                       // heavier cleanUpAllWidgetElements if not needed.\r
+                       if ( ( /data-cke-widget/ ).test( evt.data ) )\r
+                               snapshotLoaded = 1;\r
+\r
+                       widgetsRepo.destroyAll( true );\r
+               }, null, null, 9 );\r
+\r
+               // Handle pasted single widget.\r
+               editor.on( 'paste', function( evt ) {\r
+                       var data = evt.data;\r
+\r
+                       data.dataValue = data.dataValue.replace( pasteReplaceRegex, pasteReplaceFn );\r
+\r
+                       // If drag'n'drop kind of paste into nested editable (data.range), selection is set AFTER\r
+                       // data is pasted, which means editor has no chance to change activeFilter's context.\r
+                       // As a result, pasted data is filtered with default editor's filter instead of NE's and\r
+                       // funny things get inserted. Changing the filter by analysis of the paste range below (http://dev.ckeditor.com/ticket/13186).\r
+                       if ( data.range ) {\r
+                               // Check if pasting into nested editable.\r
+                               var nestedEditable = Widget.getNestedEditable( editor.editable(), data.range.startContainer );\r
+\r
+                               if ( nestedEditable ) {\r
+                                       // Retrieve the filter from NE's data and set it active before editor.insertHtml is done\r
+                                       // in clipboard plugin.\r
+                                       var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ];\r
+\r
+                                       if ( filter ) {\r
+                                               editor.setActiveFilter( filter );\r
+                                       }\r
+                               }\r
+                       }\r
+               } );\r
+\r
+               // Listen with high priority to check widgets after data was inserted.\r
+               editor.on( 'afterInsertHtml', function( evt ) {\r
+                       if ( evt.data.intoRange ) {\r
+                               widgetsRepo.checkWidgets( { initOnlyNew: true } );\r
+                       } else {\r
+                               editor.fire( 'lockSnapshot' );\r
+                               // Init only new for performance reason.\r
+                               // Focus inited if only widget was processed.\r
+                               widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } );\r
+\r
+                               editor.fire( 'unlockSnapshot' );\r
+                       }\r
+               } );\r
+       }\r
+\r
+       // Helper for coordinating which widgets should be\r
+       // selected/deselected and which one should be focused/blurred.\r
+       function stateUpdater( widgetsRepo ) {\r
+               var currentlySelected = widgetsRepo.selected,\r
+                       toBeSelected = [],\r
+                       toBeDeselected = currentlySelected.slice( 0 ),\r
+                       focused = null;\r
+\r
+               return {\r
+                       select: function( widget ) {\r
+                               if ( CKEDITOR.tools.indexOf( currentlySelected, widget ) < 0 )\r
+                                       toBeSelected.push( widget );\r
+\r
+                               var index = CKEDITOR.tools.indexOf( toBeDeselected, widget );\r
+                               if ( index >= 0 )\r
+                                       toBeDeselected.splice( index, 1 );\r
+\r
+                               return this;\r
+                       },\r
+\r
+                       focus: function( widget ) {\r
+                               focused = widget;\r
+                               return this;\r
+                       },\r
+\r
+                       commit: function() {\r
+                               var focusedChanged = widgetsRepo.focused !== focused,\r
+                                       widget, isDirty;\r
+\r
+                               widgetsRepo.editor.fire( 'lockSnapshot' );\r
+\r
+                               if ( focusedChanged && ( widget = widgetsRepo.focused ) )\r
+                                       blurWidget( widgetsRepo, widget );\r
+\r
+                               while ( ( widget = toBeDeselected.pop() ) ) {\r
+                                       currentlySelected.splice( CKEDITOR.tools.indexOf( currentlySelected, widget ), 1 );\r
+                                       // Widget could be destroyed in the meantime - e.g. data could be set.\r
+                                       if ( widget.isInited() ) {\r
+                                               isDirty = widget.editor.checkDirty();\r
+\r
+                                               widget.setSelected( false );\r
+\r
+                                               !isDirty && widget.editor.resetDirty();\r
+                                       }\r
+                               }\r
+\r
+                               if ( focusedChanged && focused ) {\r
+                                       isDirty = widgetsRepo.editor.checkDirty();\r
+\r
+                                       widgetsRepo.focused = focused;\r
+                                       widgetsRepo.fire( 'widgetFocused', { widget: focused } );\r
+                                       focused.setFocused( true );\r
+\r
+                                       !isDirty && widgetsRepo.editor.resetDirty();\r
+                               }\r
+\r
+                               while ( ( widget = toBeSelected.pop() ) ) {\r
+                                       currentlySelected.push( widget );\r
+                                       widget.setSelected( true );\r
+                               }\r
+\r
+                               widgetsRepo.editor.fire( 'unlockSnapshot' );\r
+                       }\r
+               };\r
+       }\r
+\r
+\r
+       //\r
+       // WIDGET helpers ---------------------------------------------------------\r
+       //\r
+\r
+       // LEFT, RIGHT, UP, DOWN, DEL, BACKSPACE - unblock default fake sel handlers.\r
+       var keystrokesNotBlockedByWidget = { 37: 1, 38: 1, 39: 1, 40: 1, 8: 1, 46: 1 };\r
+\r
+       // Applies or removes style's classes from widget.\r
+       // @param {CKEDITOR.style} style Custom widget style.\r
+       // @param {Boolean} apply Whether to apply or remove style.\r
+       function applyRemoveStyle( widget, style, apply ) {\r
+               var changed = 0,\r
+                       classes = getStyleClasses( style ),\r
+                       updatedClasses = widget.data.classes || {},\r
+                       cl;\r
+\r
+               // Ee... Something is wrong with this style.\r
+               if ( !classes )\r
+                       return;\r
+\r
+               // Clone, because we need to break reference.\r
+               updatedClasses = CKEDITOR.tools.clone( updatedClasses );\r
+\r
+               while ( ( cl = classes.pop() ) ) {\r
+                       if ( apply ) {\r
+                               if ( !updatedClasses[ cl ] )\r
+                                       changed = updatedClasses[ cl ] = 1;\r
+                       } else {\r
+                               if ( updatedClasses[ cl ] ) {\r
+                                       delete updatedClasses[ cl ];\r
+                                       changed = 1;\r
+                               }\r
+                       }\r
+               }\r
+               if ( changed )\r
+                       widget.setData( 'classes', updatedClasses );\r
+       }\r
+\r
+       function cancel( evt ) {\r
+               evt.cancel();\r
+       }\r
+\r
+       function copySingleWidget( widget, isCut ) {\r
+               var editor = widget.editor,\r
+                       doc = editor.document;\r
+\r
+               // We're still handling previous copy/cut.\r
+               // When keystroke is used to copy/cut this will also prevent\r
+               // conflict with copySingleWidget called again for native copy/cut event.\r
+               if ( doc.getById( 'cke_copybin' ) )\r
+                       return;\r
+\r
+                       // [IE] Use span for copybin and its container to avoid bug with expanding editable height by\r
+                       // absolutely positioned element.\r
+               var copybinName = ( editor.blockless || CKEDITOR.env.ie ) ? 'span' : 'div',\r
+                       copybin = doc.createElement( copybinName ),\r
+                       copybinContainer = doc.createElement( copybinName ),\r
+                       // IE8 always jumps to the end of document.\r
+                       needsScrollHack = CKEDITOR.env.ie && CKEDITOR.env.version < 9;\r
+\r
+               copybinContainer.setAttributes( {\r
+                       id: 'cke_copybin',\r
+                       'data-cke-temp': '1'\r
+               } );\r
+\r
+               // Position copybin element outside current viewport.\r
+               copybin.setStyles( {\r
+                       position: 'absolute',\r
+                       width: '1px',\r
+                       height: '1px',\r
+                       overflow: 'hidden'\r
+               } );\r
+\r
+               copybin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-5000px' );\r
+\r
+               var range = editor.createRange();\r
+               range.setStartBefore( widget.wrapper );\r
+               range.setEndAfter( widget.wrapper );\r
+\r
+               copybin.setHtml(\r
+                       '<span data-cke-copybin-start="1">\u200b</span>' +\r
+                       editor.editable().getHtmlFromRange( range ).getHtml() +\r
+                       '<span data-cke-copybin-end="1">\u200b</span>' );\r
+\r
+               // Save snapshot with the current state.\r
+               editor.fire( 'saveSnapshot' );\r
+\r
+               // Ignore copybin.\r
+               editor.fire( 'lockSnapshot' );\r
+\r
+               copybinContainer.append( copybin );\r
+               editor.editable().append( copybinContainer );\r
+\r
+               var listener1 = editor.on( 'selectionChange', cancel, null, null, 0 ),\r
+                       listener2 = widget.repository.on( 'checkSelection', cancel, null, null, 0 );\r
+\r
+               if ( needsScrollHack ) {\r
+                       var docElement = doc.getDocumentElement().$,\r
+                               scrollTop = docElement.scrollTop;\r
+               }\r
+\r
+               // Once the clone of the widget is inside of copybin, select\r
+               // the entire contents. This selection will be copied by the\r
+               // native browser's clipboard system.\r
+               range = editor.createRange();\r
+               range.selectNodeContents( copybin );\r
+               range.select();\r
+\r
+               if ( needsScrollHack )\r
+                       docElement.scrollTop = scrollTop;\r
+\r
+               setTimeout( function() {\r
+                       // [IE] Focus widget before removing copybin to avoid scroll jump.\r
+                       if ( !isCut )\r
+                               widget.focus();\r
+\r
+                       copybinContainer.remove();\r
+\r
+                       listener1.removeListener();\r
+                       listener2.removeListener();\r
+\r
+                       editor.fire( 'unlockSnapshot' );\r
+\r
+                       if ( isCut ) {\r
+                               widget.repository.del( widget );\r
+                               editor.fire( 'saveSnapshot' );\r
+                       }\r
+               }, 100 ); // Use 100ms, so Chrome (@Mac) will be able to grab the content.\r
+       }\r
+\r
+       // Extracts classes array from style instance.\r
+       function getStyleClasses( style ) {\r
+               var attrs = style.getDefinition().attributes,\r
+                       classes = attrs && attrs[ 'class' ];\r
+\r
+               return classes ? classes.split( /\s+/ ) : null;\r
+       }\r
+\r
+       // [IE] Force keeping focus because IE sometimes forgets to fire focus on main editable\r
+       // when blurring nested editable.\r
+       // @context widget\r
+       function onEditableBlur() {\r
+               var active = CKEDITOR.document.getActive(),\r
+                       editor = this.editor,\r
+                       editable = editor.editable();\r
+\r
+               // If focus stays within editor override blur and set currentActive because it should be\r
+               // automatically changed to editable on editable#focus but it is not fired.\r
+               if ( ( editable.isInline() ? editable : editor.document.getWindow().getFrame() ).equals( active ) )\r
+                       editor.focusManager.focus( editable );\r
+       }\r
+\r
+       // Force selectionChange when editable was focused.\r
+       // Similar to hack in selection.js#~620.\r
+       // @context widget\r
+       function onEditableFocus() {\r
+               // Gecko does not support 'DOMFocusIn' event on which we unlock selection\r
+               // in selection.js to prevent selection locking when entering nested editables.\r
+               if ( CKEDITOR.env.gecko )\r
+                       this.editor.unlockSelection();\r
+\r
+               // We don't need to force selectionCheck on Webkit, because on Webkit\r
+               // we do that on DOMFocusIn in selection.js.\r
+               if ( !CKEDITOR.env.webkit ) {\r
+                       this.editor.forceNextSelectionCheck();\r
+                       this.editor.selectionChange( 1 );\r
+               }\r
+       }\r
+\r
+       // Setup listener on widget#data which will update (remove/add) classes\r
+       // by comparing newly set classes with the old ones.\r
+       function setupDataClassesListener( widget ) {\r
+               // Note: previousClasses and newClasses may be null!\r
+               // Tip: for ( cl in null ) is correct.\r
+               var previousClasses = null;\r
+\r
+               widget.on( 'data', function() {\r
+                       var newClasses = this.data.classes,\r
+                               cl;\r
+\r
+                       // When setting new classes one need to remember\r
+                       // that he must break reference.\r
+                       if ( previousClasses == newClasses )\r
+                               return;\r
+\r
+                       for ( cl in previousClasses ) {\r
+                               // Avoid removing and adding classes again.\r
+                               if ( !( newClasses && newClasses[ cl ] ) )\r
+                                       this.removeClass( cl );\r
+                       }\r
+                       for ( cl in newClasses )\r
+                               this.addClass( cl );\r
+\r
+                       previousClasses = newClasses;\r
+               } );\r
+       }\r
+\r
+       // Add a listener to data event that will set/change widget's label (http://dev.ckeditor.com/ticket/14539).\r
+       function setupA11yListener( widget ) {\r
+               // Note, the function gets executed in a context of widget instance.\r
+               function getLabelDefault() {\r
+                       return this.editor.lang.widget.label.replace( /%1/, this.pathName || this.element.getName() );\r
+               }\r
+\r
+               // Setting a listener on data is enough, there's no need to perform it on widget initialization, as\r
+               // setupWidgetData fires this event anyway.\r
+               widget.on( 'data', function() {\r
+                       // In some cases widget might get destroyed in an earlier data listener. For instance, image2 plugin, does\r
+                       // so when changing its internal state.\r
+                       if ( !widget.wrapper ) {\r
+                               return;\r
+                       }\r
+\r
+                       var label = this.getLabel ? this.getLabel() : getLabelDefault.call( this );\r
+\r
+                       widget.wrapper.setAttribute( 'role', 'region' );\r
+                       widget.wrapper.setAttribute( 'aria-label', label );\r
+               }, null, null, 9999 );\r
+       }\r
+\r
+       function setupDragHandler( widget ) {\r
+               if ( !widget.draggable )\r
+                       return;\r
+\r
+               var editor = widget.editor,\r
+                       // Use getLast to find wrapper's direct descendant (http://dev.ckeditor.com/ticket/12022).\r
+                       container = widget.wrapper.getLast( Widget.isDomDragHandlerContainer ),\r
+                       img;\r
+\r
+               // Reuse drag handler if already exists (http://dev.ckeditor.com/ticket/11281).\r
+               if ( container )\r
+                       img = container.findOne( 'img' );\r
+               else {\r
+                       container = new CKEDITOR.dom.element( 'span', editor.document );\r
+                       container.setAttributes( {\r
+                               'class': 'cke_reset cke_widget_drag_handler_container',\r
+                               // Split background and background-image for IE8 which will break on rgba().\r
+                               style: 'background:rgba(220,220,220,0.5);background-image:url(' + editor.plugins.widget.path + 'images/handle.png)'\r
+                       } );\r
+\r
+                       img = new CKEDITOR.dom.element( 'img', editor.document );\r
+                       img.setAttributes( {\r
+                               'class': 'cke_reset cke_widget_drag_handler',\r
+                               'data-cke-widget-drag-handler': '1',\r
+                               src: CKEDITOR.tools.transparentImageData,\r
+                               width: DRAG_HANDLER_SIZE,\r
+                               title: editor.lang.widget.move,\r
+                               height: DRAG_HANDLER_SIZE,\r
+                               role: 'presentation'\r
+                       } );\r
+                       widget.inline && img.setAttribute( 'draggable', 'true' );\r
+\r
+                       container.append( img );\r
+                       widget.wrapper.append( container );\r
+               }\r
+\r
+               // Preventing page reload when dropped content on widget wrapper (http://dev.ckeditor.com/ticket/13015).\r
+               // Widget is not editable so by default drop on it isn't allowed what means that\r
+               // browser handles it (there's no editable#drop event). If there's no drop event we cannot block\r
+               // the drop, so page is reloaded. This listener enables drop on widget wrappers.\r
+               widget.wrapper.on( 'dragover', function( evt ) {\r
+                       evt.data.preventDefault();\r
+               } );\r
+\r
+               widget.wrapper.on( 'mouseenter', widget.updateDragHandlerPosition, widget );\r
+               setTimeout( function() {\r
+                       widget.on( 'data', widget.updateDragHandlerPosition, widget );\r
+               }, 50 );\r
+\r
+               if ( !widget.inline ) {\r
+                       img.on( 'mousedown', onBlockWidgetDrag, widget );\r
+\r
+                       // On IE8 'dragstart' is propagated to editable, so editor#dragstart is fired twice on block widgets.\r
+                       if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {\r
+                               img.on( 'dragstart', function( evt ) {\r
+                                       evt.data.preventDefault( true );\r
+                               } );\r
+                       }\r
+               }\r
+\r
+               widget.dragHandlerContainer = container;\r
+       }\r
+\r
+       function onBlockWidgetDrag( evt ) {\r
+               var finder = this.repository.finder,\r
+                       locator = this.repository.locator,\r
+                       liner = this.repository.liner,\r
+                       editor = this.editor,\r
+                       editable = editor.editable(),\r
+                       listeners = [],\r
+                       sorted = [],\r
+                       locations,\r
+                       y;\r
+\r
+               // Mark dragged widget for repository#finder.\r
+               this.repository._.draggedWidget = this;\r
+\r
+               // Harvest all possible relations and display some closest.\r
+               var relations = finder.greedySearch(),\r
+\r
+                       buffer = CKEDITOR.tools.eventsBuffer( 50, function() {\r
+                               locations = locator.locate( relations );\r
+\r
+                               // There's only a single line displayed for D&D.\r
+                               sorted = locator.sort( y, 1 );\r
+\r
+                               if ( sorted.length ) {\r
+                                       liner.prepare( relations, locations );\r
+                                       liner.placeLine( sorted[ 0 ] );\r
+                                       liner.cleanup();\r
+                               }\r
+                       } );\r
+\r
+               // Let's have the "dragging cursor" over entire editable.\r
+               editable.addClass( 'cke_widget_dragging' );\r
+\r
+               // Cache mouse position so it is re-used in events buffer.\r
+               listeners.push( editable.on( 'mousemove', function( evt ) {\r
+                       y = evt.data.$.clientY;\r
+                       buffer.input();\r
+               } ) );\r
+\r
+               // Fire drag start as it happens during the native D&D.\r
+               editor.fire( 'dragstart', { target: evt.sender } );\r
+\r
+               function onMouseUp() {\r
+                       var l;\r
+\r
+                       buffer.reset();\r
+\r
+                       // Stop observing events.\r
+                       while ( ( l = listeners.pop() ) )\r
+                               l.removeListener();\r
+\r
+                       onBlockWidgetDrop.call( this, sorted, evt.sender );\r
+               }\r
+\r
+               // Mouseup means "drop". This is when the widget is being detached\r
+               // from DOM and placed at range determined by the line (location).\r
+               listeners.push( editor.document.once( 'mouseup', onMouseUp, this ) );\r
+\r
+               // Prevent calling 'onBlockWidgetDrop' twice in the inline editor.\r
+               // `removeListener` does not work if it is called at the same time event is fired.\r
+               if ( !editable.isInline() ) {\r
+                       // Mouseup may occur when user hovers the line, which belongs to\r
+                       // the outer document. This is, of course, a valid listener too.\r
+                       listeners.push( CKEDITOR.document.once( 'mouseup', onMouseUp, this ) );\r
+               }\r
+       }\r
+\r
+       function onBlockWidgetDrop( sorted, dragTarget ) {\r
+               var finder = this.repository.finder,\r
+                       liner = this.repository.liner,\r
+                       editor = this.editor,\r
+                       editable = this.editor.editable();\r
+\r
+               if ( !CKEDITOR.tools.isEmpty( liner.visible ) ) {\r
+                       // Retrieve range for the closest location.\r
+                       var dropRange = finder.getRange( sorted[ 0 ] );\r
+\r
+                       // Focus widget (it could lost focus after mousedown+mouseup)\r
+                       // and save this state as the one where we want to be taken back when undoing.\r
+                       this.focus();\r
+\r
+                       // Drag range will be set in the drop listener.\r
+                       editor.fire( 'drop', {\r
+                               dropRange: dropRange,\r
+                               target: dropRange.startContainer\r
+                       } );\r
+               }\r
+\r
+               // Clean-up custom cursor for editable.\r
+               editable.removeClass( 'cke_widget_dragging' );\r
+\r
+               // Clean-up all remaining lines.\r
+               liner.hideVisible();\r
+\r
+               // Clean-up drag & drop.\r
+               editor.fire( 'dragend', { target: dragTarget } );\r
+       }\r
+\r
+       function setupEditables( widget ) {\r
+               var editableName,\r
+                       editableDef,\r
+                       definedEditables = widget.editables;\r
+\r
+               widget.editables = {};\r
+\r
+               if ( !widget.editables )\r
+                       return;\r
+\r
+               for ( editableName in definedEditables ) {\r
+                       editableDef = definedEditables[ editableName ];\r
+                       widget.initEditable( editableName, typeof editableDef == 'string' ? { selector: editableDef } : editableDef );\r
+               }\r
+       }\r
+\r
+       function setupMask( widget ) {\r
+               if ( !widget.mask )\r
+                       return;\r
+\r
+               // Reuse mask if already exists (http://dev.ckeditor.com/ticket/11281).\r
+               var img = widget.wrapper.findOne( '.cke_widget_mask' );\r
+\r
+               if ( !img ) {\r
+                       img = new CKEDITOR.dom.element( 'img', widget.editor.document );\r
+                       img.setAttributes( {\r
+                               src: CKEDITOR.tools.transparentImageData,\r
+                               'class': 'cke_reset cke_widget_mask'\r
+                       } );\r
+                       widget.wrapper.append( img );\r
+               }\r
+\r
+               widget.mask = img;\r
+       }\r
+\r
+       // Replace parts object containing:\r
+       // partName => selector pairs\r
+       // with:\r
+       // partName => element pairs\r
+       function setupParts( widget ) {\r
+               if ( widget.parts ) {\r
+                       var parts = {},\r
+                               el, partName;\r
+\r
+                       for ( partName in widget.parts ) {\r
+                               el = widget.wrapper.findOne( widget.parts[ partName ] );\r
+                               parts[ partName ] = el;\r
+                       }\r
+                       widget.parts = parts;\r
+               }\r
+       }\r
+\r
+       function setupWidget( widget, widgetDef ) {\r
+               setupWrapper( widget );\r
+               setupParts( widget );\r
+               setupEditables( widget );\r
+               setupMask( widget );\r
+               setupDragHandler( widget );\r
+               setupDataClassesListener( widget );\r
+               setupA11yListener( widget );\r
+\r
+               // http://dev.ckeditor.com/ticket/11145: [IE8] Non-editable content of widget is draggable.\r
+               if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {\r
+                       widget.wrapper.on( 'dragstart', function( evt ) {\r
+                               var target = evt.data.getTarget();\r
+\r
+                               // Allow text dragging inside nested editables or dragging inline widget's drag handler.\r
+                               if ( !Widget.getNestedEditable( widget, target ) && !( widget.inline && Widget.isDomDragHandler( target ) ) )\r
+                                       evt.data.preventDefault();\r
+                       } );\r
+               }\r
+\r
+               widget.wrapper.removeClass( 'cke_widget_new' );\r
+               widget.element.addClass( 'cke_widget_element' );\r
+\r
+               widget.on( 'key', function( evt ) {\r
+                       var keyCode = evt.data.keyCode;\r
+\r
+                       // ENTER.\r
+                       if ( keyCode == 13 ) {\r
+                               widget.edit();\r
+                               // CTRL+C or CTRL+X.\r
+                       } else if ( keyCode == CKEDITOR.CTRL + 67 || keyCode == CKEDITOR.CTRL + 88 ) {\r
+                               copySingleWidget( widget, keyCode == CKEDITOR.CTRL + 88 );\r
+                               return; // Do not preventDefault.\r
+                       } else if ( keyCode in keystrokesNotBlockedByWidget || ( CKEDITOR.CTRL & keyCode ) || ( CKEDITOR.ALT & keyCode ) ) {\r
+                               // Pass chosen keystrokes to other plugins or default fake sel handlers.\r
+                               // Pass all CTRL/ALT keystrokes.\r
+                               return;\r
+                       }\r
+\r
+                       return false;\r
+               }, null, null, 999 );\r
+               // Listen with high priority so it's possible\r
+               // to overwrite this callback.\r
+\r
+               widget.on( 'doubleclick', function( evt ) {\r
+                       if ( widget.edit() ) {\r
+                               // We have to cancel event if edit method opens a dialog, otherwise\r
+                               // link plugin may open extra dialog (http://dev.ckeditor.com/ticket/12140).\r
+                               evt.cancel();\r
+                       }\r
+               } );\r
+\r
+               if ( widgetDef.data )\r
+                       widget.on( 'data', widgetDef.data );\r
+\r
+               if ( widgetDef.edit )\r
+                       widget.on( 'edit', widgetDef.edit );\r
+       }\r
+\r
+       function setupWidgetData( widget, startupData ) {\r
+               var widgetDataAttr = widget.element.data( 'cke-widget-data' );\r
+\r
+               if ( widgetDataAttr )\r
+                       widget.setData( JSON.parse( decodeURIComponent( widgetDataAttr ) ) );\r
+               if ( startupData )\r
+                       widget.setData( startupData );\r
+\r
+               // Populate classes if they are not preset.\r
+               if ( !widget.data.classes )\r
+                       widget.setData( 'classes', widget.getClasses() );\r
+\r
+               // Unblock data and...\r
+               widget.dataReady = true;\r
+\r
+               // Write data to element because this was blocked when data wasn't ready.\r
+               writeDataToElement( widget );\r
+\r
+               // Fire data event first time, because this was blocked when data wasn't ready.\r
+               widget.fire( 'data', widget.data );\r
+       }\r
+\r
+       function setupWrapper( widget ) {\r
+               // Retrieve widget wrapper. Assign an id to it.\r
+               var wrapper = widget.wrapper = widget.element.getParent();\r
+               wrapper.setAttribute( 'data-cke-widget-id', widget.id );\r
+       }\r
+\r
+       function writeDataToElement( widget ) {\r
+               widget.element.data( 'cke-widget-data', encodeURIComponent( JSON.stringify( widget.data ) ) );\r
+       }\r
+\r
+       //\r
+       // WIDGET STYLE HANDLER ---------------------------------------------------\r
+       //\r
+\r
+       ( function() {\r
+               // Styles categorized by group. It is used to prevent applying styles for the same group being used together.\r
+               var styleGroups = {};\r
+\r
+               /**\r
+                * The class representing a widget style. It is an {@link CKEDITOR#STYLE_OBJECT object} like\r
+                * the styles handler for widgets.\r
+                *\r
+                * **Note:** This custom style handler does not support all methods of the {@link CKEDITOR.style} class.\r
+                * Not supported methods: {@link #applyToRange}, {@link #removeFromRange}, {@link #applyToObject}.\r
+                *\r
+                * @since 4.4\r
+                * @class CKEDITOR.style.customHandlers.widget\r
+                * @extends CKEDITOR.style\r
+                */\r
+               CKEDITOR.style.addCustomHandler( {\r
+                       type: 'widget',\r
+\r
+                       setup: function( styleDefinition ) {\r
+                               /**\r
+                                * The name of widget to which this style can be applied.\r
+                                * It is extracted from style definition's `widget` property.\r
+                                *\r
+                                * @property {String} widget\r
+                                */\r
+                               this.widget = styleDefinition.widget;\r
+\r
+                               /**\r
+                                * An array of groups that this style belongs to.\r
+                                * Styles assigned to the same group cannot be combined.\r
+                                *\r
+                                * @since 4.6.2\r
+                                * @property {Array} group\r
+                                */\r
+                               this.group = typeof styleDefinition.group == 'string' ? [ styleDefinition.group ] : styleDefinition.group;\r
+\r
+                               // Store style categorized by its group.\r
+                               // It is used to prevent enabling two styles from same group.\r
+                               if ( this.group ) {\r
+                                       saveStyleGroup( this );\r
+                               }\r
+                       },\r
+\r
+                       apply: function( editor ) {\r
+                               var widget;\r
+\r
+                               // Before CKEditor 4.4 wasn't a required argument, so we need to\r
+                               // handle a case when it wasn't provided.\r
+                               if ( !( editor instanceof CKEDITOR.editor ) )\r
+                                       return;\r
+\r
+                               // Theoretically we could bypass checkApplicable, get widget from\r
+                               // widgets.focused and check its name, what would be faster, but then\r
+                               // this custom style would work differently than the default style\r
+                               // which checks if it's applicable before applying or removing itself.\r
+                               if ( this.checkApplicable( editor.elementPath(), editor ) ) {\r
+                                       widget = editor.widgets.focused;\r
+\r
+                                       // Remove other styles from the same group.\r
+                                       if ( this.group ) {\r
+                                               this.removeStylesFromSameGroup( editor );\r
+                                       }\r
+\r
+                                       widget.applyStyle( this );\r
+                               }\r
+                       },\r
+\r
+                       remove: function( editor ) {\r
+                               // Before CKEditor 4.4 wasn't a required argument, so we need to\r
+                               // handle a case when it wasn't provided.\r
+                               if ( !( editor instanceof CKEDITOR.editor ) )\r
+                                       return;\r
+\r
+                               if ( this.checkApplicable( editor.elementPath(), editor ) )\r
+                                       editor.widgets.focused.removeStyle( this );\r
+                       },\r
+\r
+                       /**\r
+                        * Removes all styles that belong to the same group as this style. This method will neither add nor remove\r
+                        * the current style.\r
+                        * Returns `true` if any style was removed, otherwise returns `false`.\r
+                        *\r
+                        * @since 4.6.2\r
+                        * @param {CKEDITOR.editor} editor\r
+                        * @returns {Boolean}\r
+                        */\r
+                       removeStylesFromSameGroup: function( editor ) {\r
+                               var stylesFromSameGroup,\r
+                                       path,\r
+                                       removed = false;\r
+\r
+                               // Before CKEditor 4.4 wasn't a required argument, so we need to\r
+                               // handle a case when it wasn't provided.\r
+                               if ( !( editor instanceof CKEDITOR.editor ) )\r
+                                       return false;\r
+\r
+                               path = editor.elementPath();\r
+                               if ( this.checkApplicable( path, editor ) ) {\r
+                                       // Iterate over each group.\r
+                                       for ( var i = 0, l = this.group.length; i < l; i++ ) {\r
+                                               stylesFromSameGroup = styleGroups[ this.widget ][ this.group[ i ] ];\r
+                                               // Iterate over each style from group.\r
+                                               for ( var j = 0; j < stylesFromSameGroup.length; j++ ) {\r
+                                                       if ( stylesFromSameGroup[ j ] !== this && stylesFromSameGroup[ j ].checkActive( path, editor ) ) {\r
+                                                               editor.widgets.focused.removeStyle( stylesFromSameGroup[ j ] );\r
+                                                               removed = true;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               return removed;\r
+                       },\r
+\r
+                       checkActive: function( elementPath, editor ) {\r
+                               return this.checkElementMatch( elementPath.lastElement, 0, editor );\r
+                       },\r
+\r
+                       checkApplicable: function( elementPath, editor ) {\r
+                               // Before CKEditor 4.4 wasn't a required argument, so we need to\r
+                               // handle a case when it wasn't provided.\r
+                               if ( !( editor instanceof CKEDITOR.editor ) )\r
+                                       return false;\r
+\r
+                               return this.checkElement( elementPath.lastElement );\r
+                       },\r
+\r
+                       checkElementMatch: checkElementMatch,\r
+\r
+                       checkElementRemovable: checkElementMatch,\r
+\r
+                       /**\r
+                        * Checks if an element is a {@link CKEDITOR.plugins.widget#wrapper wrapper} of a\r
+                        * widget whose name matches the {@link #widget widget name} specified in the style definition.\r
+                        *\r
+                        * @param {CKEDITOR.dom.element} element\r
+                        * @returns {Boolean}\r
+                        */\r
+                       checkElement: function( element ) {\r
+                               if ( !Widget.isDomWidgetWrapper( element ) )\r
+                                       return false;\r
+\r
+                               var widgetElement = element.getFirst( Widget.isDomWidgetElement );\r
+                               return widgetElement && widgetElement.data( 'widget' ) == this.widget;\r
+                       },\r
+\r
+                       buildPreview: function( label ) {\r
+                               return label || this._.definition.name;\r
+                       },\r
+\r
+                       /**\r
+                        * Returns allowed content rules which should be registered for this style.\r
+                        * Uses widget's {@link CKEDITOR.plugins.widget.definition#styleableElements} to make a rule\r
+                        * allowing classes on specified elements or use widget's\r
+                        * {@link CKEDITOR.plugins.widget.definition#styleToAllowedContentRules} method to transform a style\r
+                        * into allowed content rules.\r
+                        *\r
+                        * @param {CKEDITOR.editor} The editor instance.\r
+                        * @returns {CKEDITOR.filter.allowedContentRules}\r
+                        */\r
+                       toAllowedContentRules: function( editor ) {\r
+                               if ( !editor )\r
+                                       return null;\r
+\r
+                               var widgetDef = editor.widgets.registered[ this.widget ],\r
+                                       classes,\r
+                                       rule = {};\r
+\r
+                               if ( !widgetDef )\r
+                                       return null;\r
+\r
+                               if ( widgetDef.styleableElements ) {\r
+                                       classes = this.getClassesArray();\r
+                                       if ( !classes )\r
+                                               return null;\r
+\r
+                                       rule[ widgetDef.styleableElements ] = {\r
+                                               classes: classes,\r
+                                               propertiesOnly: true\r
+                                       };\r
+                                       return rule;\r
+                               }\r
+                               if ( widgetDef.styleToAllowedContentRules )\r
+                                       return widgetDef.styleToAllowedContentRules( this );\r
+                               return null;\r
+                       },\r
+\r
+                       /**\r
+                        * Returns classes defined in the style in form of an array.\r
+                        *\r
+                        * @returns {String[]}\r
+                        */\r
+                       getClassesArray: function() {\r
+                               var classes = this._.definition.attributes && this._.definition.attributes[ 'class' ];\r
+\r
+                               return classes ? CKEDITOR.tools.trim( classes ).split( /\s+/ ) : null;\r
+                       },\r
+\r
+                       /**\r
+                        * Not implemented.\r
+                        *\r
+                        * @method applyToRange\r
+                        */\r
+                       applyToRange: notImplemented,\r
+\r
+                       /**\r
+                        * Not implemented.\r
+                        *\r
+                        * @method removeFromRange\r
+                        */\r
+                       removeFromRange: notImplemented,\r
+\r
+                       /**\r
+                        * Not implemented.\r
+                        *\r
+                        * @method applyToObject\r
+                        */\r
+                       applyToObject: notImplemented\r
+               } );\r
+\r
+               function notImplemented() {}\r
+\r
+               // @context style\r
+               function checkElementMatch( element, fullMatch, editor ) {\r
+                       // Before CKEditor 4.4 wasn't a required argument, so we need to\r
+                       // handle a case when it wasn't provided.\r
+                       if ( !editor )\r
+                               return false;\r
+\r
+                       if ( !this.checkElement( element ) )\r
+                               return false;\r
+\r
+                       var widget = editor.widgets.getByElement( element, true );\r
+                       return widget && widget.checkStyleActive( this );\r
+               }\r
+\r
+               // Save and categorize style by its group.\r
+               function saveStyleGroup( style ) {\r
+                       var widgetName = style.widget,\r
+                               group;\r
+\r
+                       if ( !styleGroups[ widgetName ] ) {\r
+                               styleGroups[ widgetName ] = {};\r
+                       }\r
+\r
+                       for ( var i = 0, l = style.group.length; i < l; i++ ) {\r
+                               group = style.group[ i ];\r
+                               if ( !styleGroups[ widgetName ][ group ] ) {\r
+                                       styleGroups[ widgetName ][ group ] = [];\r
+                               }\r
+\r
+                               styleGroups[ widgetName ][ group ].push( style );\r
+                       }\r
+               }\r
+\r
+       } )();\r
+\r
+       //\r
+       // EXPOSE PUBLIC API ------------------------------------------------------\r
+       //\r
+\r
+       CKEDITOR.plugins.widget = Widget;\r
+       Widget.repository = Repository;\r
+       Widget.nestedEditable = NestedEditable;\r
+} )();\r
+\r
+/**\r
+ * An event fired when a widget definition is registered by the {@link CKEDITOR.plugins.widget.repository#add} method.\r
+ * It is possible to modify the definition being registered.\r
+ *\r
+ * @event widgetDefinition\r
+ * @member CKEDITOR.editor\r
+ * @param {CKEDITOR.plugins.widget.definition} data Widget definition.\r
+ */\r
+\r
+/**\r
+ * This is an abstract class that describes the definition of a widget.\r
+ * It is a type of {@link CKEDITOR.plugins.widget.repository#add} method's second argument.\r
+ *\r
+ * Widget instances inherit from registered widget definitions, although not in a prototypal way.\r
+ * They are simply extended with corresponding widget definitions. Note that not all properties of\r
+ * the widget definition become properties of a widget. Some, like {@link #data} or {@link #edit}, become\r
+ * widget's events listeners.\r
+ *\r
+ * @class CKEDITOR.plugins.widget.definition\r
+ * @abstract\r
+ * @mixins CKEDITOR.feature\r
+ */\r
+\r
+/**\r
+ * Widget definition name. It is automatically set when the definition is\r
+ * {@link CKEDITOR.plugins.widget.repository#add registered}.\r
+ *\r
+ * @property {String} name\r
+ */\r
+\r
+/**\r
+ * The method executed while initializing a widget, after a widget instance\r
+ * is created, but before it is ready. It is executed before the first\r
+ * {@link CKEDITOR.plugins.widget#event-data} is fired so it is common to\r
+ * use the `init` method to populate widget data with information loaded from\r
+ * the DOM, like for exmaple:\r
+ *\r
+ *             init: function() {\r
+ *                     this.setData( 'width', this.element.getStyle( 'width' ) );\r
+ *\r
+ *                     if ( this.parts.caption.getStyle( 'display' ) != 'none' )\r
+ *                             this.setData( 'showCaption', true );\r
+ *             }\r
+ *\r
+ * @property {Function} init\r
+ */\r
+\r
+/**\r
+ * The function to be used to upcast an element to this widget or a\r
+ * comma-separated list of upcast methods from the {@link #upcasts} object.\r
+ *\r
+ * The upcast function **is not** executed in the widget context (because the widget\r
+ * does not exist yet) and two arguments are passed:\r
+ *\r
+ * * `element` ({@link CKEDITOR.htmlParser.element}) &ndash; The element to be checked.\r
+ * * `data` (`Object`) &ndash; The object which can be extended with data which will then be passed to the widget.\r
+ *\r
+ * An element will be upcasted if a function returned `true` or an instance of\r
+ * a {@link CKEDITOR.htmlParser.element} if upcasting meant DOM structure changes\r
+ * (in this case the widget will be initialized on the returned element).\r
+ *\r
+ * @property {String/Function} upcast\r
+ */\r
+\r
+/**\r
+ * The object containing functions which can be used to upcast this widget.\r
+ * Only those pointed by the {@link #upcast} property will be used.\r
+ *\r
+ * In most cases it is appropriate to use {@link #upcast} directly,\r
+ * because majority of widgets need just one method.\r
+ * However, in some cases the widget author may want to expose more than one variant\r
+ * and then this property may be used.\r
+ *\r
+ *             upcasts: {\r
+ *                     // This function may upcast only figure elements.\r
+ *                     figure: function() {\r
+ *                             // ...\r
+ *                     },\r
+ *                     // This function may upcast only image elements.\r
+ *                     image: function() {\r
+ *                             // ...\r
+ *                     },\r
+ *                     // More variants...\r
+ *             }\r
+ *\r
+ *             // Then, widget user may choose which upcast methods will be enabled.\r
+ *             editor.on( 'widgetDefinition', function( evt ) {\r
+ *                     if ( evt.data.name == 'image' )\r
+ *                             evt.data.upcast = 'figure,image'; // Use both methods.\r
+ *             } );\r
+ *\r
+ * @property {Object} upcasts\r
+ */\r
+\r
+/**\r
+ * The {@link #upcast} method(s) priority. The upcast with a lower priority number will be called before\r
+ * the one with a higher number. The default priority is `10`.\r
+ *\r
+ * @since 4.5\r
+ * @property {Number} [upcastPriority=10]\r
+ */\r
+\r
+/**\r
+ * The function to be used to downcast this widget or\r
+ * a name of the downcast option from the {@link #downcasts} object.\r
+ *\r
+ * The downcast funciton will be executed in the {@link CKEDITOR.plugins.widget} context\r
+ * and with `widgetElement` ({@link CKEDITOR.htmlParser.element}) argument which is\r
+ * the widget's main element.\r
+ *\r
+ * The function may return an instance of the {@link CKEDITOR.htmlParser.node} class if the widget\r
+ * needs to be downcasted to a different node than the widget's main element.\r
+ *\r
+ * @property {String/Function} downcast\r
+ */\r
+\r
+/**\r
+ * The object containing functions which can be used to downcast this widget.\r
+ * Only the one pointed by the {@link #downcast} property will be used.\r
+ *\r
+ * In most cases it is appropriate to use {@link #downcast} directly,\r
+ * because majority of widgets have just one variant of downcasting (or none at all).\r
+ * However, in some cases the widget author may want to expose more than one variant\r
+ * and then this property may be used.\r
+ *\r
+ *             downcasts: {\r
+ *                     // This downcast may transform the widget into the figure element.\r
+ *                     figure: function() {\r
+ *                             // ...\r
+ *                     },\r
+ *                     // This downcast may transform the widget into the image element with data-* attributes.\r
+ *                     image: function() {\r
+ *                             // ...\r
+ *                     }\r
+ *             }\r
+ *\r
+ *             // Then, the widget user may choose one of the downcast options when setting up his editor.\r
+ *             editor.on( 'widgetDefinition', function( evt ) {\r
+ *                     if ( evt.data.name == 'image' )\r
+ *                             evt.data.downcast = 'figure';\r
+ *             } );\r
+ *\r
+ * @property downcasts\r
+ */\r
+\r
+/**\r
+ * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-edit} event listener.\r
+ * This means that it will be executed when a widget is being edited.\r
+ * See the {@link CKEDITOR.plugins.widget#method-edit} method.\r
+ *\r
+ * @property {Function} edit\r
+ */\r
+\r
+/**\r
+ * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-data} event listener.\r
+ * This means that it will be executed every time the {@link CKEDITOR.plugins.widget#property-data widget data} changes.\r
+ *\r
+ * @property {Function} data\r
+ */\r
+\r
+/**\r
+ * The method to be executed when the widget's command is executed in order to insert a new widget\r
+ * (widget of this type is not focused). If not defined, then the default action will be\r
+ * performed which means that:\r
+ *\r
+ * * An instance of the widget will be created in a detached {@link CKEDITOR.dom.documentFragment document fragment},\r
+ * * The {@link CKEDITOR.plugins.widget#method-edit} method will be called to trigger widget editing,\r
+ * * The widget element will be inserted into DOM.\r
+ *\r
+ * @property {Function} insert\r
+ */\r
+\r
+/**\r
+ * The name of a dialog window which will be opened on {@link CKEDITOR.plugins.widget#method-edit}.\r
+ * If not defined, then the {@link CKEDITOR.plugins.widget#method-edit} method will not perform any action and\r
+ * widget's command will insert a new widget without opening a dialog window first.\r
+ *\r
+ * @property {String} dialog\r
+ */\r
+\r
+/**\r
+ * The template which will be used to create a new widget element (when the widget's command is executed).\r
+ * This string is populated with {@link #defaults default values} by using the {@link CKEDITOR.template} format.\r
+ * Therefore it has to be a valid {@link CKEDITOR.template} argument.\r
+ *\r
+ * @property {String} template\r
+ */\r
+\r
+/**\r
+ * The data object which will be used to populate the data of a newly created widget.\r
+ * See {@link CKEDITOR.plugins.widget#property-data}.\r
+ *\r
+ *             defaults: {\r
+ *                     showCaption: true,\r
+ *                     align: 'none'\r
+ *             }\r
+ *\r
+ * @property defaults\r
+ */\r
+\r
+/**\r
+ * An object containing definitions of widget components (part name => CSS selector).\r
+ *\r
+ *             parts: {\r
+ *                     image: 'img',\r
+ *                     caption: 'div.caption'\r
+ *             }\r
+ *\r
+ * @property parts\r
+ */\r
+\r
+/**\r
+ * An object containing definitions of nested editables (editable name => {@link CKEDITOR.plugins.widget.nestedEditable.definition}).\r
+ * Note that editables *have to* be defined in the same order as they are in DOM / {@link CKEDITOR.plugins.widget.definition#template template}.\r
+ * Otherwise errors will occur when nesting widgets inside each other.\r
+ *\r
+ *             editables: {\r
+ *                     header: 'h1',\r
+ *                     content: {\r
+ *                             selector: 'div.content',\r
+ *                             allowedContent: 'p strong em; a[!href]'\r
+ *                     }\r
+ *             }\r
+ *\r
+ * @property editables\r
+ */\r
+\r
+/**\r
+ * The function used to obtain an accessibility label for the widget. It might be used to make\r
+ * the widget labels as precise as possible, since it has access to the widget instance.\r
+ *\r
+ * If not specified, the default implementation will use the {@link #pathName} or the main\r
+ * {@link CKEDITOR.plugins.widget#element element} tag name.\r
+ *\r
+ * @property {Function} getLabel\r
+ */\r
+\r
+/**\r
+ * The widget name displayed in the elements path.\r
+ *\r
+ * @property {String} pathName\r
+ */\r
+\r
+/**\r
+ * If set to `true`, the widget's element will be covered with a transparent mask.\r
+ * This will prevent its content from being clickable, which matters in case\r
+ * of special elements like embedded Flash or iframes that generate a separate "context".\r
+ *\r
+ * @property {Boolean} mask\r
+ */\r
+\r
+/**\r
+ * If set to `true/false`, it will force the widget to be either an inline or a block widget.\r
+ * If not set, the widget type will be determined from the widget element.\r
+ *\r
+ * Widget type influences whether a block (`div`) or an inline (`span`) element is used\r
+ * for the wrapper.\r
+ *\r
+ * @property {Boolean} inline\r
+ */\r
+\r
+/**\r
+ * The label for the widget toolbar button.\r
+ *\r
+ *             editor.widgets.add( 'simplebox', {\r
+ *                     button: 'Create a simple box'\r
+ *             } );\r
+ *\r
+ *             editor.widgets.add( 'simplebox', {\r
+ *                     button: editor.lang.simplebox.title\r
+ *             } );\r
+ *\r
+ * @property {String} button\r
+ */\r
+\r
+/**\r
+ * Whether widget should be draggable. Defaults to `true`.\r
+ * If set to `false` drag handler will not be displayed when hovering widget.\r
+ *\r
+ * @property {Boolean} draggable\r
+ */\r
+\r
+/**\r
+ * Names of element(s) (separated by spaces) for which the {@link CKEDITOR.filter} should allow classes\r
+ * defined in the widget styles. For example if your widget is upcasted from a simple `<div>`\r
+ * element, then in order to make it styleable you can set:\r
+ *\r
+ *             editor.widgets.add( 'customWidget', {\r
+ *                     upcast: function( element ) {\r
+ *                             return element.name == 'div';\r
+ *                     },\r
+ *\r
+ *                     // ...\r
+ *\r
+ *                     styleableElements: 'div'\r
+ *             } );\r
+ *\r
+ * Then, when the following style is defined:\r
+ *\r
+ *             {\r
+ *                     name: 'Thick border', type: 'widget', widget: 'customWidget',\r
+ *                     attributes: { 'class': 'thickBorder' }\r
+ *             }\r
+ *\r
+ * a rule allowing the `thickBorder` class for `div` elements will be registered in the {@link CKEDITOR.filter}.\r
+ *\r
+ * If you need to have more freedom when transforming widget style to allowed content rules,\r
+ * you can use the {@link #styleToAllowedContentRules} callback.\r
+ *\r
+ * @since 4.4\r
+ * @property {String} styleableElements\r
+ */\r
+\r
+/**\r
+ * Function transforming custom widget's {@link CKEDITOR.style} instance into\r
+ * {@link CKEDITOR.filter.allowedContentRules}. It may be used when a static\r
+ * {@link #styleableElements} property is not enough to inform the {@link CKEDITOR.filter}\r
+ * what HTML features should be enabled when allowing the given style.\r
+ *\r
+ * In most cases, when style's classes just have to be added to element name(s) used by\r
+ * the widget element, it is recommended to use simpler {@link #styleableElements} property.\r
+ *\r
+ * In order to get parsed classes from the style definition you can use\r
+ * {@link CKEDITOR.style.customHandlers.widget#getClassesArray}.\r
+ *\r
+ * For example, if you want to use the [object format of allowed content rules](#!/guide/dev_allowed_content_rules-section-object-format),\r
+ * to specify `match` validator, your implementation could look like this:\r
+ *\r
+ *             editor.widgets.add( 'customWidget', {\r
+ *                     // ...\r
+ *\r
+ *                     styleToAllowedContentRules: funciton( style ) {\r
+ *                             // Retrieve classes defined in the style.\r
+ *                             var classes = style.getClassesArray();\r
+ *\r
+ *                             // Do something crazy - for example return allowed content rules in object format,\r
+ *                             // with custom match property and propertiesOnly flag.\r
+ *                             return {\r
+ *                                     h1: {\r
+ *                                             match: isWidgetElement,\r
+ *                                             propertiesOnly: true,\r
+ *                                             classes: classes\r
+ *                                     }\r
+ *                             };\r
+ *                     }\r
+ *             } );\r
+ *\r
+ * @since 4.4\r
+ * @property {Function} styleToAllowedContentRules\r
+ * @param {CKEDITOR.style.customHandlers.widget} style The style to be transformed.\r
+ * @returns {CKEDITOR.filter.allowedContentRules}\r
+ */\r
+\r
+/**\r
+ * This is an abstract class that describes the definition of a widget's nested editable.\r
+ * It is a type of values in the {@link CKEDITOR.plugins.widget.definition#editables} object.\r
+ *\r
+ * In the simplest case the definition is a string which is a CSS selector used to\r
+ * find an element that will become a nested editable inside the widget. Note that\r
+ * the widget element can be a nested editable, too.\r
+ *\r
+ * In the more advanced case a definition is an object with a required `selector` property.\r
+ *\r
+ *             editables: {\r
+ *                     header: 'h1',\r
+ *                     content: {\r
+ *                             selector: 'div.content',\r
+ *                             allowedContent: 'p strong em; a[!href]'\r
+ *                     }\r
+ *             }\r
+ *\r
+ * @class CKEDITOR.plugins.widget.nestedEditable.definition\r
+ * @abstract\r
+ */\r
+\r
+/**\r
+ * The CSS selector used to find an element which will become a nested editable.\r
+ *\r
+ * @property {String} selector\r
+ */\r
+\r
+/**\r
+ * The [Advanced Content Filter](#!/guide/dev_advanced_content_filter) rules\r
+ * which will be used to limit the content allowed in this nested editable.\r
+ * This option is similar to {@link CKEDITOR.config#allowedContent} and one can\r
+ * use it to limit the editor features available in the nested editable.\r
+ *\r
+ * If no `allowedContent` is specified, the editable will use the editor default\r
+ * {@link CKEDITOR.editor#filter}.\r
+ *\r
+ * @property {CKEDITOR.filter.allowedContentRules} allowedContent\r
+ */\r
+\r
+/**\r
+ * The [Advanced Content Filter](#!/guide/dev_advanced_content_filter) rules\r
+ * which will be used to blacklist elements within this nested editable.\r
+ * This option is similar to {@link CKEDITOR.config#disallowedContent}.\r
+ *\r
+ * Note that `disallowedContent` work on top of the definition's {@link #allowedContent}.\r
+ *\r
+ * @since 4.7.3\r
+ * @property {CKEDITOR.filter.disallowedContentRules} disallowedContent\r
+ */\r
+\r
+/**\r
+ * Nested editable name displayed in the elements path.\r
+ *\r
+ * @property {String} pathName\r
+ */\r