(function() {
'use strict';
/* istanbul ignore if */
if(CKEDITOR.plugins.get('ae_richcombobridge')) {
return;
}
/* istanbul ignore next */
function noop() {}
// API not yet implemented inside the richcombo bridge. By mocking the unsupported methods, we
// prevent plugins from crashing if they make use of them.
//
// Some methods like `setState` clash with React's own state methods. For them, unsupported means
// that we don't account for the different meaning in the passed or returned arguments.
var UNSUPPORTED_RICHCOMBO_API = {
commit: noop,
createPanel: noop,
disable: noop,
enable: noop,
getState: noop,
hideGroup: noop,
hideItem: noop,
mark: noop,
//setState: noop,
showAll: noop,
startGroup: noop,
unmarkAll: noop
};
var RICH_COMBO_DEFS = {};
/**
* Generates a RichComboBridge React class for a given richcombo definition if it has not been
* already created based on the richcombo name and definition.
*
* @method generateRichComboBridge
* @private
* @param {String} richComboName The rich combo name
* @param {Object} richComboDefinition The rich combo definition
* @return {Object} The generated or already existing React RichCombo Class
*/
var generateRichComboBridge = function(richComboName, richComboDefinition, editor) {
var RichComboBridge = AlloyEditor.Buttons[richComboName];
RICH_COMBO_DEFS[editor.name] = RICH_COMBO_DEFS[editor.name] || {};
RICH_COMBO_DEFS[editor.name][richComboName] = RICH_COMBO_DEFS[editor.name][richComboName] || richComboDefinition;
RICH_COMBO_DEFS[editor.name][richComboName].currentValue = undefined;
if (!RichComboBridge) {
RichComboBridge = React.createClass(
CKEDITOR.tools.merge(UNSUPPORTED_RICHCOMBO_API, {
displayName: richComboName,
propTypes: {
editor: React.PropTypes.object.isRequired
},
statics: {
key: richComboName
},
add: function(value, preview, title) {
this._items.push({
preview: preview,
title: title,
value: value
});
},
componentWillMount: function () {
var editor = this.props.editor.get('nativeEditor');
var editorCombo = RICH_COMBO_DEFS[editor.name][richComboName];
this._items = [];
this.setValue = this._setValue;
if (editorCombo.init) {
editorCombo.init.call(this);
}
if (editorCombo.onRender) {
editorCombo.onRender.call(this);
}
},
componentWillUnmount: function () {
this._cacheValue(this.state.value);
this.setValue = this._cacheValue;
},
getInitialState: function() {
return {
value: RICH_COMBO_DEFS[editor.name][richComboName].currentValue
};
},
getValue: function() {
return this.state.value;
},
render: function() {
var editor = this.props.editor.get('nativeEditor');
var richComboLabel = RICH_COMBO_DEFS[editor.name][richComboName].currentValue || richComboDefinition.label;
var itemsList;
if (this.props.expanded) {
itemsList = this._getItemsList();
}
return (
<div className="ae-container-dropdown ae-has-dropdown">
<button aria-expanded={this.props.expanded} aria-label={richComboLabel} className="ae-toolbar-element" onClick={this.props.toggleDropdown} role="combobox" tabIndex={this.props.tabIndex} title={richComboLabel}>
<div className="ae-container">
<span className="ae-container-dropdown-selected-item">{richComboLabel}</span>
<span className="ae-icon-arrow"></span>
</div>
</button>
{itemsList}
</div>
);
},
_cacheValue: function(value) {
var editor = this.props.editor.get('nativeEditor');
RICH_COMBO_DEFS[editor.name][richComboName].currentValue = value;
},
_getItems: function() {
var richCombo = this;
var items = this._items.map(function(item) {
return (
<li key={item.title} role="option">
<button className="ae-toolbar-element" dangerouslySetInnerHTML={{__html: item.preview}} data-value={item.value} onClick={richCombo._onClick}></button>
</li>
);
});
return items;
},
_getItemsList: function() {
return (
<AlloyEditor.ButtonDropdown onDismiss={this.props.toggleDropdown}>
{this._getItems()}
</AlloyEditor.ButtonDropdown>
);
},
_onClick: function(event) {
var editor = this.props.editor.get('nativeEditor');
var editorCombo = RICH_COMBO_DEFS[editor.name][richComboName];
if (editorCombo.onClick) {
var newValue = event.currentTarget.getAttribute('data-value');
editorCombo.onClick.call(this, newValue);
RICH_COMBO_DEFS[editor.name][richComboName].currentValue = newValue;
editor.fire('actionPerformed', this);
}
},
_setValue: function(value) {
this._cacheValue(value);
this.setState({
value: value
});
}
})
);
AlloyEditor.Buttons[richComboName] = RichComboBridge;
}
return RichComboBridge;
};
/* istanbul ignore else */
if (!CKEDITOR.plugins.get('richcombo')) {
CKEDITOR.UI_RICHCOMBO = 'richcombo';
CKEDITOR.plugins.add('richcombo', {});
}
/**
* CKEditor plugin that bridges the support offered by CKEditor RichCombo plugin. It takes over the
* responsibility of registering and creating rich combo elements via:
* - editor.ui.addRichCombo(name, definition)
* - editor.ui.add(name, CKEDITOR.UI_RICHCOMBO, definition)
*
* @class CKEDITOR.plugins.ae_richcombobridge
* @requires CKEDITOR.plugins.ae_uibridge
* @constructor
*/
CKEDITOR.plugins.add('ae_richcombobridge', {
requires: ['ae_uibridge'],
/**
* Set the add handler for UI_RICHCOMBO to our own. We do this in the init phase to override
* the one in the original plugin in case it's present
*
* @method init
* @param {Object} editor The CKEditor instance being initialized
*/
init: function(editor) {
editor.ui.addRichCombo = function(richComboName, richComboDefinition) {
this.add(richComboName, CKEDITOR.UI_RICHCOMBO, richComboDefinition);
};
editor.ui.addHandler(CKEDITOR.UI_RICHCOMBO, {
add: generateRichComboBridge,
create: function(richComboDefinition) {
var richComboName = 'richComboBridge' + ((Math.random() * 1e9) >>> 0);
var RichComboBridge = generateRichComboBridge(richComboName, richComboDefinition);
return new RichComboBridge();
}
});
}
});
}());