diff options
Diffstat (limited to 'src/main/resources/static/plugins/summernote/plugin')
4 files changed, 700 insertions, 0 deletions
diff --git a/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.css b/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.css new file mode 100644 index 0000000..6232dde --- /dev/null +++ b/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.css @@ -0,0 +1,16 @@ +.ext-databasic { + position: relative; + display: block; + min-height: 50px; + background-color: cyan; + text-align: center; + padding: 20px; + border: 1px solid white; + border-radius: 10px; +} + +.ext-databasic p { + color: white; + font-size: 1.2em; + margin: 0; +} diff --git a/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.js b/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.js new file mode 100644 index 0000000..749a867 --- /dev/null +++ b/src/main/resources/static/plugins/summernote/plugin/databasic/summernote-ext-databasic.js @@ -0,0 +1,291 @@ +(function(factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(window.jQuery); + } +}(function($) { + // pull in some summernote core functions + var ui = $.summernote.ui; + var dom = $.summernote.dom; + + // define the popover plugin + var DataBasicPlugin = function(context) { + var self = this; + var options = context.options; + var lang = options.langInfo; + + self.icon = '<i class="fa fa-object-group"></i>'; + + // add context menu button for dialog + context.memo('button.databasic', function() { + return ui.button({ + contents: self.icon, + tooltip: lang.databasic.insert, + click: context.createInvokeHandler('databasic.showDialog'), + }).render(); + }); + + // add popover edit button + context.memo('button.databasicDialog', function() { + return ui.button({ + contents: self.icon, + tooltip: lang.databasic.edit, + click: context.createInvokeHandler('databasic.showDialog'), + }).render(); + }); + + // add popover size buttons + context.memo('button.databasicSize100', function() { + return ui.button({ + contents: '<span class="note-fontsize-10">100%</span>', + tooltip: lang.image.resizeFull, + click: context.createInvokeHandler('editor.resize', '1'), + }).render(); + }); + context.memo('button.databasicSize50', function() { + return ui.button({ + contents: '<span class="note-fontsize-10">50%</span>', + tooltip: lang.image.resizeHalf, + click: context.createInvokeHandler('editor.resize', '0.5'), + }).render(); + }); + context.memo('button.databasicSize25', function() { + return ui.button({ + contents: '<span class="note-fontsize-10">25%</span>', + tooltip: lang.image.resizeQuarter, + click: context.createInvokeHandler('editor.resize', '0.25'), + }).render(); + }); + + self.events = { + 'summernote.init': function(we, e) { + // update existing containers + $('data.ext-databasic', e.editable).each(function() { self.setContent($(this)); }); + // TODO: make this an undo snapshot... + }, + 'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function() { + self.update(); + }, + 'summernote.dialog.shown': function() { + self.hidePopover(); + }, + }; + + self.initialize = function() { + // create dialog markup + var $container = options.dialogsInBody ? $(document.body) : context.layoutInfo.editor; + + var body = '<div class="form-group row-fluid">' + + '<label>' + lang.databasic.testLabel + '</label>' + + '<input class="ext-databasic-test form-control" type="text" />' + + '</div>'; + var footer = '<button href="#" class="btn btn-primary ext-databasic-save">' + lang.databasic.insert + '</button>'; + + self.$dialog = ui.dialog({ + title: lang.databasic.name, + fade: options.dialogsFade, + body: body, + footer: footer, + }).render().appendTo($container); + + // create popover + self.$popover = ui.popover({ + className: 'ext-databasic-popover', + }).render().appendTo('body'); + var $content = self.$popover.find('.popover-content'); + + context.invoke('buttons.build', $content, options.popover.databasic); + }; + + self.destroy = function() { + self.$popover.remove(); + self.$popover = null; + self.$dialog.remove(); + self.$dialog = null; + }; + + self.update = function() { + // Prevent focusing on editable when invoke('code') is executed + if (!context.invoke('editor.hasFocus')) { + self.hidePopover(); + return; + } + + var rng = context.invoke('editor.createRange'); + var visible = false; + + if (rng.isOnData()) { + var $data = $(rng.sc).closest('data.ext-databasic'); + + if ($data.length) { + var pos = dom.posFromPlaceholder($data[0]); + + self.$popover.css({ + display: 'block', + left: pos.left, + top: pos.top, + }); + + // save editor target to let size buttons resize the container + context.invoke('editor.saveTarget', $data[0]); + + visible = true; + } + } + + // hide if not visible + if (!visible) { + self.hidePopover(); + } + }; + + self.hidePopover = function() { + self.$popover.hide(); + }; + + // define plugin dialog + self.getInfo = function() { + var rng = context.invoke('editor.createRange'); + + if (rng.isOnData()) { + var $data = $(rng.sc).closest('data.ext-databasic'); + + if ($data.length) { + // Get the first node on range(for edit). + return { + node: $data, + test: $data.attr('data-test'), + }; + } + } + + return {}; + }; + + self.setContent = function($node) { + $node.html('<p contenteditable="false">' + self.icon + ' ' + lang.databasic.name + ': ' + + $node.attr('data-test') + '</p>'); + }; + + self.updateNode = function(info) { + self.setContent(info.node + .attr('data-test', info.test)); + }; + + self.createNode = function(info) { + var $node = $('<data class="ext-databasic"></data>'); + + if ($node) { + // save node to info structure + info.node = $node; + // insert node into editor dom + context.invoke('editor.insertNode', $node[0]); + } + + return $node; + }; + + self.showDialog = function() { + var info = self.getInfo(); + var newNode = !info.node; + context.invoke('editor.saveRange'); + + self + .openDialog(info) + .then(function(dialogInfo) { + // [workaround] hide dialog before restore range for IE range focus + ui.hideDialog(self.$dialog); + context.invoke('editor.restoreRange'); + + // insert a new node + if (newNode) { + self.createNode(info); + } + + // update info with dialog info + $.extend(info, dialogInfo); + + self.updateNode(info); + }) + .fail(function() { + context.invoke('editor.restoreRange'); + }); + }; + + self.openDialog = function(info) { + return $.Deferred(function(deferred) { + var $inpTest = self.$dialog.find('.ext-databasic-test'); + var $saveBtn = self.$dialog.find('.ext-databasic-save'); + var onKeyup = function(event) { + if (event.keyCode === 13) { + $saveBtn.trigger('click'); + } + }; + + ui.onDialogShown(self.$dialog, function() { + context.triggerEvent('dialog.shown'); + + $inpTest.val(info.test).on('input', function() { + ui.toggleBtn($saveBtn, $inpTest.val()); + }).trigger('focus').on('keyup', onKeyup); + + $saveBtn + .text(info.node ? lang.databasic.edit : lang.databasic.insert) + .click(function(event) { + event.preventDefault(); + + deferred.resolve({ test: $inpTest.val() }); + }); + + // init save button + ui.toggleBtn($saveBtn, $inpTest.val()); + }); + + ui.onDialogHidden(self.$dialog, function() { + $inpTest.off('input keyup'); + $saveBtn.off('click'); + + if (deferred.state() === 'pending') { + deferred.reject(); + } + }); + + ui.showDialog(self.$dialog); + }); + }; + }; + + // Extends summernote + $.extend(true, $.summernote, { + plugins: { + databasic: DataBasicPlugin, + }, + + options: { + popover: { + databasic: [ + ['databasic', ['databasicDialog', 'databasicSize100', 'databasicSize50', 'databasicSize25']], + ], + }, + }, + + // add localization texts + lang: { + 'en-US': { + databasic: { + name: 'Basic Data Container', + insert: 'insert basic data container', + edit: 'edit basic data container', + testLabel: 'test input', + }, + }, + }, + + }); +})); diff --git a/src/main/resources/static/plugins/summernote/plugin/hello/summernote-ext-hello.js b/src/main/resources/static/plugins/summernote/plugin/hello/summernote-ext-hello.js new file mode 100644 index 0000000..f95d302 --- /dev/null +++ b/src/main/resources/static/plugins/summernote/plugin/hello/summernote-ext-hello.js @@ -0,0 +1,82 @@ +(function(factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(window.jQuery); + } +}(function($) { + // Extends plugins for adding hello. + // - plugin is external module for customizing. + $.extend($.summernote.plugins, { + /** + * @param {Object} context - context object has status of editor. + */ + 'hello': function(context) { + var self = this; + + // ui has renders to build ui elements. + // - you can create a button with `ui.button` + var ui = $.summernote.ui; + + // add hello button + context.memo('button.hello', function() { + // create button + var button = ui.button({ + contents: '<i class="fa fa-child"/> Hello', + tooltip: 'hello', + click: function() { + self.$panel.show(); + self.$panel.hide(500); + // invoke insertText method with 'hello' on editor module. + context.invoke('editor.insertText', 'hello'); + }, + }); + + // create jQuery object from button instance. + var $hello = button.render(); + return $hello; + }); + + // This events will be attached when editor is initialized. + this.events = { + // This will be called after modules are initialized. + 'summernote.init': function(we, e) { + // eslint-disable-next-line + console.log('summernote initialized', we, e); + }, + // This will be called when user releases a key on editable. + 'summernote.keyup': function(we, e) { + // eslint-disable-next-line + console.log('summernote keyup', we, e); + }, + }; + + // This method will be called when editor is initialized by $('..').summernote(); + // You can create elements for plugin + this.initialize = function() { + this.$panel = $('<div class="hello-panel"/>').css({ + position: 'absolute', + width: 100, + height: 100, + left: '50%', + top: '50%', + background: 'red', + }).hide(); + + this.$panel.appendTo('body'); + }; + + // This methods will be called when editor is destroyed by $('..').summernote('destroy'); + // You should remove elements on `initialize`. + this.destroy = function() { + this.$panel.remove(); + this.$panel = null; + }; + }, + }); +})); diff --git a/src/main/resources/static/plugins/summernote/plugin/specialchars/summernote-ext-specialchars.js b/src/main/resources/static/plugins/summernote/plugin/specialchars/summernote-ext-specialchars.js new file mode 100644 index 0000000..d80eb19 --- /dev/null +++ b/src/main/resources/static/plugins/summernote/plugin/specialchars/summernote-ext-specialchars.js @@ -0,0 +1,311 @@ +(function(factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(window.jQuery); + } +}(function($) { + $.extend($.summernote.plugins, { + 'specialchars': function(context) { + var self = this; + var ui = $.summernote.ui; + + var $editor = context.layoutInfo.editor; + var options = context.options; + var lang = options.langInfo; + + var KEY = { + UP: 38, + DOWN: 40, + LEFT: 37, + RIGHT: 39, + ENTER: 13, + }; + var COLUMN_LENGTH = 12; + var COLUMN_WIDTH = 35; + + var currentColumn = 0; + var currentRow = 0; + var totalColumn = 0; + var totalRow = 0; + + // special characters data set + var specialCharDataSet = [ + '"', '&', '<', '>', '¡', '¢', + '£', '¤', '¥', '¦', '§', + '¨', '©', 'ª', '«', '¬', + '®', '¯', '°', '±', '²', + '³', '´', 'µ', '¶', '·', + '¸', '¹', 'º', '»', '¼', + '½', '¾', '¿', '×', '÷', + 'ƒ', 'ˆ', '˜', '–', '—', + '‘', '’', '‚', '“', '”', + '„', '†', '‡', '•', '…', + '‰', '′', '″', '‹', '›', + '‾', '⁄', '€', 'ℑ', '℘', + 'ℜ', '™', 'ℵ', '←', '↑', + '→', '↓', '↔', '↵', '⇐', + '⇑', '⇒', '⇓', '⇔', '∀', + '∂', '∃', '∅', '∇', '∈', + '∉', '∋', '∏', '∑', '−', + '∗', '√', '∝', '∞', '∠', + '∧', '∨', '∩', '∪', '∫', + '∴', '∼', '≅', '≈', '≠', + '≡', '≤', '≥', '⊂', '⊃', + '⊄', '⊆', '⊇', '⊕', '⊗', + '⊥', '⋅', '⌈', '⌉', '⌊', + '⌋', '◊', '♠', '♣', '♥', + '♦', + ]; + + context.memo('button.specialchars', function() { + return ui.button({ + contents: '<i class="fa fa-font fa-flip-vertical"></i>', + tooltip: lang.specialChar.specialChar, + click: function() { + self.show(); + }, + }).render(); + }); + + /** + * Make Special Characters Table + * + * @member plugin.specialChar + * @private + * @return {jQuery} + */ + this.makeSpecialCharSetTable = function() { + var $table = $('<table></table>'); + $.each(specialCharDataSet, function(idx, text) { + var $td = $('<td></td>').addClass('note-specialchar-node'); + var $tr = (idx % COLUMN_LENGTH === 0) ? $('<tr></tr>') : $table.find('tr').last(); + + var $button = ui.button({ + callback: function($node) { + $node.html(text); + $node.attr('title', text); + $node.attr('data-value', encodeURIComponent(text)); + $node.css({ + width: COLUMN_WIDTH, + 'margin-right': '2px', + 'margin-bottom': '2px', + }); + }, + }).render(); + + $td.append($button); + + $tr.append($td); + if (idx % COLUMN_LENGTH === 0) { + $table.append($tr); + } + }); + + totalRow = $table.find('tr').length; + totalColumn = COLUMN_LENGTH; + + return $table; + }; + + this.initialize = function() { + var $container = options.dialogsInBody ? $(document.body) : $editor; + + var body = '<div class="form-group row-fluid">' + this.makeSpecialCharSetTable()[0].outerHTML + '</div>'; + + this.$dialog = ui.dialog({ + title: lang.specialChar.select, + body: body, + }).render().appendTo($container); + }; + + this.show = function() { + var text = context.invoke('editor.getSelectedText'); + context.invoke('editor.saveRange'); + this.showSpecialCharDialog(text).then(function(selectChar) { + context.invoke('editor.restoreRange'); + + // build node + var $node = $('<span></span>').html(selectChar)[0]; + + if ($node) { + // insert video node + context.invoke('editor.insertNode', $node); + } + }).fail(function() { + context.invoke('editor.restoreRange'); + }); + }; + + /** + * show image dialog + * + * @param {jQuery} $dialog + * @return {Promise} + */ + this.showSpecialCharDialog = function(text) { + return $.Deferred(function(deferred) { + var $specialCharDialog = self.$dialog; + var $specialCharNode = $specialCharDialog.find('.note-specialchar-node'); + var $selectedNode = null; + var ARROW_KEYS = [KEY.UP, KEY.DOWN, KEY.LEFT, KEY.RIGHT]; + var ENTER_KEY = KEY.ENTER; + + function addActiveClass($target) { + if (!$target) { + return; + } + $target.find('button').addClass('active'); + $selectedNode = $target; + } + + function removeActiveClass($target) { + $target.find('button').removeClass('active'); + $selectedNode = null; + } + + // find next node + function findNextNode(row, column) { + var findNode = null; + $.each($specialCharNode, function(idx, $node) { + var findRow = Math.ceil((idx + 1) / COLUMN_LENGTH); + var findColumn = ((idx + 1) % COLUMN_LENGTH === 0) ? COLUMN_LENGTH : (idx + 1) % COLUMN_LENGTH; + if (findRow === row && findColumn === column) { + findNode = $node; + return false; + } + }); + return $(findNode); + } + + function arrowKeyHandler(keyCode) { + // left, right, up, down key + var $nextNode; + var lastRowColumnLength = $specialCharNode.length % totalColumn; + + if (KEY.LEFT === keyCode) { + if (currentColumn > 1) { + currentColumn = currentColumn - 1; + } else if (currentRow === 1 && currentColumn === 1) { + currentColumn = lastRowColumnLength; + currentRow = totalRow; + } else { + currentColumn = totalColumn; + currentRow = currentRow - 1; + } + } else if (KEY.RIGHT === keyCode) { + if (currentRow === totalRow && lastRowColumnLength === currentColumn) { + currentColumn = 1; + currentRow = 1; + } else if (currentColumn < totalColumn) { + currentColumn = currentColumn + 1; + } else { + currentColumn = 1; + currentRow = currentRow + 1; + } + } else if (KEY.UP === keyCode) { + if (currentRow === 1 && lastRowColumnLength < currentColumn) { + currentRow = totalRow - 1; + } else { + currentRow = currentRow - 1; + } + } else if (KEY.DOWN === keyCode) { + currentRow = currentRow + 1; + } + + if (currentRow === totalRow && currentColumn > lastRowColumnLength) { + currentRow = 1; + } else if (currentRow > totalRow) { + currentRow = 1; + } else if (currentRow < 1) { + currentRow = totalRow; + } + + $nextNode = findNextNode(currentRow, currentColumn); + + if ($nextNode) { + removeActiveClass($selectedNode); + addActiveClass($nextNode); + } + } + + function enterKeyHandler() { + if (!$selectedNode) { + return; + } + + deferred.resolve(decodeURIComponent($selectedNode.find('button').attr('data-value'))); + $specialCharDialog.modal('hide'); + } + + function keyDownEventHandler(event) { + event.preventDefault(); + var keyCode = event.keyCode; + if (keyCode === undefined || keyCode === null) { + return; + } + // check arrowKeys match + if (ARROW_KEYS.indexOf(keyCode) > -1) { + if ($selectedNode === null) { + addActiveClass($specialCharNode.eq(0)); + currentColumn = 1; + currentRow = 1; + return; + } + arrowKeyHandler(keyCode); + } else if (keyCode === ENTER_KEY) { + enterKeyHandler(); + } + return false; + } + + // remove class + removeActiveClass($specialCharNode); + + // find selected node + if (text) { + for (var i = 0; i < $specialCharNode.length; i++) { + var $checkNode = $($specialCharNode[i]); + if ($checkNode.text() === text) { + addActiveClass($checkNode); + currentRow = Math.ceil((i + 1) / COLUMN_LENGTH); + currentColumn = (i + 1) % COLUMN_LENGTH; + } + } + } + + ui.onDialogShown(self.$dialog, function() { + $(document).on('keydown', keyDownEventHandler); + + self.$dialog.find('button').tooltip(); + + $specialCharNode.on('click', function(event) { + event.preventDefault(); + deferred.resolve(decodeURIComponent($(event.currentTarget).find('button').attr('data-value'))); + ui.hideDialog(self.$dialog); + }); + }); + + ui.onDialogHidden(self.$dialog, function() { + $specialCharNode.off('click'); + + self.$dialog.find('button').tooltip(); + + $(document).off('keydown', keyDownEventHandler); + + if (deferred.state() === 'pending') { + deferred.reject(); + } + }); + + ui.showDialog(self.$dialog); + }); + }; + }, + }); +})); |