medium-editor-rails 1.1.3 → 1.2.0

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
  SHA1:
3
- metadata.gz: 59ed3d1649f4b21ed2ac23f47a5741106dee459d
4
- data.tar.gz: e445c754424ca6d986ec525810233b1f010406d3
3
+ metadata.gz: 2797d94a0b663d77df028d929090e6693d9a0931
4
+ data.tar.gz: bce123c63f3984235f94f8edec1fabf1ebc53b00
5
5
  SHA512:
6
- metadata.gz: ffb12c796fbfb1720486e39b1f3eeea4b784d159ea2c1fe2421db9a474006a88b82899dd1f4d430ca47da200dbf230a21e0e91a2d08e829e3de492a87ff1837d
7
- data.tar.gz: 4632fae0f41e107a21d15ce407e7a3397be860998120abacf4a6762cbb0238574c47e81ffab4773ca155bd46a678ab818b11f006cba0c5f1a9e70d97cb8c152b
6
+ metadata.gz: bff23ff9bc5e9ffd3ad863e6332c078facd03a6e34db99c2566e4177a187467d2655e440f6a15a9a4fbbb7a8e3a0e4deaa8a120aad155a2499af4e2268948600
7
+ data.tar.gz: a27b421862232708df549a2585eec2f20a22a3ec94e75c4b535ca94366b5e3352c7fa1ce39a60d04e83e96045e994241d8ea7ab5697d624a5f3f8e37f280f0da
@@ -1,5 +1,12 @@
1
1
 
2
2
  #### [Current]
3
+ * [e6d136d](../../commit/e6d136d) - __(Ahmet Sezgin Duran)__ Update Medium Editor files
4
+ * [7ee9c60](../../commit/7ee9c60) - __(Ahmet Sezgin Duran)__ Merge tag '1.1.3' into develop
5
+
6
+ 1.1.3
7
+
8
+ #### 1.1.3
9
+ * [8cc5af9](../../commit/8cc5af9) - __(Ahmet Sezgin Duran)__ Bump versions 1.1.3 and 2.1.3
3
10
  * [9a54e41](../../commit/9a54e41) - __(Ahmet Sezgin Duran)__ Update Medium Editor files
4
11
  * [67de6b2](../../commit/67de6b2) - __(Ahmet Sezgin Duran)__ Merge tag '1.1.2' into develop
5
12
 
data/README.md CHANGED
@@ -8,7 +8,7 @@ This gem integrates [Medium Editor](https://github.com/daviferreira/medium-edito
8
8
 
9
9
  ## Version
10
10
 
11
- The latest version of Medium Editor bundled by this gem is [2.1.3](https://github.com/daviferreira/medium-editor/releases)
11
+ The latest version of Medium Editor bundled by this gem is [2.2.0](https://github.com/daviferreira/medium-editor/releases)
12
12
 
13
13
  ## Installation
14
14
 
@@ -1,6 +1,6 @@
1
1
  module MediumEditorRails
2
2
  module Rails
3
- VERSION = '1.1.3'
4
- MEDIUM_EDITOR_VERSION = '2.1.3'
3
+ VERSION = '1.2.0'
4
+ MEDIUM_EDITOR_VERSION = '2.2.0'
5
5
  end
6
6
  end
@@ -32,6 +32,13 @@ if (typeof module === 'object') {
32
32
  // https://github.com/jashkenas/underscore
33
33
  var now = Date.now || function () {
34
34
  return new Date().getTime();
35
+ }, keyCode = {
36
+ BACKSPACE: 8,
37
+ TAB: 9,
38
+ ENTER: 13,
39
+ ESCAPE: 27,
40
+ SPACE: 32,
41
+ DELETE: 46
35
42
  };
36
43
 
37
44
  // https://github.com/jashkenas/underscore
@@ -98,7 +105,7 @@ if (typeof module === 'object') {
98
105
  function findAdjacentTextNodeWithContent(rootNode, targetNode, ownerDocument) {
99
106
  var pastTarget = false,
100
107
  nextNode,
101
- nodeIterator = ownerDocument.createNodeIterator(rootNode, NodeFilter.SHOW_TEXT);
108
+ nodeIterator = ownerDocument.createNodeIterator(rootNode, NodeFilter.SHOW_TEXT, null, false);
102
109
 
103
110
  // Use a native NodeIterator to iterate over all the text nodes that are descendants
104
111
  // of the rootNode. Once past the targetNode, choose the first non-empty text node
@@ -107,7 +114,7 @@ if (typeof module === 'object') {
107
114
  if (nextNode === targetNode) {
108
115
  pastTarget = true;
109
116
  } else if (pastTarget) {
110
- if (nextNode.nodeType === 3 && nextNode.nodeValue && nextNode.nodeValue.length > 0) {
117
+ if (nextNode.nodeType === 3 && nextNode.nodeValue && nextNode.nodeValue.trim().length > 0) {
111
118
  break;
112
119
  }
113
120
  }
@@ -219,7 +226,9 @@ if (typeof module === 'object') {
219
226
  var selection, range, el, fragment, node, lastNode;
220
227
 
221
228
  if (doc.queryCommandSupported('insertHTML')) {
222
- return doc.execCommand('insertHTML', false, html);
229
+ try {
230
+ return doc.execCommand('insertHTML', false, html);
231
+ } catch (ignore) {}
223
232
  }
224
233
 
225
234
  selection = window.getSelection();
@@ -267,6 +276,7 @@ if (typeof module === 'object') {
267
276
  disableAnchorForm: false,
268
277
  disablePlaceholders: false,
269
278
  elementsContainer: false,
279
+ imageDragging: true,
270
280
  standardizeSelectionStart: false,
271
281
  contentWindow: window,
272
282
  ownerDocument: document,
@@ -316,6 +326,7 @@ if (typeof module === 'object') {
316
326
  this.initThrottledMethods()
317
327
  .initElements()
318
328
  .bindSelect()
329
+ .bindDragDrop()
319
330
  .bindPaste()
320
331
  .setPlaceholders()
321
332
  .bindElementActions()
@@ -597,7 +608,7 @@ if (typeof module === 'object') {
597
608
  this.on(this.elements[index], 'keypress', function (e) {
598
609
  var node,
599
610
  tagName;
600
- if (e.which === 32) {
611
+ if (e.which === keyCode.SPACE) {
601
612
  node = getSelectionStart.call(self);
602
613
  tagName = node.tagName.toLowerCase();
603
614
  if (tagName === 'a') {
@@ -614,7 +625,7 @@ if (typeof module === 'object') {
614
625
  if (node && node.getAttribute('data-medium-element') && node.children.length === 0 && !(self.options.disableReturn || node.getAttribute('data-disable-return'))) {
615
626
  self.options.ownerDocument.execCommand('formatBlock', false, 'p');
616
627
  }
617
- if (e.which === 13) {
628
+ if (e.which === keyCode.ENTER) {
618
629
  node = getSelectionStart.call(self);
619
630
  tagName = node.tagName.toLowerCase();
620
631
  editorElement = self.getSelectionElement();
@@ -657,7 +668,7 @@ if (typeof module === 'object') {
657
668
  bindReturn: function (index) {
658
669
  var self = this;
659
670
  this.on(this.elements[index], 'keypress', function (e) {
660
- if (e.which === 13) {
671
+ if (e.which === keyCode.ENTER) {
661
672
  if (self.options.disableReturn || this.getAttribute('data-disable-return')) {
662
673
  e.preventDefault();
663
674
  } else if (self.options.disableDoubleReturn || this.getAttribute('data-disable-double-return')) {
@@ -675,7 +686,7 @@ if (typeof module === 'object') {
675
686
  var self = this;
676
687
  this.on(this.elements[index], 'keydown', function (e) {
677
688
 
678
- if (e.which === 9) {
689
+ if (e.which === keyCode.TAB) {
679
690
  // Override tab only for pre nodes
680
691
  var tag = getSelectionStart.call(self).tagName.toLowerCase();
681
692
  if (tag === 'pre') {
@@ -694,7 +705,7 @@ if (typeof module === 'object') {
694
705
  self.options.ownerDocument.execCommand('indent', e);
695
706
  }
696
707
  }
697
- } else if (e.which === 8 || e.which === 46 || e.which === 13) {
708
+ } else if (e.which === keyCode.BACKSPACE || e.which === keyCode.DELETE || e.which === keyCode.ENTER) {
698
709
 
699
710
  // Bind keys which can create or destroy a block element: backspace, delete, return
700
711
  self.onBlockModifier(e);
@@ -705,26 +716,24 @@ if (typeof module === 'object') {
705
716
  },
706
717
 
707
718
  onBlockModifier: function (e) {
708
-
709
719
  var range, sel, p, node = getSelectionStart.call(this),
710
720
  tagName = node.tagName.toLowerCase(),
711
721
  isEmpty = /^(\s+|<br\/?>)?$/i,
712
722
  isHeader = /h\d/i;
713
723
 
714
- // backspace or return
715
- if ((e.which === 8 || e.which === 13)
724
+ if ((e.which === keyCode.BACKSPACE || e.which === keyCode.ENTER)
716
725
  && node.previousElementSibling
717
726
  // in a header
718
727
  && isHeader.test(tagName)
719
728
  // at the very end of the block
720
729
  && getCaretOffsets(node).left === 0) {
721
- if (e.which === 8 && isEmpty.test(node.previousElementSibling.innerHTML)) {
730
+ if (e.which === keyCode.BACKSPACE && isEmpty.test(node.previousElementSibling.innerHTML)) {
722
731
  // backspacing the begining of a header into an empty previous element will
723
732
  // change the tagName of the current node to prevent one
724
733
  // instead delete previous node and cancel the event.
725
734
  node.previousElementSibling.parentNode.removeChild(node.previousElementSibling);
726
735
  e.preventDefault();
727
- } else if (e.which === 13) {
736
+ } else if (e.which === keyCode.ENTER) {
728
737
  // hitting return in the begining of a header will create empty header elements before the current one
729
738
  // instead, make "<p><br></p>" element, which are what happens if you hit return in an empty paragraph
730
739
  p = this.options.ownerDocument.createElement('p');
@@ -732,9 +741,7 @@ if (typeof module === 'object') {
732
741
  node.previousElementSibling.parentNode.insertBefore(p, node);
733
742
  e.preventDefault();
734
743
  }
735
-
736
- // delete
737
- } else if (e.which === 46
744
+ } else if (e.which === keyCode.DELETE
738
745
  && node.nextElementSibling
739
746
  && node.previousElementSibling
740
747
  // not in a header
@@ -762,7 +769,6 @@ if (typeof module === 'object') {
762
769
 
763
770
  e.preventDefault();
764
771
  }
765
-
766
772
  },
767
773
 
768
774
  buttonTemplate: function (btnType) {
@@ -1026,6 +1032,65 @@ if (typeof module === 'object') {
1026
1032
  return this;
1027
1033
  },
1028
1034
 
1035
+
1036
+ bindDragDrop: function () {
1037
+ var self = this, i, className, onDrag, onDrop, element;
1038
+
1039
+ if (!self.options.imageDragging) {
1040
+ return;
1041
+ }
1042
+
1043
+ className = 'medium-editor-dragover';
1044
+
1045
+ onDrag = function (e) {
1046
+ e.preventDefault();
1047
+ e.dataTransfer.dropEffect = "copy";
1048
+
1049
+ if (e.type === "dragover") {
1050
+ this.classList.add(className);
1051
+ } else {
1052
+ this.classList.remove(className);
1053
+ }
1054
+ };
1055
+
1056
+ onDrop = function (e) {
1057
+ var files;
1058
+ e.preventDefault();
1059
+ e.stopPropagation();
1060
+ files = Array.prototype.slice.call(e.dataTransfer.files, 0);
1061
+ files.some(function (file) {
1062
+ if (file.type.match("image")) {
1063
+ var fileReader, id;
1064
+ fileReader = new FileReader();
1065
+ fileReader.readAsDataURL(file);
1066
+
1067
+ id = 'medium-img-' + (+new Date());
1068
+ insertHTMLCommand(self.options.ownerDocument, '<img class="medium-image-loading" id="' + id + '" />');
1069
+
1070
+ fileReader.onload = function () {
1071
+ var img = document.getElementById(id);
1072
+ if (img) {
1073
+ img.removeAttribute('id');
1074
+ img.removeAttribute('class');
1075
+ img.src = fileReader.result;
1076
+ }
1077
+ };
1078
+ }
1079
+ });
1080
+ this.classList.remove(className);
1081
+ };
1082
+
1083
+ for (i = 0; i < this.elements.length; i += 1) {
1084
+ element = this.elements[i];
1085
+
1086
+
1087
+ this.on(element, 'dragover', onDrag);
1088
+ this.on(element, 'dragleave', onDrag);
1089
+ this.on(element, 'drop', onDrop);
1090
+ }
1091
+ return this;
1092
+ },
1093
+
1029
1094
  stopSelectionUpdates: function () {
1030
1095
  this.preventSelectionUpdates = true;
1031
1096
  },
@@ -1141,15 +1206,7 @@ if (typeof module === 'object') {
1141
1206
  }
1142
1207
  },
1143
1208
 
1144
- findMatchingSelectionParent: function (testElementFunction) {
1145
- var selection = this.options.contentWindow.getSelection(), range, current;
1146
-
1147
- if (selection.rangeCount === 0) {
1148
- return false;
1149
- }
1150
-
1151
- range = selection.getRangeAt(0);
1152
- current = range.commonAncestorContainer;
1209
+ traverseUp: function (current, testElementFunction) {
1153
1210
 
1154
1211
  do {
1155
1212
  if (current.nodeType === 1) {
@@ -1166,6 +1223,21 @@ if (typeof module === 'object') {
1166
1223
  } while (current);
1167
1224
 
1168
1225
  return false;
1226
+
1227
+ },
1228
+
1229
+ findMatchingSelectionParent: function (testElementFunction) {
1230
+ var selection = this.options.contentWindow.getSelection(), range, current;
1231
+
1232
+ if (selection.rangeCount === 0) {
1233
+ return false;
1234
+ }
1235
+
1236
+ range = selection.getRangeAt(0);
1237
+ current = range.commonAncestorContainer;
1238
+
1239
+ return this.traverseUp(current, testElementFunction);
1240
+
1169
1241
  },
1170
1242
 
1171
1243
  getSelectionElement: function () {
@@ -1383,7 +1455,7 @@ if (typeof module === 'object') {
1383
1455
  getSelectedParentElement: function () {
1384
1456
  var selectedParentElement = null,
1385
1457
  range = this.selectionRange;
1386
- if (this.rangeSelectsSingleNode(range)) {
1458
+ if (this.rangeSelectsSingleNode(range) && range.startContainer.childNodes[range.startOffset].nodeType !== 3) {
1387
1459
  selectedParentElement = range.startContainer.childNodes[range.startOffset];
1388
1460
  } else if (range.startContainer.nodeType === 3) {
1389
1461
  selectedParentElement = range.startContainer.parentNode;
@@ -1542,7 +1614,7 @@ if (typeof module === 'object') {
1542
1614
  var button = null,
1543
1615
  target;
1544
1616
 
1545
- if (e.keyCode === 13) {
1617
+ if (e.keyCode === keyCode.ENTER) {
1546
1618
  e.preventDefault();
1547
1619
  if (self.options.anchorTarget && self.anchorTarget.checked) {
1548
1620
  target = "_blank";
@@ -1555,7 +1627,7 @@ if (typeof module === 'object') {
1555
1627
  }
1556
1628
 
1557
1629
  self.createLink(this, target, button);
1558
- } else if (e.keyCode === 27) {
1630
+ } else if (e.keyCode === keyCode.ESCAPE) {
1559
1631
  e.preventDefault();
1560
1632
  self.showToolbarActions();
1561
1633
  restoreSelection.call(self, self.savedSelection);
@@ -1625,7 +1697,7 @@ if (typeof module === 'object') {
1625
1697
  halfOffsetWidth,
1626
1698
  defaultLeft;
1627
1699
 
1628
- self.anchorPreview.querySelector('i').textContent = anchorEl.href;
1700
+ self.anchorPreview.querySelector('i').textContent = anchorEl.attributes.href.value;
1629
1701
  halfOffsetWidth = self.anchorPreview.offsetWidth / 2;
1630
1702
  defaultLeft = self.options.diffLeft - halfOffsetWidth;
1631
1703
 
@@ -1724,7 +1796,7 @@ if (typeof module === 'object') {
1724
1796
  // We may actually be displaying the anchor preview, which should be controlled by options.delay
1725
1797
  this.delay(function () {
1726
1798
  if (self.activeAnchor) {
1727
- self.showAnchorForm(self.activeAnchor.href);
1799
+ self.showAnchorForm(self.activeAnchor.attributes.href.value);
1728
1800
  }
1729
1801
  self.keepToolbarAlive = false;
1730
1802
  });
@@ -1822,7 +1894,23 @@ if (typeof module === 'object') {
1822
1894
  createLink: function (input, target, buttonClass) {
1823
1895
  var i, event;
1824
1896
 
1825
- if (input.value.trim().length === 0) {
1897
+ this.createLinkInternal(input.value, target, buttonClass);
1898
+
1899
+ if (this.options.targetBlank || target === "_blank" || buttonClass) {
1900
+ event = this.options.ownerDocument.createEvent("HTMLEvents");
1901
+ event.initEvent("input", true, true, this.options.contentWindow);
1902
+ for (i = 0; i < this.elements.length; i += 1) {
1903
+ this.elements[i].dispatchEvent(event);
1904
+ }
1905
+ }
1906
+
1907
+ this.checkSelection();
1908
+ this.showToolbarActions();
1909
+ input.value = '';
1910
+ },
1911
+
1912
+ createLinkInternal: function (url, target, buttonClass) {
1913
+ if (!url || url.trim().length === 0) {
1826
1914
  this.hideToolbarActions();
1827
1915
  return;
1828
1916
  }
@@ -1830,10 +1918,10 @@ if (typeof module === 'object') {
1830
1918
  restoreSelection.call(this, this.savedSelection);
1831
1919
 
1832
1920
  if (this.options.checkLinkFormat) {
1833
- input.value = this.checkLinkFormat(input.value);
1921
+ url = this.checkLinkFormat(url);
1834
1922
  }
1835
1923
 
1836
- this.options.ownerDocument.execCommand('createLink', false, input.value);
1924
+ this.options.ownerDocument.execCommand('createLink', false, url);
1837
1925
 
1838
1926
  if (this.options.targetBlank || target === "_blank") {
1839
1927
  this.setTargetBlank();
@@ -1842,18 +1930,6 @@ if (typeof module === 'object') {
1842
1930
  if (buttonClass) {
1843
1931
  this.setButtonClass(buttonClass);
1844
1932
  }
1845
-
1846
- if (this.options.targetBlank || target === "_blank" || buttonClass) {
1847
- event = this.options.ownerDocument.createEvent("HTMLEvents");
1848
- event.initEvent("input", true, true, this.options.contentWindow);
1849
- for (i = 0; i < this.elements.length; i += 1) {
1850
- this.elements[i].dispatchEvent(event);
1851
- }
1852
- }
1853
-
1854
- this.checkSelection();
1855
- this.showToolbarActions();
1856
- input.value = '';
1857
1933
  },
1858
1934
 
1859
1935
  positionToolbarIfShown: function () {
@@ -1951,11 +2027,7 @@ if (typeof module === 'object') {
1951
2027
  paragraphs = e.clipboardData.getData(dataFormatPlain).split(/[\r\n]/g);
1952
2028
  for (p = 0; p < paragraphs.length; p += 1) {
1953
2029
  if (paragraphs[p] !== '') {
1954
- if (navigator.userAgent.match(/firefox/i) && p === 0) {
1955
- html += self.htmlEntities(paragraphs[p]);
1956
- } else {
1957
- html += '<p>' + self.htmlEntities(paragraphs[p]) + '</p>';
1958
- }
2030
+ html += '<p>' + self.htmlEntities(paragraphs[p]) + '</p>';
1959
2031
  }
1960
2032
  }
1961
2033
  insertHTMLCommand(self.options.ownerDocument, html);
@@ -2092,7 +2164,7 @@ if (typeof module === 'object') {
2092
2164
  }
2093
2165
 
2094
2166
  }
2095
- this.options.ownerDocument.execCommand('insertHTML', false, fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));
2167
+ insertHTMLCommand(this.options.ownerDocument, fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));
2096
2168
  },
2097
2169
  isCommonBlock: function (el) {
2098
2170
  return (el && (el.tagName.toLowerCase() === 'p' || el.tagName.toLowerCase() === 'div'));
@@ -2138,7 +2210,10 @@ if (typeof module === 'object') {
2138
2210
  var i,
2139
2211
  el,
2140
2212
  new_el,
2141
- spans = container_el.querySelectorAll('.replace-with');
2213
+ spans = container_el.querySelectorAll('.replace-with'),
2214
+ isCEF = function (el) {
2215
+ return (el && el.nodeName !== '#text' && el.getAttribute('contenteditable') === 'false');
2216
+ };
2142
2217
 
2143
2218
  for (i = 0; i < spans.length; i += 1) {
2144
2219
 
@@ -2164,6 +2239,11 @@ if (typeof module === 'object') {
2164
2239
 
2165
2240
  el = spans[i];
2166
2241
 
2242
+ // bail if span is in contenteditable = false
2243
+ if (this.traverseUp(el, isCEF)) {
2244
+ return false;
2245
+ }
2246
+
2167
2247
  // remove empty spans, replace others with their contents
2168
2248
  if (/^\s*$/.test()) {
2169
2249
  el.parentNode.removeChild(el);
@@ -124,8 +124,7 @@
124
124
 
125
125
  .stalker-toolbar {
126
126
  -webkit-animation: pop-upwards 160ms forwards linear;
127
- -ms-animation: pop-upwards 160ms forwards linear;
128
- animation: pop-upwards 160ms forwards linear;
127
+ animation: pop-upwards 160ms forwards linear;
129
128
  -webkit-transition: top 0.075s ease-out, left 0.075s ease-out;
130
129
  transition: top 0.075s ease-out, left 0.075s ease-out; }
131
130
 
@@ -150,8 +149,7 @@
150
149
  outline: 0;
151
150
  border: none;
152
151
  box-shadow: none;
153
- -webkit-appearance: none;
154
- -moz-appearance: none; }
152
+ appearance: none; }
155
153
  .medium-editor-toolbar-form label {
156
154
  display: block; }
157
155
  .medium-editor-toolbar-form a {
@@ -170,3 +168,35 @@
170
168
  content: attr(data-placeholder) !important;
171
169
  font-style: italic;
172
170
  white-space: pre; }
171
+
172
+ .medium-editor-dragover {
173
+ background: #ddd; }
174
+
175
+ .medium-image-loading {
176
+ width: 40px;
177
+ height: 40px;
178
+ background-color: #333;
179
+ display: inline-block;
180
+ border-radius: 100%;
181
+ -webkit-animation: medium-image-loading-animation 1s infinite ease-in-out;
182
+ animation: medium-image-loading-animation 1s infinite ease-in-out; }
183
+
184
+ @-webkit-keyframes medium-image-loading-animation {
185
+ 0% {
186
+ -webkit-transform: scale(0);
187
+ transform: scale(0); }
188
+
189
+ 100% {
190
+ -webkit-transform: scale(1);
191
+ transform: scale(1);
192
+ opacity: 0; } }
193
+
194
+ @keyframes medium-image-loading-animation {
195
+ 0% {
196
+ -webkit-transform: scale(0);
197
+ transform: scale(0); }
198
+
199
+ 100% {
200
+ -webkit-transform: scale(1);
201
+ transform: scale(1);
202
+ opacity: 0; } }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: medium-editor-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmet Sezgin Duran
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-01 00:00:00.000000000 Z
11
+ date: 2015-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties