mailiverse/gwt/war/ckeditor/_source/plugins/richcombo/plugin.js
2013-07-21 13:40:17 -04:00

382 lines
9.2 KiB
JavaScript

/*
Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'richcombo',
{
requires : [ 'floatpanel', 'listblock', 'button' ],
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );
}
});
/**
* Button UI element.
* @constant
* @example
*/
CKEDITOR.UI_RICHCOMBO = 'richcombo';
CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass(
{
$ : function( definition )
{
// Copy all definition properties to this object.
CKEDITOR.tools.extend( this, definition,
// Set defaults.
{
title : definition.label,
modes : { wysiwyg : 1 }
});
// We don't want the panel definition in this object.
var panelDefinition = this.panel || {};
delete this.panel;
this.id = CKEDITOR.tools.getNextNumber();
this.document = ( panelDefinition
&& panelDefinition.parent
&& panelDefinition.parent.getDocument() )
|| CKEDITOR.document;
panelDefinition.className = ( panelDefinition.className || '' ) + ' cke_rcombopanel';
panelDefinition.block =
{
multiSelect : panelDefinition.multiSelect,
attributes : panelDefinition.attributes
};
this._ =
{
panelDefinition : panelDefinition,
items : {},
state : CKEDITOR.TRISTATE_OFF
};
},
statics :
{
handler :
{
create : function( definition )
{
return new CKEDITOR.ui.richCombo( definition );
}
}
},
proto :
{
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 env = CKEDITOR.env;
var id = 'cke_' + this.id;
var clickFn = CKEDITOR.tools.addFunction( function( $element )
{
var _ = this._;
if ( _.state == CKEDITOR.TRISTATE_DISABLED )
return;
this.createPanel( editor );
if ( _.on )
{
_.panel.hide();
return;
}
this.commit();
var value = this.getValue();
if ( value )
_.list.mark( value );
else
_.list.unmarkAll();
_.panel.showBlock( this.id, new CKEDITOR.dom.element( $element ), 4 );
},
this );
var instance = {
id : id,
combo : this,
focus : function()
{
var element = CKEDITOR.document.getById( id ).getChild( 1 );
element.focus();
},
clickFn : clickFn
};
function updateState()
{
var state = this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
this.setState( editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state );
this.setValue( '' );
}
editor.on( 'mode', updateState, this );
// If this combo is sensitive to readOnly state, update it accordingly.
!this.readOnly && editor.on( 'readOnly', updateState, this);
var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element )
{
ev = new CKEDITOR.dom.event( ev );
var keystroke = ev.getKeystroke();
switch ( keystroke )
{
case 13 : // ENTER
case 32 : // SPACE
case 40 : // ARROW-DOWN
// Show panel
CKEDITOR.tools.callFunction( clickFn, element );
break;
default :
// Delegate the default behavior to toolbar button key handling.
instance.onkey( instance, keystroke );
}
// Avoid subsequent focus grab on editor document.
ev.preventDefault();
});
var focusFn = CKEDITOR.tools.addFunction( function() { instance.onfocus && instance.onfocus(); } );
// For clean up
instance.keyDownFn = keyDownFn;
output.push(
'<span class="cke_rcombo" role="presentation">',
'<span id=', id );
if ( this.className )
output.push( ' class="', this.className, ' cke_off"');
output.push(
' role="presentation">',
'<span id="' + id+ '_label" class=cke_label>', this.label, '</span>',
'<a hidefocus=true title="', this.title, '" tabindex="-1"',
env.gecko && env.version >= 10900 && !env.hc ? '' : ' href="javascript:void(\'' + this.label + '\')"',
' role="button" aria-labelledby="', id , '_label" aria-describedby="', id, '_text" aria-haspopup="true"' );
// Some browsers don't cancel key events in the keydown but in the
// keypress.
// TODO: Check if really needed for Gecko+Mac.
if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
{
output.push(
' onkeypress="return false;"' );
}
// With Firefox, we need to force it to redraw, otherwise it
// will remain in the focus state.
if ( CKEDITOR.env.gecko )
{
output.push(
' onblur="this.style.cssText = this.style.cssText;"' );
}
output.push(
' onkeydown="CKEDITOR.tools.callFunction( ', keyDownFn, ', event, this );"' +
' onfocus="return CKEDITOR.tools.callFunction(', focusFn, ', event);" ' +
( CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick' ) + // #188
'="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +
'<span>' +
'<span id="' + id + '_text" class="cke_text cke_inline_label">' + this.label + '</span>' +
'</span>' +
'<span class=cke_openbutton><span class=cke_icon>' + ( CKEDITOR.env.hc ? '&#9660;' : CKEDITOR.env.air ? '&nbsp;' : '' ) + '</span></span>' + // BLACK DOWN-POINTING TRIANGLE
'</a>' +
'</span>' +
'</span>' );
if ( this.onRender )
this.onRender();
return instance;
},
createPanel : function( editor )
{
if ( this._.panel )
return;
var panelDefinition = this._.panelDefinition,
panelBlockDefinition = this._.panelDefinition.block,
panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
list = panel.addListBlock( this.id, panelBlockDefinition ),
me = this;
panel.onShow = function()
{
if ( me.className )
this.element.getFirst().addClass( me.className + '_panel' );
me.setState( CKEDITOR.TRISTATE_ON );
list.focus( !me.multiSelect && me.getValue() );
me._.on = 1;
if ( me.onOpen )
me.onOpen();
};
panel.onHide = function( preventOnClose )
{
if ( me.className )
this.element.getFirst().removeClass( me.className + '_panel' );
me.setState( me.modes && me.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
me._.on = 0;
if ( !preventOnClose && me.onClose )
me.onClose();
};
panel.onEscape = function()
{
panel.hide();
};
list.onClick = function( value, marked )
{
// Move the focus to the main windows, otherwise it will stay
// into the floating panel, even if invisible, and Safari and
// Opera will go a bit crazy.
me.document.getWindow().focus();
if ( me.onClick )
me.onClick.call( me, value, marked );
if ( marked )
me.setValue( value, me._.items[ value ] );
else
me.setValue( '' );
panel.hide( false );
};
this._.panel = panel;
this._.list = list;
panel.getBlock( this.id ).onHide = function()
{
me._.on = 0;
me.setState( CKEDITOR.TRISTATE_OFF );
};
if ( this.init )
this.init();
},
setValue : function( value, text )
{
this._.value = value;
var textElement = this.document.getById( 'cke_' + this.id + '_text' );
if ( textElement )
{
if ( !( value || text ) )
{
text = this.label;
textElement.addClass( 'cke_inline_label' );
}
else
textElement.removeClass( 'cke_inline_label' );
textElement.setHtml( typeof text != 'undefined' ? text : value );
}
},
getValue : function()
{
return this._.value || '';
},
unmarkAll : function()
{
this._.list.unmarkAll();
},
mark : function( value )
{
this._.list.mark( value );
},
hideItem : function( value )
{
this._.list.hideItem( value );
},
hideGroup : function( groupTitle )
{
this._.list.hideGroup( groupTitle );
},
showAll : function()
{
this._.list.showAll();
},
add : function( value, html, text )
{
this._.items[ value ] = text || value;
this._.list.add( value, html, text );
},
startGroup : function( title )
{
this._.list.startGroup( title );
},
commit : function()
{
if ( !this._.committed )
{
this._.list.commit();
this._.committed = 1;
CKEDITOR.ui.fire( 'ready', this );
}
this._.committed = 1;
},
setState : function( state )
{
if ( this._.state == state )
return;
this.document.getById( 'cke_' + this.id ).setState( state );
this._.state = state;
}
}
});
CKEDITOR.ui.prototype.addRichCombo = function( name, definition )
{
this.add( name, CKEDITOR.UI_RICHCOMBO, definition );
};