You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

summernote-ext-databasic.js 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. (function (factory) {
  2. if (typeof define === 'function' && define.amd) {
  3. // AMD. Register as an anonymous module.
  4. define(['jquery'], factory);
  5. } else if (typeof module === 'object' && module.exports) {
  6. // Node/CommonJS
  7. module.exports = factory(require('jquery'));
  8. } else {
  9. // Browser globals
  10. factory(window.jQuery);
  11. }
  12. }(function ($) {
  13. // pull in some summernote core functions
  14. var ui = $.summernote.ui;
  15. var dom = $.summernote.dom;
  16. // define the popover plugin
  17. var DataBasicPlugin = function (context) {
  18. var self = this;
  19. var options = context.options;
  20. var lang = options.langInfo;
  21. self.icon = '<i class="fa fa-object-group"/>';
  22. // add context menu button for dialog
  23. context.memo('button.databasic', function () {
  24. return ui.button({
  25. contents: self.icon,
  26. tooltip: lang.databasic.insert,
  27. click: context.createInvokeHandler('databasic.showDialog'),
  28. }).render();
  29. });
  30. // add popover edit button
  31. context.memo('button.databasicDialog', function () {
  32. return ui.button({
  33. contents: self.icon,
  34. tooltip: lang.databasic.edit,
  35. click: context.createInvokeHandler('databasic.showDialog'),
  36. }).render();
  37. });
  38. // add popover size buttons
  39. context.memo('button.databasicSize100', function () {
  40. return ui.button({
  41. contents: '<span class="note-fontsize-10">100%</span>',
  42. tooltip: lang.image.resizeFull,
  43. click: context.createInvokeHandler('editor.resize', '1'),
  44. }).render();
  45. });
  46. context.memo('button.databasicSize50', function () {
  47. return ui.button({
  48. contents: '<span class="note-fontsize-10">50%</span>',
  49. tooltip: lang.image.resizeHalf,
  50. click: context.createInvokeHandler('editor.resize', '0.5'),
  51. }).render();
  52. });
  53. context.memo('button.databasicSize25', function () {
  54. return ui.button({
  55. contents: '<span class="note-fontsize-10">25%</span>',
  56. tooltip: lang.image.resizeQuarter,
  57. click: context.createInvokeHandler('editor.resize', '0.25'),
  58. }).render();
  59. });
  60. self.events = {
  61. 'summernote.init': function (we, e) {
  62. // update existing containers
  63. $('data.ext-databasic', e.editable).each(function () {
  64. self.setContent($(this));
  65. });
  66. // TODO: make this an undo snapshot...
  67. },
  68. 'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function () {
  69. self.update();
  70. },
  71. 'summernote.dialog.shown': function () {
  72. self.hidePopover();
  73. },
  74. };
  75. self.initialize = function () {
  76. // create dialog markup
  77. var $container = options.dialogsInBody ? $(document.body) : context.layoutInfo.editor;
  78. var body = '<div class="form-group row-fluid">' +
  79. '<label>' + lang.databasic.testLabel + '</label>' +
  80. '<input class="ext-databasic-test form-control" type="text" />' +
  81. '</div>';
  82. var footer = '<button href="#" class="btn btn-primary ext-databasic-save">' + lang.databasic.insert + '</button>';
  83. self.$dialog = ui.dialog({
  84. title: lang.databasic.name,
  85. fade: options.dialogsFade,
  86. body: body,
  87. footer: footer,
  88. }).render().appendTo($container);
  89. // create popover
  90. self.$popover = ui.popover({
  91. className: 'ext-databasic-popover',
  92. }).render().appendTo('body');
  93. var $content = self.$popover.find('.popover-content');
  94. context.invoke('buttons.build', $content, options.popover.databasic);
  95. };
  96. self.destroy = function () {
  97. self.$popover.remove();
  98. self.$popover = null;
  99. self.$dialog.remove();
  100. self.$dialog = null;
  101. };
  102. self.update = function () {
  103. // Prevent focusing on editable when invoke('code') is executed
  104. if (!context.invoke('editor.hasFocus')) {
  105. self.hidePopover();
  106. return;
  107. }
  108. var rng = context.invoke('editor.createRange');
  109. var visible = false;
  110. if (rng.isOnData()) {
  111. var $data = $(rng.sc).closest('data.ext-databasic');
  112. if ($data.length) {
  113. var pos = dom.posFromPlaceholder($data[0]);
  114. self.$popover.css({
  115. display: 'block',
  116. left: pos.left,
  117. top: pos.top,
  118. });
  119. // save editor target to let size buttons resize the container
  120. context.invoke('editor.saveTarget', $data[0]);
  121. visible = true;
  122. }
  123. }
  124. // hide if not visible
  125. if (!visible) {
  126. self.hidePopover();
  127. }
  128. };
  129. self.hidePopover = function () {
  130. self.$popover.hide();
  131. };
  132. // define plugin dialog
  133. self.getInfo = function () {
  134. var rng = context.invoke('editor.createRange');
  135. if (rng.isOnData()) {
  136. var $data = $(rng.sc).closest('data.ext-databasic');
  137. if ($data.length) {
  138. // Get the first node on range(for edit).
  139. return {
  140. node: $data,
  141. test: $data.attr('data-test'),
  142. };
  143. }
  144. }
  145. return {};
  146. };
  147. self.setContent = function ($node) {
  148. $node.html('<p contenteditable="false">' + self.icon + ' ' + lang.databasic.name + ': ' +
  149. $node.attr('data-test') + '</p>');
  150. };
  151. self.updateNode = function (info) {
  152. self.setContent(info.node
  153. .attr('data-test', info.test));
  154. };
  155. self.createNode = function (info) {
  156. var $node = $('<data class="ext-databasic"></data>');
  157. if ($node) {
  158. // save node to info structure
  159. info.node = $node;
  160. // insert node into editor dom
  161. context.invoke('editor.insertNode', $node[0]);
  162. }
  163. return $node;
  164. };
  165. self.showDialog = function () {
  166. var info = self.getInfo();
  167. var newNode = !info.node;
  168. context.invoke('editor.saveRange');
  169. self
  170. .openDialog(info)
  171. .then(function (dialogInfo) {
  172. // [workaround] hide dialog before restore range for IE range focus
  173. ui.hideDialog(self.$dialog);
  174. context.invoke('editor.restoreRange');
  175. // insert a new node
  176. if (newNode) {
  177. self.createNode(info);
  178. }
  179. // update info with dialog info
  180. $.extend(info, dialogInfo);
  181. self.updateNode(info);
  182. })
  183. .fail(function () {
  184. context.invoke('editor.restoreRange');
  185. });
  186. };
  187. self.openDialog = function (info) {
  188. return $.Deferred(function (deferred) {
  189. var $inpTest = self.$dialog.find('.ext-databasic-test');
  190. var $saveBtn = self.$dialog.find('.ext-databasic-save');
  191. var onKeyup = function (event) {
  192. if (event.keyCode === 13) {
  193. $saveBtn.trigger('click');
  194. }
  195. };
  196. ui.onDialogShown(self.$dialog, function () {
  197. context.triggerEvent('dialog.shown');
  198. $inpTest.val(info.test).on('input', function () {
  199. ui.toggleBtn($saveBtn, $inpTest.val());
  200. }).trigger('focus').on('keyup', onKeyup);
  201. $saveBtn
  202. .text(info.node ? lang.databasic.edit : lang.databasic.insert)
  203. .click(function (event) {
  204. event.preventDefault();
  205. deferred.resolve({test: $inpTest.val()});
  206. });
  207. // init save button
  208. ui.toggleBtn($saveBtn, $inpTest.val());
  209. });
  210. ui.onDialogHidden(self.$dialog, function () {
  211. $inpTest.off('input keyup');
  212. $saveBtn.off('click');
  213. if (deferred.state() === 'pending') {
  214. deferred.reject();
  215. }
  216. });
  217. ui.showDialog(self.$dialog);
  218. });
  219. };
  220. };
  221. // Extends summernote
  222. $.extend(true, $.summernote, {
  223. plugins: {
  224. databasic: DataBasicPlugin,
  225. },
  226. options: {
  227. popover: {
  228. databasic: [
  229. ['databasic', ['databasicDialog', 'databasicSize100', 'databasicSize50', 'databasicSize25']],
  230. ],
  231. },
  232. },
  233. // add localization texts
  234. lang: {
  235. 'en-US': {
  236. databasic: {
  237. name: 'Basic Data Container',
  238. insert: 'insert basic data container',
  239. edit: 'edit basic data container',
  240. testLabel: 'test input',
  241. },
  242. },
  243. },
  244. });
  245. }));