Orbit/public/javascripts/ckeditor/_source/plugins/panel/plugin.js

403 lines
9.6 KiB
JavaScript

/*
Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'panel',
{
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
}
});
/**
* Panel UI element.
* @constant
* @example
*/
CKEDITOR.UI_PANEL = 2;
CKEDITOR.ui.panel = function( document, definition )
{
// Copy all definition properties to this object.
if ( definition )
CKEDITOR.tools.extend( this, definition );
// Set defaults.
CKEDITOR.tools.extend( this,
{
className : '',
css : []
});
this.id = CKEDITOR.tools.getNextId();
this.document = document;
this._ =
{
blocks : {}
};
};
/**
* Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
* instance.
* @type Object
* @example
*/
CKEDITOR.ui.panel.handler =
{
create : function( definition )
{
return new CKEDITOR.ui.panel( definition );
}
};
CKEDITOR.ui.panel.prototype =
{
renderHtml : function( editor )
{
var output = [];
this.render( editor, output );
return output.join( '' );
},
/**
* Renders the combo.
* @param {CKEDITOR.editor} editor The editor instance which this button is
* to be used by.
* @param {Array} output The output array to which append the HTML relative
* to this button.
* @example
*/
render : function( editor, output )
{
var id = this.id;
output.push(
'<div class="', editor.skinClass ,'"' +
' lang="', editor.langCode, '"' +
' role="presentation"' +
// iframe loading need sometime, keep the panel hidden(#4186).
' style="display:none;z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' +
'<div' +
' id=', id,
' dir=', editor.lang.dir,
' role="presentation"' +
' class="cke_panel cke_', editor.lang.dir );
if ( this.className )
output.push( ' ', this.className );
output.push(
'">' );
if ( this.forceIFrame || this.css.length )
{
output.push(
'<iframe id="', id, '_frame"' +
' frameborder="0"' +
' role="application" src="javascript:void(' );
output.push(
// Support for custom document.domain in IE.
CKEDITOR.env.isCustomDomain() ?
'(function(){' +
'document.open();' +
'document.domain=\'' + document.domain + '\';' +
'document.close();' +
'})()'
:
'0' );
output.push(
')"></iframe>' );
}
output.push(
'</div>' +
'</div>' );
return id;
},
getHolderElement : function()
{
var holder = this._.holder;
if ( !holder )
{
if ( this.forceIFrame || this.css.length )
{
var iframe = this.document.getById( this.id + '_frame' ),
parentDiv = iframe.getParent(),
dir = parentDiv.getAttribute( 'dir' ),
className = parentDiv.getParent().getAttribute( 'class' ),
langCode = parentDiv.getParent().getAttribute( 'lang' ),
doc = iframe.getFrameDocument();
var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function( ev )
{
this.isLoaded = true;
if ( this.onLoad )
this.onLoad();
}, this ) );
var data =
'<!DOCTYPE html>' +
'<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' +
'<head>' +
'<style>.' + className + '_container{visibility:hidden}</style>' +
'</head>' +
'<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0"' +
' onload="( window.CKEDITOR || window.parent.CKEDITOR ).tools.callFunction(' + onLoad + ');"></body>' +
// It looks strange, but for FF2, the styles must go
// after <body>, so it (body) becames immediatelly
// available. (#3031)
CKEDITOR.tools.buildStyleHtml( this.css ) +
'<\/html>';
doc.write( data );
var win = doc.getWindow();
// Register the CKEDITOR global.
win.$.CKEDITOR = CKEDITOR;
// Arrow keys for scrolling is only preventable with 'keypress' event in Opera (#4534).
doc.on( 'key' + ( CKEDITOR.env.opera? 'press':'down' ), function( evt )
{
var keystroke = evt.data.getKeystroke(),
dir = this.document.getById( this.id ).getAttribute( 'dir' );
// Delegate key processing to block.
if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )
{
evt.data.preventDefault();
return;
}
// ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl)
if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) )
{
if ( this.onEscape && this.onEscape( keystroke ) === false )
evt.data.preventDefault();
}
},
this );
holder = doc.getBody();
holder.unselectable();
CKEDITOR.env.air && CKEDITOR.tools.callFunction( onLoad );
}
else
holder = this.document.getById( this.id );
this._.holder = holder;
}
return holder;
},
addBlock : function( name, block )
{
block = this._.blocks[ name ] = block instanceof CKEDITOR.ui.panel.block ? block
: new CKEDITOR.ui.panel.block( this.getHolderElement(), block );
if ( !this._.currentBlock )
this.showBlock( name );
return block;
},
getBlock : function( name )
{
return this._.blocks[ name ];
},
showBlock : function( name )
{
var blocks = this._.blocks,
block = blocks[ name ],
current = this._.currentBlock,
holder = this.forceIFrame ?
this.document.getById( this.id + '_frame' )
: this._.holder;
// Disable context menu for block panel.
holder.getParent().getParent().disableContextMenu();
if ( current )
{
// Clean up the current block's effects on holder.
holder.removeAttributes( current.attributes );
current.hide();
}
this._.currentBlock = block;
holder.setAttributes( block.attributes );
CKEDITOR.fire( 'ariaWidget', holder );
// Reset the focus index, so it will always go into the first one.
block._.focusIndex = -1;
this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
block.onMark = function( item )
{
holder.setAttribute( 'aria-activedescendant', item.getId() + '_option' );
};
block.onUnmark = function()
{
holder.removeAttribute( 'aria-activedescendant' );
};
block.show();
return block;
},
destroy : function()
{
this.element && this.element.remove();
}
};
CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(
{
$ : function( blockHolder, blockDefinition )
{
this.element = blockHolder.append(
blockHolder.getDocument().createElement( 'div',
{
attributes :
{
'tabIndex' : -1,
'class' : 'cke_panel_block',
'role' : 'presentation'
},
styles :
{
display : 'none'
}
}) );
// Copy all definition properties to this object.
if ( blockDefinition )
CKEDITOR.tools.extend( this, blockDefinition );
if ( !this.attributes.title )
this.attributes.title = this.attributes[ 'aria-label' ];
this.keys = {};
this._.focusIndex = -1;
// Disable context menu for panels.
this.element.disableContextMenu();
},
_ : {
/**
* Mark the item specified by the index as current activated.
*/
markItem: function( index )
{
if ( index == -1 )
return;
var links = this.element.getElementsByTag( 'a' );
var item = links.getItem( this._.focusIndex = index );
// Safari need focus on the iframe window first(#3389), but we need
// lock the blur to avoid hiding the panel.
if ( CKEDITOR.env.webkit || CKEDITOR.env.opera )
item.getDocument().getWindow().focus();
item.focus();
this.onMark && this.onMark( item );
}
},
proto :
{
show : function()
{
this.element.setStyle( 'display', '' );
},
hide : function()
{
if ( !this.onHide || this.onHide.call( this ) !== true )
this.element.setStyle( 'display', 'none' );
},
onKeyDown : function( keystroke )
{
var keyAction = this.keys[ keystroke ];
switch ( keyAction )
{
// Move forward.
case 'next' :
var index = this._.focusIndex,
links = this.element.getElementsByTag( 'a' ),
link;
while ( ( link = links.getItem( ++index ) ) )
{
// Move the focus only if the element is marked with
// the _cke_focus and it it's visible (check if it has
// width).
if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
{
this._.focusIndex = index;
link.focus();
break;
}
}
return false;
// Move backward.
case 'prev' :
index = this._.focusIndex;
links = this.element.getElementsByTag( 'a' );
while ( index > 0 && ( link = links.getItem( --index ) ) )
{
// Move the focus only if the element is marked with
// the _cke_focus and it it's visible (check if it has
// width).
if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
{
this._.focusIndex = index;
link.focus();
break;
}
}
return false;
case 'click' :
index = this._.focusIndex;
link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
if ( link )
link.$.click ? link.$.click() : link.$.onclick();
return false;
}
return true;
}
}
});
/**
* Fired when a panel is added to the document
* @name CKEDITOR#ariaWidget
* @event
* @param {Object} holder The element wrapping the panel
*/