activeadmin_quill_editor 0.2.9 → 0.2.10

Sign up to get free protection for your applications and to get access to all the features.
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