diff --git a/README.md b/README.md index d69b8c3..7b909d7 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,19 @@ tinymce Editor 4.x / 5.x FootNotes Plugin. > **JQuery is required (tinymce 4.x)** +This is a fork of https://github.com/rainywalker/footNotes. Contrary to the original version, this one allows formatting footnotes with HTML (using tinyMCE) and it also supports using double quotes in footnotes. Note: the HTML formatting only works for tinyMCE 4.x, the 5.x plugin is unchanged from the original. + +The footnote plugin button in the menu bar of tinyMCE: + + + +The footnote plugin dialog: + + ## Principle -The text entered in the insert contents window is stored in the 'data-content' attribute +The text entered in the insert contents window is stored in the 'data-content' attribute. Double quotes and single quotes or apostrophes are replaced with their respective HTML entities. Double quotes in HTML attributes (e.g. the href for a link) will be replaced with single quotes so they don't break the data-content attribute in which they are contained. ```` //html of button inserted in editor diff --git a/screenshot_dialog.png b/screenshot_dialog.png new file mode 100644 index 0000000..d201aeb Binary files /dev/null and b/screenshot_dialog.png differ diff --git a/screenshot_menu.png b/screenshot_menu.png new file mode 100644 index 0000000..0d35bb4 Binary files /dev/null and b/screenshot_menu.png differ diff --git a/tinymce4.x/footnotes/img/footnotes.png b/tinymce4.x/footnotes/img/footnotes.png index 7715744..25a5bb8 100644 Binary files a/tinymce4.x/footnotes/img/footnotes.png and b/tinymce4.x/footnotes/img/footnotes.png differ diff --git a/tinymce4.x/footnotes/plugin.js b/tinymce4.x/footnotes/plugin.js index 1e8dea7..769b232 100644 --- a/tinymce4.x/footnotes/plugin.js +++ b/tinymce4.x/footnotes/plugin.js @@ -1,5 +1,5 @@ tinymce.PluginManager.add('footnotes', function(editor) { - + var footnoteText = null; function replaceTmpl(str, data) { var result = str; for (var key in data) { @@ -9,8 +9,10 @@ tinymce.PluginManager.add('footnotes', function(editor) { } function showDialog() { - var selectedNode = editor.selection.getNode(), name = '', - isFootNotes = selectedNode.tagName == 'SPAN' && editor.dom.getAttrib(selectedNode, 'class') === 'fnoteWrap'; + var selectedNode = editor.selection.getNode(); + var selectedRange = editor.selection.getRng().endContainer; + var name = ''; + var isFootNotes = selectedNode.tagName == 'SPAN' && editor.dom.getAttrib(selectedNode, 'class') === 'fnoteWrap'; var selectIndex = (function(){ if (selectedNode.className == 'fnoteWrap') { @@ -27,7 +29,7 @@ tinymce.PluginManager.add('footnotes', function(editor) { } editor.windowManager.open({ - title: "Insert a contents", + title: "Insert contents for footnote", id: 'footnote-dialog', body: { type: 'textbox', @@ -35,17 +37,18 @@ tinymce.PluginManager.add('footnotes', function(editor) { multiline: true, minWidth: 520, minHeight: 100, - value : name + value: name }, onSubmit: function(e) { - var newfootnoteContent = e.data.name, + var newfootnoteContent = footnoteText, fixFootnoteContent = (function () { - return encodeURIComponent(newfootnoteContent); + return newfootnoteContent; }()), - htmlTemplate = ' ', - totalFootNote = editor.getDoc().querySelectorAll('.fnoteBtn'), - totalCount = totalFootNote.length, - html; + htmlTemplate = ''; + + var totalFootNote = editor.getDoc().querySelectorAll('.fnoteBtn'); + var totalCount = totalFootNote.length; + var html; function findNextFD($node) { @@ -97,8 +100,10 @@ tinymce.PluginManager.add('footnotes', function(editor) { return currentClassNot_NextClass; } - var nextFD = findNextFD($(editor.selection.getRng().endContainer)); + // destroy the embedded footnote HTML editor + tinymce.activeEditor.destroy(); + var nextFD = findNextFD($(selectedRange)); if(nextFD.length) { nextFD = nextFD[0]; var foundIdx; @@ -110,6 +115,7 @@ tinymce.PluginManager.add('footnotes', function(editor) { if (selectIndex < totalCount) { // modify html = replaceTmpl(htmlTemplate,{FOOTNOTE_INDEX : $(totalFootNote[selectIndex-1]).html()}); + editor.selection.select(selectedNode); } else { // anywhere add @@ -132,12 +138,43 @@ tinymce.PluginManager.add('footnotes', function(editor) { }); } }); + tinymce.init({ + selector: '#footnote-dialog textarea', + content_css: '/css/frontend.css', + forced_root_block : 'div', + skin: false, + branding: false, + statusbar: true, + menubar: false, + plugins: ['link'], + toolbar: 'bold italic | link', + setup: function(editor) { + editor.on('init', function (e) { + editor.focus(); + }); + editor.on('keyup', function(e) { + footnoteText = sanitizeHtml(footnoteText = editor.getContent()); + }); + editor.on('change', function(e) { + footnoteText = sanitizeHtml(footnoteText = editor.getContent()); + }); + } + }); + } editor.addCommand('mceFootnotes', showDialog); editor.addButton("footnotes", { - title : 'footnote', - image : tinyMCE.baseURL + '/plugins/footnotes/img/footnotes.png', + title : 'Insert footnote', + image : tinyMCE.baseURL + '/tinymce/plugins/footnotesHtml/img/footnotes.png', onclick: showDialog, stateSelector: 'span.fnoteWrap' }); + + function sanitizeHtml(str) { + str = str.replaceAll('"', """); // first, replace all double quotes with entity – works for quotes in normal text + str = str.replaceAll("'", "'"); // also, replace all single quotes and apostrophes with entity + str = str.replace(/(\w+)\s*=\s*((")(.*?)\3|([^>\s]*)(?=\s|\/>))(?=[^<]*>)/g, "$1='$4'"); // now replace " with single quotes in attributes + return str; + } }); + \ No newline at end of file diff --git a/tinymce4.x/footnotes/plugin.min.js b/tinymce4.x/footnotes/plugin.min.js index f52c5ac..3929960 100644 --- a/tinymce4.x/footnotes/plugin.min.js +++ b/tinymce4.x/footnotes/plugin.min.js @@ -1 +1 @@ -tinymce.PluginManager.add("footnotes",function(t){function n(t,n){var e=t;for(var o in n)e=e.replace("{"+o+"}",n[o]);return e}function e(){var e=t.selection.getNode(),o="",a="SPAN"==e.tagName&&"fnoteWrap"===t.dom.getAttrib(e,"class"),i=function(){if("fnoteWrap"==e.className){var t=e.childNodes[0].firstChild.nodeValue.replace(/[^0-9]/g,"");return t}return e.childNodes[0]}();a&&(o=e.name||decodeURIComponent(e.childNodes[0].getAttribute("data-content"))||""),t.windowManager.open({title:"Insert a contents",id:"footnote-dialog",body:{type:"textbox",name:"name",multiline:!0,minWidth:520,minHeight:100,value:o},onSubmit:function(e){function o(t){function n(t,n){for(var a=e(n);0!==a.length;){var i=o(t,a);if(null!==i)return i;a=e(a)}return a}function e(t){return t.nextAll().find(".fnoteBtn").length>0?t.next().hasClass("fnoteBtn")?t.next().children().children():t.nextAll().find(".fnoteBtn"):"BODY"==t.prop("nodeName")?[]:e(t.parent())}function o(t,n){if(!n)return!1;if(n)return n;var e=null;return n.children().each(function(){n&&(e=o(t,$(this)))}),e}var a=n(".fnoteBtn",t);return a}var a,r=e.data.name,l=function(){return encodeURIComponent(r)}(),c=' ',f=t.getDoc().querySelectorAll(".fnoteBtn"),s=f.length,d=o($(t.selection.getRng().endContainer));if(d.length){d=d[0];var u;for(u=0;u{FOOTNOTE_INDEX}',s=t.getDoc().querySelectorAll(".fnoteBtn"),f=s.length;tinymce.activeEditor.destroy();var u=function(t){function n(t){return t.nextAll().find(".fnoteBtn").length>0?t.next().hasClass("fnoteBtn")?t.next().children().children():t.nextAll().find(".fnoteBtn"):"BODY"==t.prop("nodeName")?[]:n(t.parent())}function e(t,n){if(!n)return!1;if(n)return n;var o=null;return n.children().each(function(){n&&(o=e(t,$(this)))}),o}return function(t,o){for(var i=n(o);0!==i.length;){var a=e(t,i);if(null!==a)return a;i=n(i)}return i}(".fnoteBtn",t)}($(a));if(u.length){var d;for(u=u[0],d=0;d\s]*)(?=\s|\/>))(?=[^<]*>)/g,"$1='$4'")}t.addCommand("mceFootnotes",o),t.addButton("footnotes",{title:"Insert footnote",image:tinyMCE.baseURL+"/tinymce/plugins/footnotesHtml/img/footnotes.png",onclick:o,stateSelector:"span.fnoteWrap"})}); \ No newline at end of file diff --git a/tinymce5.x/footnotes/img/footnotes.png b/tinymce5.x/footnotes/img/footnotes.png index 7715744..25a5bb8 100644 Binary files a/tinymce5.x/footnotes/img/footnotes.png and b/tinymce5.x/footnotes/img/footnotes.png differ