/** * Basic sample plugin inserting footnotes elements into CKEditor editing area. * * Version 1.0.9 * https://github.com/andykirk/CKEditorFootnotes * */ // Register the plugin within the editor. (function() { "use strict"; CKEDITOR.plugins.add( 'footnotes', { footnote_ids: [], requires: 'widget', icons: 'footnotes', // The plugin initialization logic goes inside this method. init: function(editor) { // Allow `cite` to be editable: CKEDITOR.dtd.$editable['cite'] = 1; // Add some CSS tweaks: var css = '.footnotes{background:#eee; padding:1px 15px;} .footnotes cite{font-style: normal;}'; CKEDITOR.addCss(css); var $this = this; /*editor.on('saveSnapshot', function(evt) { console.log('saveSnapshot'); });*/ // Force a reorder on startup to make sure all vars are set: (e.g. footnotes store): editor.on('instanceReady', function(evt) { $this.reorderMarkers(editor); }); // Add the reorder change event: editor.on('change', function(evt) { // Copy the footnotes_store as we may be doing a cut: if(!evt.editor.footnotes_tmp) { evt.editor.footnotes_tmp = evt.editor.footnotes_store; } // Prevent no selection errors: if (!evt.editor.getSelection().getStartElement()) { return; } // Don't reorder the markers if editing a cite: var footnote_section = evt.editor.getSelection().getStartElement().getAscendant('section'); if (footnote_section && footnote_section.$.className.indexOf('footnotes') != -1) { return; } // SetTimeout seems to be necessary (it's used in the core but can't be 100% sure why) setTimeout(function(){ $this.reorderMarkers(editor); }, 0 ); }); // Build the initial footnotes widget editables definition: var prefix = editor.config.footnotesPrefix ? '-' + editor.config.footnotesPrefix : ''; var def = { header: { selector: 'header > *', //allowedContent: '' allowedContent: 'strong em span sub sup;' } }; // Get the number of existing footnotes. Note that the editor document isn't populated // yet so we need to use vanilla JS: var div = document.createElement('div'); div.innerHTML = editor.element.$.textContent.trim(); var l = div.querySelectorAll('.footnotes li').length, i = 1; for (i; i <= l; i++) { def['footnote_' + i] = {selector: '#footnote' + prefix + '-' + i + ' cite', allowedContent: 'a[href]; cite[*](*); strong em span br'}; } // Register the footnotes widget. editor.widgets.add('footnotes', { // Minimum HTML which is required by this widget to work. requiredContent: 'section(footnotes)', // Check the elements that need to be converted to widgets. upcast: function(element) { return element.name == 'section' && element.hasClass('footnotes'); }, editables: def }); // Register the footnotemarker widget. editor.widgets.add('footnotemarker', { // Minimum HTML which is required by this widget to work. requiredContent: 'sup[data-footnote-id]', // Check the elements that need to be converted to widgets. upcast: function(element) { return element.name == 'sup' && typeof(element.attributes['data-footnote-id']) != 'undefined'; }, }); // Define an editor command that opens our dialog. editor.addCommand('footnotes', new CKEDITOR.dialogCommand('footnotesDialog', { // @TODO: This needs work: allowedContent: 'section[*](*);header[*](*);li[*];a[*];cite(*)[*];sup[*]', requiredContent: 'section[*](*);header[*](*);li[*];a[*];cite(*)[*];sup[*]' })); // Create a toolbar button that executes the above command. editor.ui.addButton('Footnotes', { // The text part of the button (if available) and tooptip. label: 'Insert Footnotes', // The command to execute on click. command: 'footnotes', // The button placement in the toolbar (toolbar group name). toolbar: 'insert' }); // Register our dialog file. this.path is the plugin folder path. CKEDITOR.dialog.add('footnotesDialog', this.path + 'dialogs/footnotes.js'); }, build: function(footnote, is_new, editor) { var footnote_id; if (is_new) { // Generate new id: footnote_id = this.generateFootnoteId(); } else { // Existing footnote id passed: footnote_id = footnote; } // Insert the marker: var footnote_marker = 'X'; editor.insertHtml(footnote_marker); if (is_new) { editor.fire('lockSnapshot'); this.addFootnote(this.buildFootnote(footnote_id, footnote, false, editor), editor); editor.fire('unlockSnapshot'); } this.reorderMarkers(editor); }, buildFootnote: function(footnote_id, footnote_text, data, editor) { var links = '', footnote, letters = 'abcdefghijklmnopqrstuvwxyz', order = data ? data.order.indexOf(footnote_id) + 1 : 1, prefix = editor.config.footnotesPrefix ? '-' + editor.config.footnotesPrefix : ''; if (data && data.occurrences[footnote_id] == 1) { links = '^ '; } else if (data && data.occurrences[footnote_id] > 1) { var i = 0 , l = data.occurrences[footnote_id] , n = l; for (i; i < l; i++) { links += '' + letters.charAt(i) + ''; if (i < l-1) { links += ', '; } else { links += ' '; } } } footnote = '