From b0cd8c2fc656a0e357cbb4ac8a212c3dd4301f24 Mon Sep 17 00:00:00 2001 From: Andy Kirk Date: Tue, 5 Aug 2014 12:59:24 +0100 Subject: [PATCH 1/2] Fixed to allow multiple instances --- footnotes/dialogs/footnotes.js | 37 +++++++------- footnotes/plugin.js | 90 +++++++++++++++++----------------- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/footnotes/dialogs/footnotes.js b/footnotes/dialogs/footnotes.js index fc12b6f..6e70001 100644 --- a/footnotes/dialogs/footnotes.js +++ b/footnotes/dialogs/footnotes.js @@ -1,4 +1,4 @@ -/** +/** * The footnotes dialog definition. * * Created out of the CKEditor Plugin SDK: @@ -7,6 +7,7 @@ // Dialog definition. CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { + return { editor_name: false, // Basic properties of the dialog window: title, minimum size. @@ -38,19 +39,19 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { id: 'footnote_id', name: 'footnote_id', label: 'No existing footnotes', - + // Called by the main setupContent call on dialog initialization. setup: function( element ) { var dialog = this.getDialog(); $el = jQuery('#' + this.domId); - + dialog.footnotes_el = $el; - + editor = dialog.getParentEditor(); // Dynamically add existing footnotes: $footnotes = jQuery('#' + editor.id + '_contents iframe').contents().find('#footnotes ol'); - $this = this; + $this = this; if ($footnotes.length > 0) { if ($el.find('p').length == 0) { @@ -58,20 +59,20 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { } else { $el.find('ol').empty(); } - + var radios = ''; $footnotes.find('li').each(function(){ $item = jQuery(this); var footnote_id = $item.attr('data-footnote-id'); radios += '
  • '; }); - + $el.children('label,div').css('display', 'none'); $el.find('ol').html(radios); $el.find(':radio').change(function(){; $el.find(':text').val(jQuery(this).val()); }); - + } else { $el.children('div').css('display', 'none'); } @@ -80,7 +81,7 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { ] }, ], - + // Invoked when the dialog is loaded. onShow: function() { this.setupContent(); @@ -90,7 +91,7 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { dialog.editor_name = evt.editor.name; } ); - + CKEDITOR.replaceAll( function( textarea, config ) { if (!textarea.className.match(/footnote_text/)) { return false; @@ -107,7 +108,7 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { config.resize_enabled = false; config.autoGrow_minHeight = 80; config.removePlugins = 'footnotes'; - + config.on = { focus: function( evt ){ var $editor_el = jQuery('#' + evt.editor.id + '_contents'); @@ -117,18 +118,18 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { }; return true; }); - + }, // This method is invoked once a user clicks the OK button, confirming the dialog. onOk: function() { var dialog = this; - + var footnote_editor = CKEDITOR.instances[dialog.editor_name]; var footnote_id = dialog.getValueOf('tab-basic', 'footnote_id'); - + editor.fire('saveSnapshot'); - + if (footnote_id == '') { // No existing id selected, check for new footnote: var new_footnote = footnote_editor.getData(); @@ -137,15 +138,15 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { return; } else { // Insert new footnote: - editor.plugins.footnotes.build(new_footnote, true); + editor.plugins.footnotes.build(new_footnote, true, editor); } } else { // Insert existing footnote: - editor.plugins.footnotes.build(footnote_id, false); + editor.plugins.footnotes.build(footnote_id, false, editor); } // Destroy the editor so it's rebuilt properly next time: footnote_editor.destroy(); return; } }; -}); \ No newline at end of file +}); diff --git a/footnotes/plugin.js b/footnotes/plugin.js index 83a0a84..ae99195 100644 --- a/footnotes/plugin.js +++ b/footnotes/plugin.js @@ -1,4 +1,4 @@ -/** +/** * Basic sample plugin inserting footnotes elements into CKEditor editing area. * * Created out of the CKEditor Plugin SDK: @@ -7,24 +7,21 @@ // Register the plugin within the editor. CKEDITOR.plugins.add( 'footnotes', { - - editor: false, - footnote_ids: [], + + footnote_ids: [], requires: 'widget', icons: 'footnotes', - + // The plugin initialization logic goes inside this method. init: function(editor) { - this.editor = 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); - + // Add the reorder change event: var $this = this; editor.on('change', function(evt) { @@ -35,12 +32,12 @@ CKEDITOR.plugins.add( 'footnotes', { } // SetTimeout seems to be necessary (it's used in the core but can't be 100% sure why) setTimeout(function(){ - $this.reorderMarkers(); + $this.reorderMarkers(editor); }, 0 ); }); - + // Build the initial footnotes widget editables definition: var def = { header: { @@ -55,10 +52,10 @@ CKEDITOR.plugins.add( 'footnotes', { for (i; i <= l; i++) { def['footnote_' + i] = {selector: '#footnote-' + i +' cite', allowedContent: 'a[href]; cite[*](*); b i span'}; } - + // Register the footnotes widget. editor.widgets.add('footnotes', { - + // Minimum HTML which is required by this widget to work. requiredContent: 'section(footnotes)', @@ -66,10 +63,10 @@ CKEDITOR.plugins.add( 'footnotes', { upcast: function(element) { return element.name == 'section' && element.hasClass('footnotes'); }, - + editables: def }); - + // Register the footnotemarker widget. editor.widgets.add('footnotemarker', { @@ -105,10 +102,10 @@ CKEDITOR.plugins.add( 'footnotes', { // 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) { - this.editor.fire('lockSnapshot'); + + build: function(footnote, is_new, editor) { + editor.fire('lockSnapshot'); if (is_new) { // Generate new id: footnote_id = this.generateFootnoteId(); @@ -120,16 +117,16 @@ CKEDITOR.plugins.add( 'footnotes', { // Insert the marker: var footnote_marker = 'X'; - this.editor.fire('unlockSnapshot'); - this.editor.insertHtml(footnote_marker); - + editor.fire('unlockSnapshot'); + editor.insertHtml(footnote_marker); + if (is_new) { - this.addFootnote(this.buildFootnote(footnote_id, footnote)); + this.addFootnote(this.buildFootnote(footnote_id, footnote), editor); } - this.reorderMarkers(); + this.reorderMarkers(editor); }, - + buildFootnote: function(footnote_id, footnote_text, data) { data ? data : false; var links = ''; @@ -154,25 +151,25 @@ CKEDITOR.plugins.add( 'footnotes', { footnote = '
  • ' + links + '' + footnote_text + '
  • '; return footnote; }, - - addFootnote: function(footnote) { - $contents = jQuery('#' + this.editor.id + '_contents iframe').contents().find('body'); + + addFootnote: function(footnote, editor) { + $contents = jQuery('#' + editor.id + '_contents iframe').contents().find('body'); $footnotes = $contents.find('#footnotes'); - + if ($footnotes.length == 0) { var container = '

    Footnotes

      ' + footnote + '
    '; // Move cursor to end of content: - var range = this.editor.createRange(); + var range = editor.createRange(); range.moveToElementEditEnd(range.root); - this.editor.getSelection().selectRanges([range]); + editor.getSelection().selectRanges([range]); // Insert the container: - this.editor.insertHtml(container); + editor.insertHtml(container); } else { $footnotes.find('ol').append(footnote); } return; }, - + generateFootnoteId: function() { var id = Math.random().toString(36).substr(2, 5); while (jQuery.inArray(id, this.footnote_ids) != -1) { @@ -181,16 +178,21 @@ CKEDITOR.plugins.add( 'footnotes', { this.footnote_ids.push(id); return id; }, - - reorderMarkers: function() { - this.editor.fire('lockSnapshot'); - editor = this.editor; + + reorderMarkers: function(editor) { + editor.fire('lockSnapshot'); $contents = jQuery('#' + editor.id + '_contents iframe').contents().find('body'); var data = { order: [], occurrences: {} }; + // Check that there's a footnotes section. If it's been deleted the markers are useless: + if ($contents.find('#footnotes').length == 0) { + $contents.find('sup[data-footnote-id]').remove(); + return; + } + // Find all the markers in the document: var $markers = $contents.find('sup[data-footnote-id]'); // If there aren't any, remove the Footnotes container: @@ -198,13 +200,13 @@ CKEDITOR.plugins.add( 'footnotes', { $contents.find('#footnotes').remove(); return; } - + // Otherwise reorder the markers: $markers.each(function(){ var footnote_id = jQuery(this).attr('data-footnote-id') , marker_ref , n = data.order.indexOf(footnote_id); - + // If this is the markers first occurrence: if (n == -1) { // Store the id: @@ -223,7 +225,7 @@ CKEDITOR.plugins.add( 'footnotes', { var marker = '[' + n + ']'; jQuery(this).html(marker); }); - + // Then rebuild the Footnotes content to match marker order: var footnotes = ''; var footnote_text = ''; @@ -233,16 +235,16 @@ CKEDITOR.plugins.add( 'footnotes', { footnotes += this.buildFootnote(footnote_id, footnote_text, data); } $contents.find('#footnotes ol').html(footnotes); - + // Next we need to reinstate the 'editable' properties of the footnotes. // (we have to do this individually due to Widgets 'fireOnce' for editable selectors) var el = $contents.find('#footnotes') , footnote_widget; // So first we need to find the right Widget instance: // (I hope there's a better way of doing this but I can't find one) - for (i in this.editor.widgets.instances) { - if (this.editor.widgets.instances[i].name == 'footnotes') { - footnote_widget = this.editor.widgets.instances[i]; + for (i in editor.widgets.instances) { + if (editor.widgets.instances[i].name == 'footnotes') { + footnote_widget = editor.widgets.instances[i]; break; } } @@ -252,7 +254,7 @@ CKEDITOR.plugins.add( 'footnotes', { footnote_widget.initEditable('footnote_' + n, {selector: '#footnote-' + n +' cite', allowedContent: 'a[href]; cite[*](*); b i span'}); } - this.editor.fire('unlockSnapshot'); + editor.fire('unlockSnapshot'); return; } }); From f510c0798ac6ca5822dad253caf92fd3669d088e Mon Sep 17 00:00:00 2001 From: Andy Kirk Date: Wed, 13 Aug 2014 07:59:07 +0100 Subject: [PATCH 2/2] Fixed line-break crash --- footnotes/dialogs/footnotes.js | 5 +++-- footnotes/plugin.js | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/footnotes/dialogs/footnotes.js b/footnotes/dialogs/footnotes.js index 6e70001..6593af1 100644 --- a/footnotes/dialogs/footnotes.js +++ b/footnotes/dialogs/footnotes.js @@ -102,12 +102,13 @@ CKEDITOR.dialog.add( 'footnotesDialog', function( editor ) { { name: 'clipboard', groups: [ 'clipboard' ] }, { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] }, ] - config.allowedContent = 'b i; a[!href]'; + config.allowedContent = 'br b i; a[!href]'; + config.enterMode = CKEDITOR.ENTER_BR; config.autoParagraph = false; config.height = 80; config.resize_enabled = false; config.autoGrow_minHeight = 80; - config.removePlugins = 'footnotes'; + config.removePlugins = 'footnotes';//,elementspath'; config.on = { focus: function( evt ){ diff --git a/footnotes/plugin.js b/footnotes/plugin.js index ae99195..fdcf2a9 100644 --- a/footnotes/plugin.js +++ b/footnotes/plugin.js @@ -25,6 +25,10 @@ CKEDITOR.plugins.add( 'footnotes', { // Add the reorder change event: var $this = this; editor.on('change', function(evt) { + // 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.$.id == 'footnotes') { @@ -50,7 +54,7 @@ CKEDITOR.plugins.add( 'footnotes', { , l = contents.find('#footnotes li').length , i = 1; for (i; i <= l; i++) { - def['footnote_' + i] = {selector: '#footnote-' + i +' cite', allowedContent: 'a[href]; cite[*](*); b i span'}; + def['footnote_' + i] = {selector: '#footnote-' + i +' cite', allowedContent: 'a[href]; cite[*](*); b i span br'}; } // Register the footnotes widget.