JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.2.2
[ckeditor.git] / _source / plugins / dialog / plugin.js
index 6b5c2e4..5615b11 100644 (file)
@@ -248,6 +248,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                {\r
                                        if ( this.fire( 'cancel', { hide : true } ).hide !== false )\r
                                                this.hide();\r
+                                       evt.data.preventDefault();\r
                                }, this );\r
 \r
                // Sort focus list according to tab order definitions.\r
@@ -312,7 +313,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        if ( me != CKEDITOR.dialog._.currentTop )\r
                                return;\r
 \r
-                       var keystroke = evt.data.getKeystroke();\r
+                       var keystroke = evt.data.getKeystroke(),\r
+                               rtl = editor.lang.dir == 'rtl';\r
 \r
                        processed = 0;\r
                        if ( keystroke == 9 || keystroke == CKEDITOR.SHIFT + 9 )\r
@@ -335,7 +337,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                                processed = 1;\r
                        }\r
-                       else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode )\r
+                       else if ( keystroke == CKEDITOR.ALT + 121 && !me._.tabBarMode && me.getPageCount() > 1 )\r
                        {\r
                                // Alt-F10 puts focus into the current tab item in the tab bar.\r
                                me._.tabBarMode = true;\r
@@ -345,7 +347,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        else if ( ( keystroke == 37 || keystroke == 39 ) && me._.tabBarMode )\r
                        {\r
                                // Arrow keys - used for changing tabs.\r
-                               nextId = ( keystroke == 37 ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );\r
+                               nextId = ( keystroke == ( rtl ? 39 : 37 ) ? getPreviousVisibleTab.call( me ) : getNextVisibleTab.call( me ) );\r
                                me.selectPage( nextId );\r
                                me._.tabs[ nextId ][ 0 ].focus();\r
                                processed = 1;\r
@@ -381,11 +383,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )\r
                                        dialogElement.on( 'keypress', focusKeyPressHandler, this );\r
 \r
-                               if ( CKEDITOR.env.ie6Compat )\r
-                               {\r
-                                       var coverDoc = coverElement.getChild( 0 ).getFrameDocument();\r
-                                       coverDoc.on( 'keydown', focusKeydownHandler, this, null, 0 );\r
-                               }\r
                        } );\r
                this.on( 'hide', function()\r
                        {\r
@@ -505,8 +502,6 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                for ( i = 0 ; i < buttons.length ; i++ )\r
                        this._.buttons[ buttons[i].id ] = buttons[i];\r
-\r
-               CKEDITOR.skins.load( editor, 'dialog' );\r
        };\r
 \r
        // Focusable interface. Use it via dialog.addFocusable.\r
@@ -543,6 +538,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
        CKEDITOR.dialog.prototype =\r
        {\r
+               destroy : function()\r
+               {\r
+                       this.hide();\r
+                       this._.element.remove();\r
+               },\r
+\r
                /**\r
                 * Resizes the dialog.\r
                 * @param {Number} width The width of the dialog in pixels.\r
@@ -659,7 +660,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        if ( !( element.getParent() && element.getParent().equals( CKEDITOR.document.getBody() ) ) )\r
                                element.appendTo( CKEDITOR.document.getBody() );\r
                        else\r
-                               return;\r
+                               element.setStyle( 'display', 'block' );\r
 \r
                        // FIREFOX BUG: Fix vanishing caret for Firefox 2 or Gecko 1.8.\r
                        if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )\r
@@ -693,7 +694,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        {\r
                                CKEDITOR.dialog._.currentTop = this;\r
                                this._.parentDialog = null;\r
-                               addCover( this._.editor );\r
+                               showCover( this._.editor );\r
 \r
                                element.on( 'keydown', accessKeyDownHandler );\r
                                element.on( CKEDITOR.env.opera ? 'keypress' : 'keyup', accessKeyUpHandler );\r
@@ -797,23 +798,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                 */\r
                hide : function()\r
                {\r
+                       if ( !this.parts.dialog.isVisible() )\r
+                               return;\r
+\r
                        this.fire( 'hide', {} );\r
                        this._.editor.fire( 'dialogHide', this );\r
-\r
-                       // Remove the dialog's element from the root document.\r
                        var element = this._.element;\r
-                       if ( !element.getParent() )\r
-                               return;\r
-\r
-                       element.remove();\r
+                       element.setStyle( 'display', 'none' );\r
                        this.parts.dialog.setStyle( 'visibility', 'hidden' );\r
-\r
                        // Unregister all access keys associated with this dialog.\r
                        unregisterAccessKey( this );\r
 \r
+                       // Close any child(top) dialogs first.\r
+                       while( CKEDITOR.dialog._.currentTop != this )\r
+                               CKEDITOR.dialog._.currentTop.hide();\r
+\r
                        // Maintain dialog ordering and remove cover if needed.\r
                        if ( !this._.parentDialog )\r
-                               removeCover();\r
+                               hideCover();\r
                        else\r
                        {\r
                                var parentElement = this._.parentDialog.getElement().getFirst();\r
@@ -846,7 +848,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        else\r
                                CKEDITOR.dialog._.currentZIndex -= 10;\r
 \r
-\r
+                       delete this._.parentDialog;\r
                        // Reset the initial values of the dialog.\r
                        this.foreach( function( contentObj ) { contentObj.resetInitValue && contentObj.resetInitValue(); } );\r
                },\r
@@ -868,7 +870,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                                        children : contents.elements,\r
                                                        expand : !!contents.expand,\r
                                                        padding : contents.padding,\r
-                                                       style : contents.style || 'width: 100%;' + ( CKEDITOR.env.ie6Compat ? '' : 'height: 100%;' )\r
+                                                       style : contents.style || 'width: 100%; height: 100%;'\r
                                                }, pageHtml );\r
 \r
                        // Create the HTML for the tab and the content block.\r
@@ -893,17 +895,12 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                        page.setAttribute( 'aria-labelledby', tabId );\r
 \r
-                       // If only a single page exist, a different style is used in the central pane.\r
-                       if ( this._.pageCount === 0 )\r
-                               this.parts.dialog.addClass( 'cke_single_page' );\r
-                       else\r
-                               this.parts.dialog.removeClass( 'cke_single_page' );\r
-\r
                        // Take records for the tabs and elements created.\r
                        this._.tabs[ contents.id ] = [ tab, page ];\r
                        this._.tabIdList.push( contents.id );\r
-                       this._.pageCount++;\r
+                       !contents.hidden && this._.pageCount++;\r
                        this._.lastTab = tab;\r
+                       this.updateStyle();\r
 \r
                        var contentMap = this._.contents[ contents.id ] = {},\r
                                cursor,\r
@@ -961,6 +958,13 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        this._.currentTabIndex = CKEDITOR.tools.indexOf( this._.tabIdList, id );\r
                },\r
 \r
+               // Dialog state-specific style updates.\r
+               updateStyle : function()\r
+               {\r
+                       // If only a single page shown, a different style is used in the central pane.\r
+                       this.parts.dialog[ ( this._.pageCount === 1 ? 'add' : 'remove' ) + 'Class' ]( 'cke_single_page' );\r
+               },\r
+\r
                /**\r
                 * Hides a page's tab away from the dialog.\r
                 * @param {String} id The page's Id.\r
@@ -970,9 +974,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                hidePage : function( id )\r
                {\r
                        var tab = this._.tabs[id] && this._.tabs[id][0];\r
-                       if ( !tab )\r
+                       if ( !tab || this._.pageCount == 1 )\r
                                return;\r
+                       // Switch to other tab first when we're hiding the active tab.\r
+                       else if ( id == this._.currentTabId )\r
+                               this.selectPage( getPreviousVisibleTab.call( this ) );\r
+\r
                        tab.hide();\r
+                       this._.pageCount--;\r
+                       this.updateStyle();\r
                },\r
 \r
                /**\r
@@ -987,6 +997,8 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        if ( !tab )\r
                                return;\r
                        tab.show();\r
+                       this._.pageCount++;\r
+                       this.updateStyle();\r
                },\r
 \r
                /**\r
@@ -1269,12 +1281,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
        var defaultDialogDefinition =\r
        {\r
-               resizable : CKEDITOR.DIALOG_RESIZE_NONE,\r
+               resizable : CKEDITOR.DIALOG_RESIZE_BOTH,\r
                minWidth : 600,\r
                minHeight : 400,\r
                buttons : [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]\r
        };\r
 \r
+       // The buttons in MacOS Apps are in reverse order #4750\r
+       CKEDITOR.env.mac && defaultDialogDefinition.buttons.reverse();\r
+\r
        // Tool function used to return an item from an array based on its id\r
        // property.\r
        var getById = function( array, id, recurse )\r
@@ -1566,7 +1581,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                        if ( CKEDITOR.env.ie6Compat )\r
                        {\r
-                               var coverDoc = coverElement.getChild( 0 ).getFrameDocument();\r
+                               var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
                                coverDoc.removeListener( 'mousemove', mouseMoveHandler );\r
                                coverDoc.removeListener( 'mouseup', mouseUpHandler );\r
                        }\r
@@ -1584,7 +1599,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                                if ( CKEDITOR.env.ie6Compat )\r
                                {\r
-                                       var coverDoc = coverElement.getChild( 0 ).getFrameDocument();\r
+                                       var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
                                        coverDoc.on( 'mousemove', mouseMoveHandler );\r
                                        coverDoc.on( 'mouseup', mouseUpHandler );\r
                                }\r
@@ -1642,7 +1657,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                        if ( CKEDITOR.env.ie6Compat )\r
                        {\r
-                               var coverDoc = coverElement.getChild( 0 ).getFrameDocument();\r
+                               var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
                                coverDoc.on( 'mousemove', mouseMoveHandler, dialog, { part : partName } );\r
                                coverDoc.on( 'mouseup', mouseUpHandler, dialog, { part : partName } );\r
                        }\r
@@ -1713,7 +1728,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
 \r
                        if ( CKEDITOR.env.ie6Compat )\r
                        {\r
-                               var coverDoc = coverElement.getChild( 0 ).getFrameDocument();\r
+                               var coverDoc = currentCover.getChild( 0 ).getFrameDocument();\r
                                coverDoc.removeListener( 'mouseup', mouseUpHandler );\r
                                coverDoc.removeListener( 'mousemove', mouseMoveHandler );\r
                        }\r
@@ -1737,25 +1752,33 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
        }\r
 \r
        var resizeCover;\r
-       var coverElement;\r
+       // Caching resuable covers and allowing only one cover\r
+       // on screen.\r
+       var covers = {},\r
+               currentCover;\r
 \r
-       var addCover = function( editor )\r
+       function showCover( editor )\r
        {\r
                var win = CKEDITOR.document.getWindow();\r
+               var backgroundColorStyle = editor.config.dialog_backgroundCoverColor || 'white',\r
+                       backgroundCoverOpacity = editor.config.dialog_backgroundCoverOpacity,\r
+                       baseFloatZIndex = editor.config.baseFloatZIndex,\r
+                       coverKey = CKEDITOR.tools.genKey(\r
+                                       backgroundColorStyle,\r
+                                       backgroundCoverOpacity,\r
+                                       baseFloatZIndex ),\r
+                       coverElement = covers[ coverKey ];\r
 \r
                if ( !coverElement )\r
                {\r
-                       var backgroundColorStyle = editor.config.dialog_backgroundCoverColor || 'white';\r
-\r
                        var html = [\r
                                        '<div style="position: ', ( CKEDITOR.env.ie6Compat ? 'absolute' : 'fixed' ),\r
-                                       '; z-index: ', editor.config.baseFloatZIndex,\r
+                                       '; z-index: ', baseFloatZIndex,\r
                                        '; top: 0px; left: 0px; ',\r
                                        ( !CKEDITOR.env.ie6Compat ? 'background-color: ' + backgroundColorStyle : '' ),\r
-                                       '" id="cke_dialog_background_cover">'\r
+                                       '" class="cke_dialog_background_cover">'\r
                                ];\r
 \r
-\r
                        if ( CKEDITOR.env.ie6Compat )\r
                        {\r
                                // Support for custom document.domain in IE.\r
@@ -1791,14 +1814,19 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                        html.push( '</div>' );\r
 \r
                        coverElement = CKEDITOR.dom.element.createFromHtml( html.join( '' ) );\r
-               }\r
+                       coverElement.setOpacity( backgroundCoverOpacity != undefined ? backgroundCoverOpacity : 0.5 );\r
 \r
-               var element = coverElement;\r
+                       coverElement.appendTo( CKEDITOR.document.getBody() );\r
+                       covers[ coverKey ] = coverElement;\r
+               }\r
+               else\r
+                       coverElement.   show();\r
 \r
+               currentCover = coverElement;\r
                var resizeFunc = function()\r
                {\r
                        var size = win.getViewPaneSize();\r
-                       element.setStyles(\r
+                       coverElement.setStyles(\r
                                {\r
                                        width : size.width + 'px',\r
                                        height : size.height + 'px'\r
@@ -1809,7 +1837,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                {\r
                        var pos = win.getScrollPosition(),\r
                                cursor = CKEDITOR.dialog._.currentTop;\r
-                       element.setStyles(\r
+                       coverElement.setStyles(\r
                                        {\r
                                                left : pos.x + 'px',\r
                                                top : pos.y + 'px'\r
@@ -1841,20 +1869,15 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                }, 0 );\r
                        scrollFunc();\r
                }\r
+       }\r
 \r
-               var opacity = editor.config.dialog_backgroundCoverOpacity;\r
-               element.setOpacity( typeof opacity != 'undefined' ? opacity : 0.5 );\r
-\r
-               element.appendTo( CKEDITOR.document.getBody() );\r
-       };\r
-\r
-       var removeCover = function()\r
+       function hideCover()\r
        {\r
-               if ( !coverElement )\r
+               if ( !currentCover )\r
                        return;\r
 \r
                var win = CKEDITOR.document.getWindow();\r
-               coverElement.remove();\r
+               currentCover.hide();\r
                win.removeListener( 'resize', resizeCover );\r
 \r
                if ( CKEDITOR.env.ie6Compat )\r
@@ -1866,7 +1889,14 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                }, 0 );\r
                }\r
                resizeCover = null;\r
-       };\r
+       }\r
+\r
+       function removeCovers()\r
+       {\r
+               for ( var coverId in covers )\r
+                       covers[ coverId ].remove();\r
+               covers = {};\r
+       }\r
 \r
        var accessKeyProcessors = {};\r
 \r
@@ -2646,7 +2676,7 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                // undo support should dedicate to specific dialog implementation.\r
                canUndo: false,\r
 \r
-               editorFocus : CKEDITOR.env.ie\r
+               editorFocus : CKEDITOR.env.ie || CKEDITOR.env.webkit\r
        };\r
 \r
        (function()\r
@@ -2766,6 +2796,24 @@ CKEDITOR.DIALOG_RESIZE_BOTH = 3;
                                return this.functions( function( val ){ return val != value; }, msg );\r
                        }\r
                };\r
+\r
+       CKEDITOR.on( 'instanceDestroyed', function( evt )\r
+       {\r
+               // Remove dialog cover on last instance destroy.\r
+               if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) )\r
+               {\r
+                       var currentTopDialog;\r
+                       while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) )\r
+                               currentTopDialog.hide();\r
+                       removeCovers();\r
+               }\r
+\r
+               var dialogs = evt.editor._.storedDialogs;\r
+               for ( var name in dialogs )\r
+                       dialogs[ name ].destroy();\r
+\r
+       });\r
+\r
        })();\r
 })();\r
 \r
@@ -2784,10 +2832,11 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
                 */\r
                openDialog : function( dialogName, callback )\r
                {\r
-                       var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];\r
+                       var dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],\r
+                                       dialogSkin = this.skin.dialog;\r
 \r
                        // If the dialogDefinition is already loaded, open it immediately.\r
-                       if ( typeof dialogDefinitions == 'function' )\r
+                       if ( typeof dialogDefinitions == 'function' && dialogSkin._isLoaded )\r
                        {\r
                                var storedDialogs = this._.storedDialogs ||\r
                                        ( this._.storedDialogs = {} );\r
@@ -2809,14 +2858,31 @@ CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
                                me = this;\r
 \r
                        body.setStyle( 'cursor', 'wait' );\r
-                       CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), function()\r
-                               {\r
-                                       // In case of plugin error, mark it as loading failed.\r
-                                       if ( typeof CKEDITOR.dialog._.dialogDefinitions[ dialogName ] != 'function' )\r
-                                                       CKEDITOR.dialog._.dialogDefinitions[ dialogName ] =  'failed';\r
-                                       me.openDialog( dialogName, callback );\r
-                                       body.setStyle( 'cursor', cursor );\r
-                               } );\r
+\r
+                       function onDialogFileLoaded( success )\r
+                       {\r
+                               var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ],\r
+                                               skin = me.skin.dialog;\r
+\r
+                               // Check if both skin part and definition is loaded.\r
+                               if ( !skin._isLoaded || loadDefinition && typeof success == 'undefined' )\r
+                                       return;\r
+\r
+                               // In case of plugin error, mark it as loading failed.\r
+                               if ( typeof dialogDefinition != 'function' )\r
+                                       CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed';\r
+\r
+                               me.openDialog( dialogName, callback );\r
+                               body.setStyle( 'cursor', cursor );\r
+                       }\r
+\r
+                       if ( typeof dialogDefinitions == 'string' )\r
+                       {\r
+                               var loadDefinition = 1;\r
+                               CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ), onDialogFileLoaded );\r
+                       }\r
+\r
+                       CKEDITOR.skins.load( this, 'dialog', onDialogFileLoaded );\r
 \r
                        return null;\r
                }\r