/** * Functions for HtmlEditorFields in the back end. * Includes the JS for the ImageUpload forms. * * Relies on the jquery.form.js plugin to power the * ajax / iframe submissions */ import $ from 'jQuery'; import i18n from 'i18n'; var ss = typeof window.ss !== 'undefined' ? window.ss : {}; /** * Wrapper for HTML WYSIWYG libraries, which abstracts library internals * from interface concerns like inserting and editing links. * Caution: Incomplete and unstable API. */ ss.editorWrappers = {}; ss.editorWrappers.tinyMCE = (function() { // ID of editor this is assigned to var editorID; return { /** * Initialise the editor * * @param {String} ID of parent textarea domID */ init: function(ID) { editorID = ID; this.create(); }, /** * Remove the editor and cleanup */ destroy: function() { tinymce.EditorManager.execCommand('mceRemoveEditor', false, editorID); }, /** * Get TinyMCE Editor instance * * @returns Editor */ getInstance: function() { return tinymce.EditorManager.get(editorID); }, /**( * Invoked when a content-modifying UI is opened. */ onopen: function() { // NOOP }, /**( * Invoked when a content-modifying UI is closed. */ onclose: function() { // NOOP }, /** * Get config for this data * * @returns array */ getConfig: function() { var selector = "#" + editorID, config = $(selector).data('config'), self = this; // Add instance specific data to config config.selector = selector; // Ensure save events write back to textarea config.setup = function(ed) { ed.on('change', function() { self.save(); }); }; return config; }, /** * Write the HTML back to the original text area field. */ save: function() { var instance = this.getInstance(); instance.save(); // Update change detection $(instance.getElement()).trigger("change"); }, /** * Create a new instance based on a textarea field. */ create: function() { var config = this.getConfig(); // hack to set baseURL safely if(typeof config.baseURL !== 'undefined') { tinymce.EditorManager.baseURL = config.baseURL; } tinymce.init(config); }, /** * Request an update to editor content */ repaint: function() { // NOOP }, /** * @return boolean */ isDirty: function() { return this.getInstance().isDirty(); }, /** * HTML representation of the edited content. * * Returns: {String} */ getContent: function() { return this.getInstance().getContent(); }, /** * DOM tree of the edited content * * Returns: DOMElement */ getDOM: function() { return this.getInstance().getElement(); }, /** * Returns: DOMElement */ getContainer: function() { return this.getInstance().getContainer(); }, /** * Get the closest node matching the current selection. * * Returns: {jQuery} DOMElement */ getSelectedNode: function() { return this.getInstance().selection.getNode(); }, /** * Select the given node within the editor DOM * * Parameters: {DOMElement} */ selectNode: function(node) { this.getInstance().selection.select(node); }, /** * Replace entire content * * @param {String} html * @param {Object} opts */ setContent: function(html, opts) { this.getInstance().setContent(html, opts); }, /** * Insert content at the current caret position * * @param {String} html * @param {Object} opts */ insertContent: function(html, opts) { this.getInstance().insertContent(html, opts); }, /** * Replace currently selected content * * @param {String} html */ replaceContent: function(html, opts) { this.getInstance().execCommand('mceReplaceContent', false, html, opts); }, /** * Insert or update a link in the content area (based on current editor selection) * * Parameters: {Object} attrs */ insertLink: function(attrs, opts) { this.getInstance().execCommand("mceInsertLink", false, attrs, opts); }, /** * Remove the link from the currently selected node (if any). */ removeLink: function() { this.getInstance().execCommand('unlink', false); }, /** * Strip any editor-specific notation from link in order to make it presentable in the UI. * * Parameters: * {Object} * {DOMElement} */ cleanLink: function(href, node) { var settings = this.getConfig, cb = settings['urlconverter_callback']; if(cb) href = eval(cb + "(href, node, true);"); // Turn into relative if(href.match(new RegExp('^' + tinyMCE.settings['document_base_url'] + '(.*)$'))) { href = RegExp.$1; } // Get rid of TinyMCE's temporary URLs if(href.match(/^javascript:\s*mctmp/)) href = ''; return href; }, /** * Creates a bookmark for the currently selected range, * which can be used to reselect this range at a later point. * @return {mixed} */ createBookmark: function() { return this.getInstance().selection.getBookmark(); }, /** * Selects a bookmarked range previously saved through createBookmark(). * @param {mixed} bookmark */ moveToBookmark: function(bookmark) { this.getInstance().selection.moveToBookmark(bookmark); this.getInstance().focus(); }, /** * Removes any selection & de-focuses this editor */ blur: function() { this.getInstance().selection.collapse(); }, /** * Add new undo point with the current DOM content. */ addUndo: function() { this.getInstance().undoManager.add(); } }; }); // Override this to switch editor wrappers ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE; $.entwine('ss', function($) { /** * Class: textarea.htmleditor * * Add tinymce to HtmlEditorFields within the CMS. Works in combination * with a TinyMCE.init() call which is prepopulated with the used HTMLEditorConfig settings, * and included in the page as an inline