activeadmin_quill_editor 0.2.0 → 1.0.0

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: 8644198fa29615148c05e303e6e14e5618f45a35db6325e44a618acaff8dac09
4
- data.tar.gz: c7d489ebc49866a7ca1b77daa2901795f99c7f55c8469488bffbac0671f2743f
3
+ metadata.gz: e375a2fb59c984b11edb01fcd2fe96105f6d4ed7799265ab7807f0643128e364
4
+ data.tar.gz: 8d66f041b8f72232f9ac9f71f4d26062c77770249f03a1b3603d8f8426f99fdf
5
5
  SHA512:
6
- metadata.gz: 6c039f2c9009a15853294ecdd0ea87bbcf51c737c98b59fb379ecaf3bf06cc1189f6b142fa84f0c512e91d5473bad1c25edce8225b8590b145c6764f3bc42283
7
- data.tar.gz: fbf2b324fff5e01f7b52b09f42f8427e39a17f1e3088233cf1bb54d6adc5407f034504049c40f329e186a1b39c143fac3b1c181dcc09a9f95b66be6a1de5b8fb
6
+ metadata.gz: a1efd9801f1b6cd50fefdbdc8f9dda6107fad108b72707be9d893d67e473c85c3012be31f7c54e7b603d3e0da8bce394165c24433b195fa9edd90d861375e6ab
7
+ data.tar.gz: 333d51a8e177b7243ed71e6765d6c4031c5c076616dbd996fb604625656d799aabb21e32c3c890a483b14e0783414707cff23ddc80e4c275c655bcd123da5339
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017 Mattia Roccoberton
1
+ Copyright (c) 2017-2022 Mattia Roccoberton
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,33 +1,59 @@
1
- # ActiveAdmin Quill Editor [![Gem Version](https://badge.fury.io/rb/activeadmin_quill_editor.svg)](https://badge.fury.io/rb/activeadmin_quill_editor)
1
+ # ActiveAdmin Quill Editor
2
+ [![gem version](https://badge.fury.io/rb/activeadmin_quill_editor.svg)](https://badge.fury.io/rb/activeadmin_quill_editor)
3
+ [![gem downloads](https://badgen.net/rubygems/dt/activeadmin_quill_editor)](https://rubygems.org/gems/activeadmin_quill_editor)
4
+ [![linters](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/linters.yml)
5
+ [![specs Rails 6.1](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails61.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails61.yml)
6
+ [![specs Rails 7.0](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails70.yml/badge.svg)](https://github.com/blocknotes/activeadmin_quill_editor/actions/workflows/specs_rails70.yml)
2
7
 
3
- An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill)
8
+ An Active Admin plugin to use [Quill Rich Text Editor](https://github.com/quilljs/quill) in form fields.
4
9
 
5
- ![screenshot](screenshot.jpg)
10
+ ![screenshot](extra/screenshot.png)
11
+
12
+ Please :star: if you like it.
6
13
 
7
14
  ## Install
8
15
 
9
- - Update your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
10
- - Add at the end of your ActiveAdmin styles (_app/assets/stylesheets/active_admin.scss_):
11
- ```css
16
+ After installing Active Admin, add to your Gemfile: `gem 'activeadmin_quill_editor'` (and execute *bundle*)
17
+
18
+ If you installed Active Admin without Webpacker support (default for now):
19
+
20
+ - Add a SASS/SCSS gem to your Gemfile (ex. `gem 'sassc'`)
21
+ - Add at the end of your Active Admin styles (_app/assets/stylesheets/active_admin.scss_):
22
+ ```scss
23
+ @import 'activeadmin/quill_editor/quill.snow';
12
24
  @import 'activeadmin/quill_editor_input';
13
25
  ```
14
- - Add at the end of your ActiveAdmin javascripts (_app/assets/javascripts/active_admin.js_):
26
+ - Add at the end of your Active Admin javascripts (_app/assets/javascripts/active_admin.js_):
15
27
  ```js
16
28
  //= require activeadmin/quill_editor/quill
17
29
  //= require activeadmin/quill_editor_input
18
30
  ```
19
- - Use the input with `as: :quill_editor` in Active Admin model conf
20
31
 
21
- Why 2 separated scripts? In this way you can include a different version of *quill editor* if you like.
32
+ > **UPDATE FROM VERSION <= 2.0**: please add to your _app/assets/stylesheets/active_admin.scss_ the line `@import 'activeadmin/quill_editor/quill.snow';`
33
+
34
+ If you installed Active Admin with Webpacker support:
35
+
36
+ - Execute in your project root:
37
+ ```sh
38
+ yarn add blocknotes/activeadmin_quill_editor
39
+ ```
40
+ - Add to your *app/javascript/packs/active_admin.js*:
41
+ ```js
42
+ require('activeadmin_quill_editor')
43
+ ```
44
+
45
+ ## Usage
22
46
 
23
- ## Options
47
+ In your Active Admin models, form configuration, set the text inputs with `as: :quill_editor` where needed.
24
48
 
25
49
  **data-options**: permits to set *quill editor* options directly - see [options list](https://quilljs.com/docs/configuration/)
26
50
 
27
51
  ## Examples
28
52
 
53
+ ### Basic usage
54
+
29
55
  ```ruby
30
- # ActiveAdmin article form conf:
56
+ # Active Admin article form conf:
31
57
  form do |f|
32
58
  f.inputs 'Article' do
33
59
  f.input :title
@@ -38,26 +64,54 @@ Why 2 separated scripts? In this way you can include a different version of *qui
38
64
  end
39
65
  ```
40
66
 
41
- Toolbar buttons configuration:
67
+ ### Toolbar buttons configuration
42
68
 
43
69
  ```ruby
44
- f.input :description, as: :quill_editor, input_html: {data: {options: {modules: {toolbar: [['bold', 'italic', 'underline'], ['link']]}, placeholder: 'Type something...', theme: 'snow'}}}
70
+ f.input :description, as: :quill_editor, input_html: { data: { options: { modules: { toolbar: [['bold', 'italic', 'underline'], ['link']] }, placeholder: 'Type something...', theme: 'snow' } } }
45
71
  ```
46
72
 
47
- ## Notes
73
+ ### ImageUploader plugin
74
+
75
+ 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).
76
+
77
+ ```ruby
78
+ # Upload method (to be included in the admin entity configuration)
79
+ member_action :upload, method: [:post] do
80
+ result = { success: resource.images.attach(params[:file_upload]) }
81
+ result[:url] = url_for(resource.images.last) if result[:success]
82
+ render json: result
83
+ end
84
+ ```
85
+
86
+ ```ruby
87
+ # Form field
88
+ unless object.new_record?
89
+ plugin_opts = { image_uploader: { server_url: upload_admin_post_path(object.id), field_name: 'file_upload' } }
90
+ f.input :description, as: :quill_editor, input_html: { data: { plugins: plugin_opts } }
91
+ end
92
+ ```
93
+
94
+ For the relevant files of the upload example see [here](examples/upload_plugin_using_activestorage/).
95
+ Consider that this is just a basic example: images are uploaded as soon as they are attached to the
96
+ editor (regardless of the form submit), it shows the editor only for an existing record (because of
97
+ the *upload_admin_post_path*) and it doesn't provide a way to remove images (just deleting them from
98
+ the editor will not destroy them, you'll need to implement a purge logic for that).
99
+
100
+ ## Changelog
48
101
 
49
- - Upload functions (Images, Documents, Files, etc.) are not implemented yet
102
+ The changelog is available [here](CHANGELOG.md).
50
103
 
51
104
  ## Do you like it? Star it!
52
105
 
53
- If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
106
+ If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source).
54
107
 
55
- Take a look at [other ActiveAdmin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source) that I made if you are curious.
108
+ Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).
56
109
 
57
110
  ## Contributors
58
111
 
59
- - [Mattia Roccoberton](http://blocknot.es) - creator, maintainer
112
+ - [Mattia Roccoberton](http://blocknot.es): author
113
+ - The good guys that opened issues and pull requests from time to time
60
114
 
61
115
  ## License
62
116
 
63
- [MIT](LICENSE.txt)
117
+ The gem is available as open-source under the terms of the [MIT](LICENSE.txt).
data/Rakefile CHANGED
@@ -1,3 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
+
5
+ begin
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ # t.ruby_opts = %w[-w]
10
+ t.rspec_opts = ['--color', '--format documentation']
11
+ end
12
+
13
+ task default: :spec
14
+ rescue LoadError
15
+ puts '! LoadError: no RSpec available'
16
+ end
@@ -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,5 +1,5 @@
1
1
  /*!
2
- * Quill Editor v1.3.6
2
+ * Quill Editor v1.3.7
3
3
  * https://quilljs.com/
4
4
  * Copyright (c) 2014, Jason Chen
5
5
  * Copyright (c) 2013, salesforce.com
@@ -439,7 +439,19 @@ Delta.prototype.slice = function (start, end) {
439
439
  Delta.prototype.compose = function (other) {
440
440
  var thisIter = op.iterator(this.ops);
441
441
  var otherIter = op.iterator(other.ops);
442
- var delta = new Delta();
442
+ var ops = [];
443
+ var firstOther = otherIter.peek();
444
+ if (firstOther != null && typeof firstOther.retain === 'number' && firstOther.attributes == null) {
445
+ var firstLeft = firstOther.retain;
446
+ while (thisIter.peekType() === 'insert' && thisIter.peekLength() <= firstLeft) {
447
+ firstLeft -= thisIter.peekLength();
448
+ ops.push(thisIter.next());
449
+ }
450
+ if (firstOther.retain - firstLeft > 0) {
451
+ otherIter.next(firstOther.retain - firstLeft);
452
+ }
453
+ }
454
+ var delta = new Delta(ops);
443
455
  while (thisIter.hasNext() || otherIter.hasNext()) {
444
456
  if (otherIter.peekType() === 'insert') {
445
457
  delta.push(otherIter.next());
@@ -460,6 +472,13 @@ Delta.prototype.compose = function (other) {
460
472
  var attributes = op.attributes.compose(thisOp.attributes, otherOp.attributes, typeof thisOp.retain === 'number');
461
473
  if (attributes) newOp.attributes = attributes;
462
474
  delta.push(newOp);
475
+
476
+ // Optimization if rest of other is just retain
477
+ if (!otherIter.hasNext() && equal(delta.ops[delta.ops.length - 1], newOp)) {
478
+ var rest = new Delta(thisIter.rest());
479
+ return delta.concat(rest).chop();
480
+ }
481
+
463
482
  // Other op should be delete, we could be an insert or retain
464
483
  // Insert + delete cancels out
465
484
  } else if (typeof otherOp['delete'] === 'number' && typeof thisOp.retain === 'number') {
@@ -617,6 +636,8 @@ module.exports = Delta;
617
636
 
618
637
  var hasOwn = Object.prototype.hasOwnProperty;
619
638
  var toStr = Object.prototype.toString;
639
+ var defineProperty = Object.defineProperty;
640
+ var gOPD = Object.getOwnPropertyDescriptor;
620
641
 
621
642
  var isArray = function isArray(arr) {
622
643
  if (typeof Array.isArray === 'function') {
@@ -646,6 +667,35 @@ var isPlainObject = function isPlainObject(obj) {
646
667
  return typeof key === 'undefined' || hasOwn.call(obj, key);
647
668
  };
648
669
 
670
+ // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target
671
+ var setProperty = function setProperty(target, options) {
672
+ if (defineProperty && options.name === '__proto__') {
673
+ defineProperty(target, options.name, {
674
+ enumerable: true,
675
+ configurable: true,
676
+ value: options.newValue,
677
+ writable: true
678
+ });
679
+ } else {
680
+ target[options.name] = options.newValue;
681
+ }
682
+ };
683
+
684
+ // Return undefined instead of __proto__ if '__proto__' is not an own property
685
+ var getProperty = function getProperty(obj, name) {
686
+ if (name === '__proto__') {
687
+ if (!hasOwn.call(obj, name)) {
688
+ return void 0;
689
+ } else if (gOPD) {
690
+ // In early versions of node, obj['__proto__'] is buggy when obj has
691
+ // __proto__ as an own property. Object.getOwnPropertyDescriptor() works.
692
+ return gOPD(obj, name).value;
693
+ }
694
+ }
695
+
696
+ return obj[name];
697
+ };
698
+
649
699
  module.exports = function extend() {
650
700
  var options, name, src, copy, copyIsArray, clone;
651
701
  var target = arguments[0];
@@ -670,8 +720,8 @@ module.exports = function extend() {
670
720
  if (options != null) {
671
721
  // Extend the base object
672
722
  for (name in options) {
673
- src = target[name];
674
- copy = options[name];
723
+ src = getProperty(target, name);
724
+ copy = getProperty(options, name);
675
725
 
676
726
  // Prevent never-ending loop
677
727
  if (target !== copy) {
@@ -685,11 +735,11 @@ module.exports = function extend() {
685
735
  }
686
736
 
687
737
  // Never move original objects, clone them
688
- target[name] = extend(deep, clone, copy);
738
+ setProperty(target, { name: name, newValue: extend(deep, clone, copy) });
689
739
 
690
740
  // Don't bring in undefined values
691
741
  } else if (typeof copy !== 'undefined') {
692
- target[name] = copy;
742
+ setProperty(target, { name: name, newValue: copy });
693
743
  }
694
744
  }
695
745
  }
@@ -1533,7 +1583,7 @@ Quill.DEFAULTS = {
1533
1583
  Quill.events = _emitter4.default.events;
1534
1584
  Quill.sources = _emitter4.default.sources;
1535
1585
  // eslint-disable-next-line no-undef
1536
- Quill.version = false ? 'dev' : "1.3.6";
1586
+ Quill.version = false ? 'dev' : "1.3.7";
1537
1587
 
1538
1588
  Quill.imports = {
1539
1589
  'delta': _quillDelta2.default,
@@ -3682,8 +3732,8 @@ var LeafBlot = /** @class */ (function (_super) {
3682
3732
  return [this.parent.domNode, offset];
3683
3733
  };
3684
3734
  LeafBlot.prototype.value = function () {
3685
- return _a = {}, _a[this.statics.blotName] = this.statics.value(this.domNode) || true, _a;
3686
3735
  var _a;
3736
+ return _a = {}, _a[this.statics.blotName] = this.statics.value(this.domNode) || true, _a;
3687
3737
  };
3688
3738
  LeafBlot.scope = Registry.Scope.INLINE_BLOT;
3689
3739
  return LeafBlot;
@@ -3832,6 +3882,22 @@ Iterator.prototype.peekType = function () {
3832
3882
  return 'retain';
3833
3883
  };
3834
3884
 
3885
+ Iterator.prototype.rest = function () {
3886
+ if (!this.hasNext()) {
3887
+ return [];
3888
+ } else if (this.offset === 0) {
3889
+ return this.ops.slice(this.index);
3890
+ } else {
3891
+ var offset = this.offset;
3892
+ var index = this.index;
3893
+ var next = this.next();
3894
+ var rest = this.ops.slice(this.index);
3895
+ this.offset = offset;
3896
+ this.index = index;
3897
+ return [next].concat(rest);
3898
+ }
3899
+ };
3900
+
3835
3901
 
3836
3902
  module.exports = lib;
3837
3903
 
@@ -3946,7 +4012,13 @@ function clone(parent, circular, depth, prototype, includeNonEnumerable) {
3946
4012
  } else if (clone.__isDate(parent)) {
3947
4013
  child = new Date(parent.getTime());
3948
4014
  } else if (useBuffer && Buffer.isBuffer(parent)) {
3949
- child = new Buffer(parent.length);
4015
+ if (Buffer.allocUnsafe) {
4016
+ // Node.js >= 4.5.0
4017
+ child = Buffer.allocUnsafe(parent.length);
4018
+ } else {
4019
+ // Older Node.js versions
4020
+ child = new Buffer(parent.length);
4021
+ }
3950
4022
  parent.copy(child);
3951
4023
  return child;
3952
4024
  } else if (_instanceof(parent, Error)) {
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Quill Editor v1.3.6
2
+ * Quill Editor v1.3.7
3
3
  * https://quilljs.com/
4
4
  * Copyright (c) 2014, Jason Chen
5
5
  * Copyright (c) 2013, salesforce.com
@@ -439,7 +439,19 @@ Delta.prototype.slice = function (start, end) {
439
439
  Delta.prototype.compose = function (other) {
440
440
  var thisIter = op.iterator(this.ops);
441
441
  var otherIter = op.iterator(other.ops);
442
- var delta = new Delta();
442
+ var ops = [];
443
+ var firstOther = otherIter.peek();
444
+ if (firstOther != null && typeof firstOther.retain === 'number' && firstOther.attributes == null) {
445
+ var firstLeft = firstOther.retain;
446
+ while (thisIter.peekType() === 'insert' && thisIter.peekLength() <= firstLeft) {
447
+ firstLeft -= thisIter.peekLength();
448
+ ops.push(thisIter.next());
449
+ }
450
+ if (firstOther.retain - firstLeft > 0) {
451
+ otherIter.next(firstOther.retain - firstLeft);
452
+ }
453
+ }
454
+ var delta = new Delta(ops);
443
455
  while (thisIter.hasNext() || otherIter.hasNext()) {
444
456
  if (otherIter.peekType() === 'insert') {
445
457
  delta.push(otherIter.next());
@@ -460,6 +472,13 @@ Delta.prototype.compose = function (other) {
460
472
  var attributes = op.attributes.compose(thisOp.attributes, otherOp.attributes, typeof thisOp.retain === 'number');
461
473
  if (attributes) newOp.attributes = attributes;
462
474
  delta.push(newOp);
475
+
476
+ // Optimization if rest of other is just retain
477
+ if (!otherIter.hasNext() && equal(delta.ops[delta.ops.length - 1], newOp)) {
478
+ var rest = new Delta(thisIter.rest());
479
+ return delta.concat(rest).chop();
480
+ }
481
+
463
482
  // Other op should be delete, we could be an insert or retain
464
483
  // Insert + delete cancels out
465
484
  } else if (typeof otherOp['delete'] === 'number' && typeof thisOp.retain === 'number') {
@@ -617,6 +636,8 @@ module.exports = Delta;
617
636
 
618
637
  var hasOwn = Object.prototype.hasOwnProperty;
619
638
  var toStr = Object.prototype.toString;
639
+ var defineProperty = Object.defineProperty;
640
+ var gOPD = Object.getOwnPropertyDescriptor;
620
641
 
621
642
  var isArray = function isArray(arr) {
622
643
  if (typeof Array.isArray === 'function') {
@@ -646,6 +667,35 @@ var isPlainObject = function isPlainObject(obj) {
646
667
  return typeof key === 'undefined' || hasOwn.call(obj, key);
647
668
  };
648
669
 
670
+ // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target
671
+ var setProperty = function setProperty(target, options) {
672
+ if (defineProperty && options.name === '__proto__') {
673
+ defineProperty(target, options.name, {
674
+ enumerable: true,
675
+ configurable: true,
676
+ value: options.newValue,
677
+ writable: true
678
+ });
679
+ } else {
680
+ target[options.name] = options.newValue;
681
+ }
682
+ };
683
+
684
+ // Return undefined instead of __proto__ if '__proto__' is not an own property
685
+ var getProperty = function getProperty(obj, name) {
686
+ if (name === '__proto__') {
687
+ if (!hasOwn.call(obj, name)) {
688
+ return void 0;
689
+ } else if (gOPD) {
690
+ // In early versions of node, obj['__proto__'] is buggy when obj has
691
+ // __proto__ as an own property. Object.getOwnPropertyDescriptor() works.
692
+ return gOPD(obj, name).value;
693
+ }
694
+ }
695
+
696
+ return obj[name];
697
+ };
698
+
649
699
  module.exports = function extend() {
650
700
  var options, name, src, copy, copyIsArray, clone;
651
701
  var target = arguments[0];
@@ -670,8 +720,8 @@ module.exports = function extend() {
670
720
  if (options != null) {
671
721
  // Extend the base object
672
722
  for (name in options) {
673
- src = target[name];
674
- copy = options[name];
723
+ src = getProperty(target, name);
724
+ copy = getProperty(options, name);
675
725
 
676
726
  // Prevent never-ending loop
677
727
  if (target !== copy) {
@@ -685,11 +735,11 @@ module.exports = function extend() {
685
735
  }
686
736
 
687
737
  // Never move original objects, clone them
688
- target[name] = extend(deep, clone, copy);
738
+ setProperty(target, { name: name, newValue: extend(deep, clone, copy) });
689
739
 
690
740
  // Don't bring in undefined values
691
741
  } else if (typeof copy !== 'undefined') {
692
- target[name] = copy;
742
+ setProperty(target, { name: name, newValue: copy });
693
743
  }
694
744
  }
695
745
  }
@@ -1533,7 +1583,7 @@ Quill.DEFAULTS = {
1533
1583
  Quill.events = _emitter4.default.events;
1534
1584
  Quill.sources = _emitter4.default.sources;
1535
1585
  // eslint-disable-next-line no-undef
1536
- Quill.version = false ? 'dev' : "1.3.6";
1586
+ Quill.version = false ? 'dev' : "1.3.7";
1537
1587
 
1538
1588
  Quill.imports = {
1539
1589
  'delta': _quillDelta2.default,
@@ -3682,8 +3732,8 @@ var LeafBlot = /** @class */ (function (_super) {
3682
3732
  return [this.parent.domNode, offset];
3683
3733
  };
3684
3734
  LeafBlot.prototype.value = function () {
3685
- return _a = {}, _a[this.statics.blotName] = this.statics.value(this.domNode) || true, _a;
3686
3735
  var _a;
3736
+ return _a = {}, _a[this.statics.blotName] = this.statics.value(this.domNode) || true, _a;
3687
3737
  };
3688
3738
  LeafBlot.scope = Registry.Scope.INLINE_BLOT;
3689
3739
  return LeafBlot;
@@ -3832,6 +3882,22 @@ Iterator.prototype.peekType = function () {
3832
3882
  return 'retain';
3833
3883
  };
3834
3884
 
3885
+ Iterator.prototype.rest = function () {
3886
+ if (!this.hasNext()) {
3887
+ return [];
3888
+ } else if (this.offset === 0) {
3889
+ return this.ops.slice(this.index);
3890
+ } else {
3891
+ var offset = this.offset;
3892
+ var index = this.index;
3893
+ var next = this.next();
3894
+ var rest = this.ops.slice(this.index);
3895
+ this.offset = offset;
3896
+ this.index = index;
3897
+ return [next].concat(rest);
3898
+ }
3899
+ };
3900
+
3835
3901
 
3836
3902
  module.exports = lib;
3837
3903
 
@@ -3946,7 +4012,13 @@ function clone(parent, circular, depth, prototype, includeNonEnumerable) {
3946
4012
  } else if (clone.__isDate(parent)) {
3947
4013
  child = new Date(parent.getTime());
3948
4014
  } else if (useBuffer && Buffer.isBuffer(parent)) {
3949
- child = new Buffer(parent.length);
4015
+ if (Buffer.allocUnsafe) {
4016
+ // Node.js >= 4.5.0
4017
+ child = Buffer.allocUnsafe(parent.length);
4018
+ } else {
4019
+ // Older Node.js versions
4020
+ child = new Buffer(parent.length);
4021
+ }
3950
4022
  parent.copy(child);
3951
4023
  return child;
3952
4024
  } else if (_instanceof(parent, Error)) {
@@ -5291,6 +5363,7 @@ var Link = function (_Inline) {
5291
5363
  var node = _get(Link.__proto__ || Object.getPrototypeOf(Link), 'create', this).call(this, value);
5292
5364
  value = this.sanitize(value);
5293
5365
  node.setAttribute('href', value);
5366
+ node.setAttribute('rel', 'noopener noreferrer');
5294
5367
  node.setAttribute('target', '_blank');
5295
5368
  return node;
5296
5369
  }
@@ -9954,7 +10027,7 @@ var SnowTooltip = function (_BaseTooltip) {
9954
10027
  return SnowTooltip;
9955
10028
  }(_base.BaseTooltip);
9956
10029
 
9957
- SnowTooltip.TEMPLATE = ['<a class="ql-preview" target="_blank" href="about:blank"></a>', '<input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL">', '<a class="ql-action"></a>', '<a class="ql-remove"></a>'].join('');
10030
+ SnowTooltip.TEMPLATE = ['<a class="ql-preview" rel="noopener noreferrer" target="_blank" href="about:blank"></a>', '<input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL">', '<a class="ql-action"></a>', '<a class="ql-remove"></a>'].join('');
9958
10031
 
9959
10032
  exports.default = SnowTheme;
9960
10033