Permalink
Browse files

added basic data plugin

* added plugins to the Gruntfile, so these also pass through jshint,
jscs, uglify, recess and are copied to the dist folder
* plugin/specialchars - modified so jscs passed
* plugin/databasic - very basic plugin that demonstrates the inteded
use of DATA nodes
* src/ - inserted small changes to handle DATA nodes in dom/range; make
dom available to plugins by adding to $.summernote
  • Loading branch information...
1 parent e757c02 commit 8069765e92815ba009eaf8cf3596b23e3674661a Guido Pinkas committed Mar 17, 2016
View
@@ -107,7 +107,7 @@ module.exports = function (grunt) {
},
jscs: {
- src: ['*.js', 'src/**/*.js', 'test/**/*.js'],
+ src: ['*.js', 'src/**/*.js', 'test/**/*.js', 'plugin/**/*.js'],
gruntfile: 'Gruntfile.js',
build: 'build'
},
@@ -126,6 +126,13 @@ module.exports = function (grunt) {
src: '**/*.js',
dest: 'dist/lang',
ext: '.min.js'
+ },
+ {
+ expand: true,
+ cwd: 'dist/plugin',
+ src: '**/*.js',
+ dest: 'dist/plugin',
+ ext: '.min.js'
}
]
}
@@ -135,9 +142,18 @@ module.exports = function (grunt) {
recess: {
dist: {
options: { compile: true, compress: true },
- files: {
- 'dist/summernote.css': ['src/less/summernote.less']
- }
+ files: [
+ {
+ 'dist/summernote.css': ['src/less/summernote.less']
+ },
+ {
+ expand: true,
+ cwd: 'dist/plugin',
+ src: '**/*.css',
+ dest: 'dist/plugin',
+ ext: '.min.css'
+ }
+ ]
}
},
@@ -160,7 +176,7 @@ module.exports = function (grunt) {
'dist/font/*'
]
}, {
- src: ['plugin/**/*.js', 'lang/**/*.js'],
+ src: ['plugin/**/*.js', 'plugin/**/*.css', 'lang/**/*.js'],
dest: 'dist/'
}]
}
@@ -245,6 +261,7 @@ module.exports = function (grunt) {
dist: {
files: [
{ src: 'lang/*', dest: 'dist/' },
+ { src: 'plugin/**/*', dest: 'dist/' },
{ expand: true, cwd: 'src/icons/dist/font/', src: ['**', '!*.html'], dest: 'dist/font/' },
{ src: 'src/icons/dist/summernote.css', dest: 'src/icons/dist/summernote.less' }
]
@@ -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;
+}
@@ -0,0 +1,303 @@
+(function (factory) {
+ /* global define */
+ 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"/>';
+
+ // 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'
+ }
+ }
+ }
+
+ });
+
+}));
Oops, something went wrong.

0 comments on commit 8069765

Please sign in to comment.