activeadmin_quill_editor 0.2.9 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f42a9042c7220f4a77082d6f3dd2c9a33219f7d6d9d90a99394e166faeb8cc1e
4
- data.tar.gz: f46e1e841a1cbe9b38d158a5b80e2776c21b77f5f675a552d9f9d9d76991a92a
3
+ metadata.gz: bf8cb33be21c875ee835f3e8b1fa4cb831ef0d46658122bb29aa0c6aba1d1a54
4
+ data.tar.gz: 4ca4db51f40f7c091e6373214131a9352cc931563e77b161a8198a3ed0462361
5
5
  SHA512:
6
- metadata.gz: a22cefc16231c2d08a3336f10579783de82daacdb7075120506ec557ee0548bcc74f1e750ac75208893a56bee119819a7671db0624b5e03403f8780bf17611ab
7
- data.tar.gz: 8cc61172369187fdecaeddca938fddae91aacac933aafe02303122329aec91dc88d844544ba4ebe1f1ccbc802170e37b20a5c6b3123e210d793a8302fdc4505e
6
+ metadata.gz: b24f32b38c090be210d3d348db347c32daeb46fcdcb205b072d9b57095fbfd657f262f54754f001d46307d91ca9f1f784cd36c8b79ccc3ac89490f9b0d243d42
7
+ data.tar.gz: 8ff0c6ddbc5b35da1642166c4d27d72cd2475ba2fba8592855088d2633e78dabe8972cf52b2272962c16104bb1f8114d297adf83bb13fb6b89198e9b4e68332c
data/README.md CHANGED
@@ -47,8 +47,31 @@ Why 2 separated scripts/styles? In this way you can include a different version
47
47
  f.input :description, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: [['bold', 'italic', 'underline'], ['link']] }, placeholder: 'Type something...', theme: 'snow' } } }
48
48
  ```
49
49
 
50
- ## Notes
51
- - Upload features (images/documents/files): not tested yet.
50
+ ### ImageUploader plugin
51
+ This plugin allows to upload images to the server (instead of storing them in *base64* by default), reference [here](https://github.com/NoelOConnell/quill-image-uploader).
52
+
53
+ ```ruby
54
+ # Upload method (to be included in the admin entity configuration)
55
+ member_action :upload, method: [:post] do
56
+ result = { success: resource.images.attach(params[:file_upload]) }
57
+ result[:url] = url_for(resource.images.last) if result[:success]
58
+ render json: result
59
+ end
60
+ ```
61
+
62
+ ```ruby
63
+ # Form field
64
+ unless object.new_record?
65
+ plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
66
+ f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
67
+ end
68
+ ```
69
+
70
+ For the relevant files of the upload example see [here](examples/upload_plugin_using_activestorage/).
71
+ Consider that this is just a basic example: images are uploaded as soon as they are attached to the
72
+ editor (regardless of the form submit), it shows the editor only for an existing record (because of
73
+ the *upload_admin_post_path*) and it doesn't provide a way to remove images (just deleting them from
74
+ the editor will not destroy them, you'll need to implement a purge logic for that).
52
75
 
53
76
  ## Do you like it? Star it!
54
77
  If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
@@ -0,0 +1 @@
1
+ !function(e){var t={};function n(i){if(t[i])return t[i].exports;var r=t[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(i,r,function(t){return e[t]}.bind(null,r));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t){e.exports=Quill},function(e,t,n){"use strict";n.r(t);var i=n(0),r=n.n(i),o=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),a=function e(t,n,i){null===t&&(t=Function.prototype);var r=Object.getOwnPropertyDescriptor(t,n);if(void 0===r){var o=Object.getPrototypeOf(t);return null===o?void 0:e(o,n,i)}if("value"in r)return r.value;var a=r.get;return void 0!==a?a.call(i):void 0};function l(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}var u=function(e){function t(){return l(this,t),s(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),o(t,[{key:"deleteAt",value:function(e,n){a(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"deleteAt",this).call(this,e,n),this.cache={}}}],[{key:"create",value:function(e){var n=a(t.__proto__||Object.getPrototypeOf(t),"create",this).call(this,e);if(!0===e)return n;var i=document.createElement("img");return i.setAttribute("src",e),n.appendChild(i),n}},{key:"value",value:function(e){var t=e.dataset;return{src:t.src,custom:t.custom}}}]),t}(r.a.import("blots/block"));u.blotName="imageBlot",u.className="image-uploading",u.tagName="span",r.a.register({"formats/imageBlot":u});var c=u,f=(n(3),function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}());var d=function(){function e(t,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.quill=t,this.options=n,this.range=null,"function"!=typeof this.options.upload&&console.warn("[Missing config] upload function that returns a promise is required"),this.quill.getModule("toolbar").addHandler("image",this.selectLocalImage.bind(this)),this.handleDrop=this.handleDrop.bind(this),this.handlePaste=this.handlePaste.bind(this),this.quill.root.addEventListener("drop",this.handleDrop,!1),this.quill.root.addEventListener("paste",this.handlePaste,!1)}return f(e,[{key:"selectLocalImage",value:function(){var e=this;this.range=this.quill.getSelection(),this.fileHolder=document.createElement("input"),this.fileHolder.setAttribute("type","file"),this.fileHolder.setAttribute("accept","image/*"),this.fileHolder.setAttribute("style","visibility:hidden"),this.fileHolder.onchange=this.fileChanged.bind(this),document.body.appendChild(this.fileHolder),this.fileHolder.click(),window.requestAnimationFrame((function(){document.body.removeChild(e.fileHolder)}))}},{key:"handleDrop",value:function(e){var t=this;if(e.stopPropagation(),e.preventDefault(),e.dataTransfer&&e.dataTransfer.files&&e.dataTransfer.files.length){if(document.caretRangeFromPoint){var n=document.getSelection(),i=document.caretRangeFromPoint(e.clientX,e.clientY);n&&i&&n.setBaseAndExtent(i.startContainer,i.startOffset,i.startContainer,i.startOffset)}else{var r=document.getSelection(),o=document.caretPositionFromPoint(e.clientX,e.clientY);r&&o&&r.setBaseAndExtent(o.offsetNode,o.offset,o.offsetNode,o.offset)}this.range=this.quill.getSelection();var a=e.dataTransfer.files[0];setTimeout((function(){t.range=t.quill.getSelection(),t.readAndUploadFile(a)}),0)}}},{key:"handlePaste",value:function(e){var t=this,n=e.clipboardData||window.clipboardData;if(n&&(n.items||n.files))for(var i=n.items||n.files,r=/^image\/(jpe?g|gif|png|svg|webp)$/i,o=0;o<i.length;o++)r.test(i[o].type)&&function(){var n=i[o].getAsFile?i[o].getAsFile():i[o];n&&(t.range=t.quill.getSelection(),e.preventDefault(),setTimeout((function(){t.range=t.quill.getSelection(),t.readAndUploadFile(n)}),0))}()}},{key:"readAndUploadFile",value:function(e){var t=this,n=!1,i=new FileReader;i.addEventListener("load",(function(){if(!n){var e=i.result;t.insertBase64Image(e)}}),!1),e&&i.readAsDataURL(e),this.options.upload(e).then((function(e){t.insertToEditor(e)}),(function(e){n=!0,t.removeBase64Image(),console.warn(e)}))}},{key:"fileChanged",value:function(){var e=this.fileHolder.files[0];this.readAndUploadFile(e)}},{key:"insertBase64Image",value:function(e){var t=this.range;this.quill.insertEmbed(t.index,c.blotName,""+e,"user")}},{key:"insertToEditor",value:function(e){var t=this.range;this.quill.deleteText(t.index,3,"user"),this.quill.insertEmbed(t.index,"image",""+e,"user"),t.index++,this.quill.setSelection(t,"user")}},{key:"removeBase64Image",value:function(){var e=this.range;this.quill.deleteText(e.index,3,"user")}}]),e}();window.ImageUploader=d;t.default=d},,function(e,t){}]);
@@ -1,25 +1,40 @@
1
+ // --- functions ---------------------------------------------------------------
1
2
  function initQuillEditors() {
3
+ var default_theme = 'snow';
4
+ var default_toolbar = [
5
+ ['bold', 'italic', 'underline'],
6
+ ['link', 'blockquote', 'code-block'],
7
+ [{ 'script': 'sub'}, { 'script': 'super' }],
8
+ [{ 'align': [] }, { list: 'ordered' }, { list: 'bullet' }],
9
+ [{ 'color': [] }, { 'background': [] }],
10
+ ['image'],
11
+ ['clean'],
12
+ ];
2
13
  var editors = document.querySelectorAll('.quill-editor');
3
- var default_options = {
4
- modules: {
5
- toolbar: [
6
- ['bold', 'italic', 'underline'],
7
- ['link', 'blockquote', 'code-block'],
8
- [{ 'script': 'sub'}, { 'script': 'super' }],
9
- [{ 'align': [] }, { list: 'ordered' }, { list: 'bullet' }],
10
- [{ 'color': [] }, { 'background': [] }],
11
- ['clean'],
12
- ]
13
- },
14
- placeholder: '',
15
- theme: 'snow'
16
- };
14
+ var registered_plugins = {};
17
15
 
18
16
  for(var i = 0; i < editors.length; i++) {
19
17
  var content = editors[i].querySelector('.quill-editor-content');
20
18
  var isActive = editors[i].classList.contains('quill-editor--active');
21
19
  if(content && !isActive) {
22
- var options = editors[i].getAttribute('data-options') ? JSON.parse(editors[i].getAttribute('data-options')) : default_options;
20
+ // Setup editor options
21
+ var options = editors[i].getAttribute('data-options') ? JSON.parse(editors[i].getAttribute('data-options')) : {};
22
+ if(!options.theme) options.theme = default_theme;
23
+ if(!options.modules) options.modules = {};
24
+ if(!options.modules.toolbar) options.modules.toolbar = default_toolbar;
25
+
26
+ // Setup plugin options
27
+ var plugin_options = editors[i].getAttribute('data-plugins') ? JSON.parse(editors[i].getAttribute('data-plugins')) : {};
28
+ if(plugin_options.image_uploader && plugin_options.image_uploader.server_url) {
29
+ if(!registered_plugins.image_uploader) {
30
+ Quill.register('modules/imageUploader', ImageUploader);
31
+ registered_plugins.image_uploader = true;
32
+ }
33
+ var opts = plugin_options.image_uploader;
34
+ options.modules.imageUploader = setupImageUploader(opts.server_url, opts.field_name);
35
+ }
36
+
37
+ // Init editor
23
38
  editors[i]['_quill-editor'] = new Quill(content, options);
24
39
  editors[i].classList += ' quill-editor--active';
25
40
  }
@@ -40,6 +55,33 @@ function initQuillEditors() {
40
55
  }
41
56
  }
42
57
 
58
+ function setupImageUploader(server_url, field_name) {
59
+ return {
60
+ upload: file => {
61
+ return new Promise((resolve, reject) => {
62
+ const formData = new FormData();
63
+ formData.append(field_name || 'file_upload', file);
64
+
65
+ fetch(server_url, {
66
+ body: formData,
67
+ headers: {
68
+ 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
69
+ },
70
+ method: 'POST'
71
+ }).then(response => response.json())
72
+ .then(result => {
73
+ resolve(result.url);
74
+ })
75
+ .catch(error => {
76
+ reject('Upload failed');
77
+ console.error('Error: ', error);
78
+ });
79
+ });
80
+ }
81
+ }
82
+ }
83
+
84
+ // --- events ------------------------------------------------------------------
43
85
  $(document).ready( function() {
44
86
  initQuillEditors();
45
87
  });
@@ -0,0 +1,33 @@
1
+ .image-uploading {
2
+ position: relative;
3
+ display: inline-block;
4
+ }
5
+
6
+ .image-uploading img {
7
+ max-width: 98% !important;
8
+ filter: blur(5px);
9
+ opacity: 0.3;
10
+ }
11
+
12
+ .image-uploading::before {
13
+ content: "";
14
+ box-sizing: border-box;
15
+ position: absolute;
16
+ top: 50%;
17
+ left: 50%;
18
+ width: 30px;
19
+ height: 30px;
20
+ margin-top: -15px;
21
+ margin-left: -15px;
22
+ border-radius: 50%;
23
+ border: 3px solid #ccc;
24
+ border-top-color: #1e986c;
25
+ z-index: 1;
26
+ animation: spinner 0.6s linear infinite;
27
+ }
28
+
29
+ @keyframes spinner {
30
+ to {
31
+ transform: rotate(360deg);
32
+ }
33
+ }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveAdmin
4
4
  module QuillEditor
5
- VERSION = '0.2.9'
5
+ VERSION = '0.2.10'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin_quill_editor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-04 00:00:00.000000000 Z
11
+ date: 2020-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeadmin
@@ -159,11 +159,13 @@ files:
159
159
  - LICENSE.txt
160
160
  - README.md
161
161
  - Rakefile
162
+ - app/assets/javascripts/activeadmin/quill.imageUploader.min.js
162
163
  - app/assets/javascripts/activeadmin/quill_editor/quill.core.js
163
164
  - app/assets/javascripts/activeadmin/quill_editor/quill.js
164
165
  - app/assets/javascripts/activeadmin/quill_editor/quill.min.js
165
166
  - app/assets/javascripts/activeadmin/quill_editor_input.js
166
167
  - app/assets/stylesheets/activeadmin/_quill_editor_input.scss
168
+ - app/assets/stylesheets/activeadmin/quill.imageUploader.min.css
167
169
  - app/assets/stylesheets/activeadmin/quill_editor/quill.bubble.css
168
170
  - app/assets/stylesheets/activeadmin/quill_editor/quill.core.css
169
171
  - app/assets/stylesheets/activeadmin/quill_editor/quill.snow.css