UNPKG

apostrophe

Version:

The Apostrophe Content Management System.

181 lines (147 loc) 5.93 kB
apos.define('apostrophe-rich-text-widgets-editor', { afterConstruct: function(self) { return self.start(); }, construct: function(self, options) { self.options = options; self.$widget = options.$widget; // Start contextual editing (on click for instance) self.start = function() { if (self.started || options.readOnly) { return; } self.$widget.trigger('aposRichTextStarting'); self.$richText = self.$widget.find('[data-rich-text]:first'); self.id = self.$richText.attr('id'); if (!self.id) { // Must have one for ckeditor self.id = apos.utils.generateId(); self.$richText.attr('id', self.id); } self.$richText.attr('contenteditable', 'true'); // Support for ckeditor4 styles self.styles = self.options.styles || []; // Allow both universal A2 and ckeditor-specific controls in the toolbar. // Don't worry about widgets, those are presented separately. self.toolbar = self.options.toolbar || []; if (!self.defaultStyle) { if (self.options.defaultElement) { // eslint-disable-next-line new-cap self.defaultStyle = new CKEDITOR.style({ element: self.options.defaultElement }); } else if (self.styles.length) { var defaultStyle = _.find(self.styles, { name: self.options.defaultStyle }); if (defaultStyle) { // eslint-disable-next-line new-cap self.defaultStyle = new CKEDITOR.style(defaultStyle); } } } // This will allow loading of extra plugins for each editor var extraPlugins = [ 'split' ]; // Additional standard plugins can be configured // simply by name, third-party plugins need an // object with name and path properties _.each(options.plugins, function(plugin) { if (plugin.path) { // Make sure we don't have it already due to // another instance plugin = CKEDITOR.plugins.get(plugin.name) || plugin; if (plugin !== null) { CKEDITOR.plugins.addExternal(plugin.name, plugin.path); } } extraPlugins.push(plugin.name || plugin); }); extraPlugins = extraPlugins.join(','); self.config = { extraPlugins: extraPlugins, toolbar: [ self.toolbar ], stylesSet: self.styles, on: { // TODO these event handlers should check whether the ckeditor ckeditorInstance // really belongs to apostrophe and play nice if not pluginsLoaded: function(evt) { var cmd = evt.editor.getCommand('table'); // Don't allow table elements, properties and styles that // complicate responsive design cmd.allowedContent = 'table tr th td'; }, instanceReady: function(ck) { ck.editor.aposWidgetEditor = self; } } }; if (!self.toolbar.length) { // We can't remove the toolbar because of: // https://github.com/ckeditor/ckeditor-dev/issues/654` // To avoid errors and a nonfunctional editor we have to put up // with an empty toolbar; it would be further progress to figure // out a way to at least hide it // self.config.removePlugins = 'toolbar'; } else { // These are the buttons that we want to remove from CKEDITOR's default // config, but not if the developer has requested them var removeButtons = ['Underline', 'Subscript', 'Superscript'].filter(function(button) { return !_.includes(self.toolbar, button); }); self.config.removeButtons = removeButtons.join(','); } self.beforeCkeditorInline(); self.ckeditorInstance = CKEDITOR.inline(self.id, self.config); self.focus = false; self.ckeditorInstance.on('focus', function() { self.focus = true; self.setActive(true); }); self.ckeditorInstance.on('blur', function() { self.focus = false; self.setActive(false); }); self.ckeditorInstance.on('instanceReady', function(event) { self.ckeditorInstance.focus(); if (self.ckeditorInstance.getData() === '') { if (self.defaultStyle) { self.ckeditorInstance.applyStyle(self.defaultStyle); } } self.$richText.data('aposRichTextState', 'started'); self.$widget.trigger('aposRichTextStarted'); }); self.setActive(true); self.started = true; }; // End contextual editing (on blur for instance) self.stop = function() { // make sure there is a blur event before // the destruction takes place var data = self.ckeditorInstance.getData(); self.ckeditorInstance.focusManager.blur(true); self.ckeditorInstance.destroy(); self.ckeditorInstance = null; self.$richText.removeAttr('contenteditable'); self.$richText.html(data); self.$richText.data('aposRichTextState', undefined); self.$widget.trigger('aposRichTextStopped'); self.started = false; self.setActive(false); }; // Trigger `aposRichTextActive` or `aposRichTextInactive` // on the widget's DOM element and set or clear the // `apos-active` CSS class. Reflects what has already happened // at the ckeditor level, called on blur and focus events. // Does not start and stop editing, not to be called directly. self.setActive = function(state) { self.$widget.trigger(state ? 'aposRichTextActive' : 'aposRichTextInactive'); return self.$widget.toggleClass('apos-active', state); }; // A convenient override point just before // `self.id` and `self.config` are passed to // `CKEDITOR.inline` to launch editing self.beforeCkeditorInline = function() { }; } });