summernote-image-attributes.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /* https://github.com/DiemenDesign/summernote-image-attributes */
  2. (function (factory) {
  3. if (typeof define === 'function' && define.amd) {
  4. define(['jquery'], factory);
  5. } else if (typeof module === 'object' && module.exports) {
  6. module.exports = factory(require('jquery'));
  7. } else {
  8. factory(window.jQuery);
  9. }
  10. }(function ($) {
  11. var readFileAsDataURL = function (file) {
  12. return $.Deferred( function (deferred) {
  13. $.extend(new FileReader(),{
  14. onload: function (e) {
  15. var sDataURL = e.target.result;
  16. deferred.resolve(sDataURL);
  17. },
  18. onerror: function () {
  19. deferred.reject(this);
  20. }
  21. }).readAsDataURL(file);
  22. }).promise();
  23. };
  24. $.extend(true,$.summernote.lang, {
  25. 'en-US': { /* US English(Default Language) */
  26. imageAttributes: {
  27. dialogTitle: 'Image Attributes',
  28. tooltip: 'Image Attributes',
  29. tabImage: 'Image',
  30. src: 'Source',
  31. browse: 'Browse',
  32. title: 'Title',
  33. alt: 'Alt Text',
  34. dimensions: 'Dimensions',
  35. tabAttributes: 'Attributes',
  36. class: 'Class',
  37. style: 'Style',
  38. role: 'Role',
  39. tabLink: 'Link',
  40. linkHref: 'URL',
  41. linkTarget: 'Target',
  42. linkTargetInfo: 'Options: _self, _blank, _top, _parent',
  43. linkClass: 'Class',
  44. linkStyle: 'Style',
  45. linkRel: 'Rel',
  46. linkRelInfo: 'Options: alternate, author, bookmark, help, license, next, nofollow, noreferrer, prefetch, prev, search, tag',
  47. linkRole: 'Role',
  48. tabUpload: 'Upload',
  49. upload: 'Upload',
  50. tabBrowse: 'Browse',
  51. editBtn: 'OK'
  52. }
  53. }
  54. });
  55. $.extend($.summernote.options, {
  56. imageAttributes: {
  57. icon: '<i class="note-icon-pencil"/>',
  58. removeEmpty: true,
  59. disableUpload: false,
  60. imageFolder: ''
  61. }
  62. });
  63. $.extend($.summernote.plugins, {
  64. 'imageAttributes': function (context) {
  65. var self = this,
  66. ui = $.summernote.ui,
  67. $note = context.layoutInfo.note,
  68. $editor = context.layoutInfo.editor,
  69. $editable = context.layoutInfo.editable,
  70. options = context.options,
  71. lang = options.langInfo,
  72. imageAttributesLimitation = '';
  73. if (options.maximumImageFileSize) {
  74. var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));
  75. var readableSize = (options.maximumImageFileSize/Math.pow(1024,unit)).toFixed(2) * 1 + ' ' + ' KMGTP'[unit] + 'B';
  76. imageAttributesLimitation = '<small class="help-block note-help-block">' + lang.image.maximumFileSize + ' : ' + readableSize+'</small>';
  77. }
  78. if(! ('_counter' in $.summernote.options.imageAttributes)) {
  79. $.summernote.options.imageAttributes._counter = 0;
  80. }
  81. context.memo('button.imageAttributes', function() {
  82. var button = ui.button({
  83. contents: options.imageAttributes.icon,
  84. container: "body",
  85. tooltip: lang.imageAttributes.tooltip,
  86. click: function () {
  87. context.invoke('imageAttributes.show');
  88. }
  89. });
  90. return button.render();
  91. });
  92. this.initialize = function () {
  93. var $container = options.dialogsInBody ? $(document.body) : $editor;
  94. $.summernote.options.imageAttributes._counter++;
  95. var i = $.summernote.options.imageAttributes._counter;
  96. // console.log('indice for imageAttribute : ', i);
  97. var body = '<ul class="nav note-nav nav-tabs note-nav-tabs">' +
  98. '<li class="nav-item note-nav-item active"><a class="nav-link note-nav-link active" href="#note-imageAttributes-' + i + '" data-toggle="tab">' + lang.imageAttributes.tabImage + '</a></li>' +
  99. '<li class="nav-item note-nav-item"><a class="nav-link note-nav-link" href="#note-imageAttributes-attributes-' + i + '" data-toggle="tab">' + lang.imageAttributes.tabAttributes + '</a></li>' +
  100. '<li class="nav-item note-nav-item"><a class="nav-link note-nav-link" href="#note-imageAttributes-link-' + i + '" data-toggle="tab">' + lang.imageAttributes.tabLink + '</a></li>';
  101. if (options.imageAttributes.disableUpload == false) {
  102. body += '<li class="nav-item note-nav-item"><a class="nav-link note-nav-link" href="#note-imageAttributes-upload-' + i + '" data-toggle="tab">' + lang.imageAttributes.tabUpload + '</a></li>';
  103. }
  104. body += '</ul>' +
  105. '<div class="tab-content">' +
  106. // Tab 2
  107. '<div class="tab-pane note-tab-pane" id="note-imageAttributes-attributes-' + i + '">' +
  108. '<div class="note-form-group form-group note-group-imageAttributes-class">' +
  109. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.class + '</label>' +
  110. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  111. '<input class="note-imageAttributes-class form-control note-form-control note-input" type="text">' +
  112. '</div>' +
  113. '</div>' +
  114. '<div class="note-form-group form-group note-group-imageAttributes-style">' +
  115. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.style + '</label>' +
  116. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  117. '<input class="note-imageAttributes-style form-control note-form-control note-input" type="text">' +
  118. '</div>' +
  119. '</div>' +
  120. '<div class="note-form-group form-group note-group-imageAttributes-role">' +
  121. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.role + '</label>' +
  122. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  123. '<input class="note-imageAttributes-role form-control note-form-control note-input" type="text">' +
  124. '</div>' +
  125. '</div>' +
  126. '</div>' +
  127. // Tab 3
  128. '<div class="tab-pane note-tab-pane" id="note-imageAttributes-link-' + i + '">' +
  129. '<div class="note-form-group form-group note-group-imageAttributes-link-href">' +
  130. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkHref + '</label>' +
  131. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  132. '<input class="note-imageAttributes-link-href form-control note-form-control note-input" type="text">' +
  133. '</div>' +
  134. '</div>' +
  135. '<div class="note-form-group form-group note-group-imageAttributes-link-target">' +
  136. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkTarget + '</label>' +
  137. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  138. '<input class="note-imageAttributes-link-target form-control note-form-control note-input" type="text">' +
  139. '</div>' +
  140. '<small class="help-block note-help-block text-right">' + lang.imageAttributes.linkTargetInfo + '</small>' +
  141. '</div>' +
  142. '<div class="note-form-group form-group note-group-imageAttributes-link-class">' +
  143. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkClass + '</label>' +
  144. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  145. '<input class="note-imageAttributes-link-class form-control note-form-control note-input" type="text">' +
  146. '</div>' +
  147. '</div>' +
  148. '<div class="note-form-group form-group note-group-imageAttributes-link-style">' +
  149. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkStyle + '</label>' +
  150. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  151. '<input class="note-imageAttributes-link-style form-control note-form-control note-input" type="text">' +
  152. '</div>' +
  153. '</div>' +
  154. '<div class="note-form-group form-group note-group-imageAttributes-link-rel">' +
  155. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkRel + '</label>' +
  156. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  157. '<input class="note-imageAttributes-link-rel form-control note-form-control note-input" type="text">' +
  158. '</div>' +
  159. '<small class="help-block note-help-block text-right">' + lang.imageAttributes.linkRelInfo + '</small>' +
  160. '</div>' +
  161. '<div class="note-form-group form-group note-group-imageAttributes-link-role">' +
  162. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.linkRole + '</label>' +
  163. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  164. '<input class="note-imageAttributes-link-role form-control note-form-control note-input" type="text">' +
  165. '</div>' +
  166. '</div>' +
  167. '</div>';
  168. if (options.imageAttributes.disableUpload == false) {
  169. // Tab 4
  170. body += '<div class="tab-pane note-tab-pane" id="note-imageAttributes-upload-' + i + '">' +
  171. '<label class="control-label note-form-label col-xs-3">' + lang.imageAttributes.upload + '</label>' +
  172. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  173. '<input class="note-imageAttributes-input form-control note-form-control note-input" type="file" name="files" accept="image/*" multiple="multiple">' +
  174. imageAttributesLimitation +
  175. '</div>' +
  176. '</div>';
  177. }
  178. // Tab 1
  179. body += '<div class="tab-pane note-tab-pane fade in active" id="note-imageAttributes-' + i + '">' +
  180. '<div class="note-form-group form-group note-group-imageAttributes-url">' +
  181. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.src + '</label>' +
  182. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  183. '<input class="note-imageAttributes-src form-control note-form-control note-input" type="text">' +
  184. '</div>' +
  185. '</div>' +
  186. '<div class="note-form-group form-group note-group-imageAttributes-title">' +
  187. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.title + '</label>' +
  188. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  189. '<input class="note-imageAttributes-title form-control note-form-control note-input" type="text">' +
  190. '</div>' +
  191. '</div>' +
  192. '<div class="note-form-group form-group note-group-imageAttributes-alt">' +
  193. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.alt + '</label>' +
  194. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  195. '<input class="note-imageAttributes-alt form-control note-form-control note-input" type="text">' +
  196. '</div>' +
  197. '</div>' +
  198. '<div class="note-form-group form-group note-group-imageAttributes-dimensions">' +
  199. '<label class="control-label note-form-label col-sm-3">' + lang.imageAttributes.dimensions + '</label>' +
  200. '<div class="input-group note-input-group col-xs-12 col-sm-9">' +
  201. '<input class="note-imageAttributes-width form-control note-form-control note-input" type="text">' +
  202. '<span class="input-group-addon note-input-group-addon">x</span>' +
  203. '<input class="note-imageAttributes-height form-control note-form-control note-input" type="text">' +
  204. '</div>' +
  205. '</div>' +
  206. '</div>' +
  207. '</div>';
  208. this.$dialog=ui.dialog({
  209. title: lang.imageAttributes.dialogTitle,
  210. body: body,
  211. footer: '<button href="#" class="btn btn-primary note-btn note-btn-primary note-imageAttributes-btn">' + lang.imageAttributes.editBtn + '</button>'
  212. }).render().appendTo($container);
  213. };
  214. this.destroy = function () {
  215. ui.hideDialog(this.$dialog);
  216. this.$dialog.remove();
  217. };
  218. this.bindEnterKey = function ($input,$btn) {
  219. $input.on('keypress', function (e) {
  220. if (e.keyCode === 13) $btn.trigger('click');
  221. });
  222. };
  223. this.bindLabels = function () {
  224. self.$dialog.find('.form-control:first').focus().select();
  225. self.$dialog.find('label').on('click', function () {
  226. $(this).parent().find('.form-control:first').focus();
  227. });
  228. };
  229. this.show = function () {
  230. var $img = $($editable.data('target'));
  231. var imgInfo = {
  232. imgDom: $img,
  233. title: $img.attr('title'),
  234. src: $img.attr('src'),
  235. alt: $img.attr('alt'),
  236. width: $img.attr('width'),
  237. height: $img.attr('height'),
  238. role: $img.attr('role'),
  239. class: $img.attr('class'),
  240. style: $img.attr('style'),
  241. imgLink: $($img).parent().is("a") ? $($img).parent() : null
  242. };
  243. this.showImageAttributesDialog(imgInfo).then( function (imgInfo) {
  244. ui.hideDialog(self.$dialog);
  245. var $img = imgInfo.imgDom;
  246. if (options.imageAttributes.removeEmpty) {
  247. if (imgInfo.alt) $img.attr('alt', imgInfo.alt); else $img.removeAttr('alt');
  248. if (imgInfo.width) $img.attr('width', imgInfo.width); else $img.removeAttr('width');
  249. if (imgInfo.height) $img.attr('height',imgInfo.height); else $img.removeAttr('height');
  250. if (imgInfo.title) $img.attr('title', imgInfo.title); else $img.removeAttr('title');
  251. if (imgInfo.src) $img.attr('src', imgInfo.src); else $img.attr('src', '#');
  252. if (imgInfo.class) $img.attr('class', imgInfo.class); else $img.removeAttr('class');
  253. if (imgInfo.style) $img.attr('style', imgInfo.style); else $img.removeAttr('style');
  254. if (imgInfo.role) $img.attr('role', imgInfo.role); else $img.removeAttr('role');
  255. } else {
  256. if (imgInfo.src) $img.attr('src', imgInfo.src); else $img.attr('src', '#');
  257. $img.attr('alt', imgInfo.alt);
  258. $img.attr('width', imgInfo.width);
  259. $img.attr('height', imgInfo.height);
  260. $img.attr('title', imgInfo.title);
  261. $img.attr('class', imgInfo.class);
  262. $img.attr('style', imgInfo.style);
  263. $img.attr('role', imgInfo.role);
  264. }
  265. if($img.parent().is("a")) $img.unwrap();
  266. if (imgInfo.linkHref) {
  267. var linkBody = '<a';
  268. if (imgInfo.linkClass) linkBody += ' class="' + imgInfo.linkClass + '"';
  269. if (imgInfo.linkStyle) linkBody += ' style="' + imgInfo.linkStyle + '"';
  270. linkBody += ' href="' + imgInfo.linkHref + '" target="' + imgInfo.linkTarget + '"';
  271. if (imgInfo.linkRel) linkBody += ' rel="' + imgInfo.linkRel + '"';
  272. if (imgInfo.linkRole) linkBody += ' role="' + imgInfo.linkRole + '"';
  273. linkBody += '></a>';
  274. $img.wrap(linkBody);
  275. }
  276. $note.val(context.invoke('code'));
  277. $note.change();
  278. });
  279. };
  280. this.showImageAttributesDialog = function (imgInfo) {
  281. return $.Deferred( function (deferred) {
  282. var $imageTitle = self.$dialog.find('.note-imageAttributes-title'),
  283. $imageInput = self.$dialog.find('.note-imageAttributes-input'),
  284. $imageSrc = self.$dialog.find('.note-imageAttributes-src'),
  285. $imageAlt = self.$dialog.find('.note-imageAttributes-alt'),
  286. $imageWidth = self.$dialog.find('.note-imageAttributes-width'),
  287. $imageHeight = self.$dialog.find('.note-imageAttributes-height'),
  288. $imageClass = self.$dialog.find('.note-imageAttributes-class'),
  289. $imageStyle = self.$dialog.find('.note-imageAttributes-style'),
  290. $imageRole = self.$dialog.find('.note-imageAttributes-role'),
  291. $linkHref = self.$dialog.find('.note-imageAttributes-link-href'),
  292. $linkTarget = self.$dialog.find('.note-imageAttributes-link-target'),
  293. $linkClass = self.$dialog.find('.note-imageAttributes-link-class'),
  294. $linkStyle = self.$dialog.find('.note-imageAttributes-link-style'),
  295. $linkRel = self.$dialog.find('.note-imageAttributes-link-rel'),
  296. $linkRole = self.$dialog.find('.note-imageAttributes-link-role'),
  297. $editBtn = self.$dialog.find('.note-imageAttributes-btn');
  298. $linkHref.val();
  299. $linkClass.val();
  300. $linkStyle.val();
  301. $linkRole.val();
  302. $linkTarget.val();
  303. $linkRel.val();
  304. if (imgInfo.imgLink) {
  305. $linkHref.val(imgInfo.imgLink.attr('href'));
  306. $linkClass.val(imgInfo.imgLink.attr('class'));
  307. $linkStyle.val(imgInfo.imgLink.attr('style'));
  308. $linkRole.val(imgInfo.imgLink.attr('role'));
  309. $linkTarget.val(imgInfo.imgLink.attr('target'));
  310. $linkRel.val(imgInfo.imgLink.attr('rel'));
  311. }
  312. ui.onDialogShown(self.$dialog, function () {
  313. context.triggerEvent('dialog.shown');
  314. $imageInput.replaceWith(
  315. $imageInput.clone().on('change', function () {
  316. var callbacks = options.callbacks;
  317. if (callbacks.onImageUpload) {
  318. context.triggerEvent('image.upload',this.files[0]);
  319. } else {
  320. readFileAsDataURL(this.files[0]).then( function (dataURL) {
  321. $imageSrc.val(dataURL);
  322. }).fail( function () {
  323. context.triggerEvent('image.upload.error');
  324. });
  325. }
  326. }).val('')
  327. );
  328. $editBtn.click( function (e) {
  329. e.preventDefault();
  330. deferred.resolve({
  331. imgDom: imgInfo.imgDom,
  332. title: $imageTitle.val(),
  333. src: $imageSrc.val(),
  334. alt: $imageAlt.val(),
  335. width: $imageWidth.val(),
  336. height: $imageHeight.val(),
  337. class: $imageClass.val(),
  338. style: $imageStyle.val(),
  339. role: $imageRole.val(),
  340. linkHref: $linkHref.val(),
  341. linkTarget: $linkTarget.val(),
  342. linkClass: $linkClass.val(),
  343. linkStyle: $linkStyle.val(),
  344. linkRel: $linkRel.val(),
  345. linkRole: $linkRole.val()
  346. }).then(function (img) {
  347. context.triggerEvent('change', $editable.html());
  348. });
  349. });
  350. $imageTitle.val(imgInfo.title);
  351. $imageSrc.val(imgInfo.src);
  352. $imageAlt.val(imgInfo.alt);
  353. $imageWidth.val(imgInfo.width);
  354. $imageHeight.val(imgInfo.height);
  355. $imageClass.val(imgInfo.class);
  356. $imageStyle.val(imgInfo.style);
  357. $imageRole.val(imgInfo.role);
  358. self.bindEnterKey($editBtn);
  359. self.bindLabels();
  360. });
  361. ui.onDialogHidden(self.$dialog, function () {
  362. $editBtn.off('click');
  363. if (deferred.state() === 'pending') deferred.reject();
  364. });
  365. ui.showDialog(self.$dialog);
  366. });
  367. };
  368. }
  369. });
  370. }));