squire-rails 0.0.3 → 0.0.4

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: 398337563890132e5830d98979f048918d241a65
4
- data.tar.gz: 369080a22ada52156865c0761f168479f4a0ff49
3
+ metadata.gz: 71603b368ec71fe5cf214adf46464eef336023dd
4
+ data.tar.gz: 6b4dbbce99f7fbae8a142e1d67ae121028d04265
5
5
  SHA512:
6
- metadata.gz: 8727b1dcdaa35bb14f3ba5e926254a9d36a55aefcf6932f622a40fde33687df45865669926d93ed3c75b8a45283430710213c65f848e96669fb98ffed3a6ddfb
7
- data.tar.gz: 12ecb53d2bdeff9eb00fa9b818c9ab166de6702ae954f95e75a6e92c92080d2805cb415bf718b8f3b6567edbb3f05fc12f18c09712267d4cb5c75637e763e7bb
6
+ metadata.gz: 10e4d50c2b1eb393e8edff64c94e9ed1b12a4a7551b1b684a3b0027253a6d2a83c341cd501ab3df05f8cde4c08143f3e754fea7ef84c180c3c34dcd1b4ae0ece
7
+ data.tar.gz: 98162dbf3641b1a433f249c14d1548deb8eb1a8ee652b05f6730db7534c6b9cb10440acbef87e7c8fd0df30bdb7e31e3518f16de330fb1b88596362ac45d6182
@@ -50,18 +50,18 @@
50
50
  <option data-fonts="verdana">Verdana</option>
51
51
  </select><br>
52
52
 
53
- <div class="btn submitFont">Apply</div>
53
+ <div class="btn btn-black submitFont">Apply</div>
54
54
  </div>
55
55
  <div id="drop-link">
56
56
  <strong>Insert Link</strong>
57
57
  <i class="fa fa-chevron-up squire-quit"></i>
58
58
  <input placeholder="Link URL" type="text" id="url" />
59
- <div class="btn submitLink">Insert</div>
59
+ <div class="btn btn-black submitLink">Insert</div>
60
60
  </div>
61
61
  <div id="drop-image">
62
62
  <strong>Insert Image</strong>
63
63
  <i class="fa fa-chevron-up squire-quit"></i>
64
64
  <input placeholder="Image URL" type="text" id="imageUrl" />
65
- <div class="btn sumbitImageURL">Insert</div>
65
+ <div class="btn btn-black sumbitImageURL">Insert</div>
66
66
  </div>
67
67
  </div>
@@ -42,7 +42,7 @@ $(document).ready(function() {
42
42
  });
43
43
 
44
44
  this.linkDrop.on('open', function () {
45
- $('.squire-quit').click(function () {
45
+ $('.quit').click(function () {
46
46
  $(this).parent().parent().removeClass('drop-open');
47
47
  });
48
48
 
@@ -62,7 +62,7 @@ $(document).ready(function() {
62
62
  });
63
63
 
64
64
  this.imageDrop.on('open', function () {
65
- $('.squire-quit').unbind().click(function () {
65
+ $('.quit').unbind().click(function () {
66
66
  $(this).parent().parent().removeClass('drop-open');
67
67
  });
68
68
 
@@ -85,7 +85,7 @@ $(document).ready(function() {
85
85
  });
86
86
 
87
87
  this.fontDrop.on('open', function () {
88
- $('.squire-quit').click(function () {
88
+ $('.quit').click(function () {
89
89
  $(this).parent().parent().removeClass('drop-open');
90
90
  });
91
91
 
@@ -153,19 +153,30 @@ $(document).ready(function() {
153
153
  });
154
154
  });
155
155
 
156
+ iframe.addEventListener('load', function() {
157
+ // Make sure we're in standards mode.
158
+ var doc = iframe.contentDocument;
159
+ if ( doc.compatMode !== 'CSS1Compat' ) {
160
+ doc.open();
161
+ doc.write( '<!DOCTYPE html><title></title>' );
162
+ doc.close();
163
+ }
164
+ // doc.close() can cause a re-entrant load event in some browsers,
165
+ // such as IE9.
166
+ if ( iframe.contentWindow.editor ) {
167
+ return;
168
+ }
169
+
170
+ iframe.contentWindow.editor = new Squire(iframe.contentWindow.document);
171
+ iframe.contentWindow.document.head.appendChild(style);
172
+ });
173
+
156
174
  $(container).append(div);
157
175
  $(container).append(iframe);
158
176
 
159
177
  var style = document.createElement('style');
160
178
  style.innerHTML = 'blockquote { border-left: 3px green solid; padding-left: 5px; }';
161
179
 
162
-
163
- iframe.contentWindow.editor = new Squire(iframe.contentWindow.document);
164
- iframe.addEventListener('load', function() {
165
- iframe.contentWindow.editor = new Squire(iframe.contentWindow.document);
166
- });
167
-
168
- iframe.contentWindow.document.head.appendChild(style);
169
180
  return iframe.contentWindow.editor;
170
181
  };
171
182
  });
@@ -1,3 +1,3 @@
1
1
  module SquireRails
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -291,12 +291,14 @@ function fixCursor ( node ) {
291
291
  // cursor to appear.
292
292
  var doc = node.ownerDocument,
293
293
  root = node,
294
- fixer, child,
295
- l, instance;
294
+ fixer, child, instance;
296
295
 
297
296
  if ( node.nodeName === 'BODY' ) {
298
297
  if ( !( child = node.firstChild ) || child.nodeName === 'BR' ) {
299
- fixer = doc.createElement( 'DIV' );
298
+ instance = getSquireInstance( doc );
299
+ fixer = instance ?
300
+ instance.createDefaultBlock() :
301
+ createElement( doc, 'DIV' );
300
302
  if ( child ) {
301
303
  node.replaceChild( fixer, child );
302
304
  }
@@ -318,14 +320,7 @@ function fixCursor ( node ) {
318
320
  if ( !child ) {
319
321
  if ( cantFocusEmptyTextNodes ) {
320
322
  fixer = doc.createTextNode( ZWS );
321
- // Find the relevant Squire instance and notify
322
- l = instances.length;
323
- while ( l-- ) {
324
- instance = instances[l];
325
- if ( instance._doc === doc ) {
326
- instance._didAddZWS();
327
- }
328
- }
323
+ getSquireInstance( doc )._didAddZWS();
329
324
  } else {
330
325
  fixer = doc.createTextNode( '' );
331
326
  }
@@ -351,7 +346,7 @@ function fixCursor ( node ) {
351
346
  }
352
347
  }
353
348
  else if ( !node.querySelector( 'BR' ) ) {
354
- fixer = doc.createElement( 'BR' );
349
+ fixer = createElement( doc, 'BR' );
355
350
  while ( ( child = node.lastElementChild ) && !isInline( child ) ) {
356
351
  node = child;
357
352
  }
@@ -426,8 +421,8 @@ function split ( node, offset, stopNode ) {
426
421
  offset = next;
427
422
  }
428
423
 
429
- // Maintain li numbering
430
- if ( node.nodeName === 'OL' ) {
424
+ // Maintain li numbering if inside a quote.
425
+ if ( node.nodeName === 'OL' && getNearest( node, 'BLOCKQUOTE' ) ) {
431
426
  clone.start = ( +node.start || 1 ) + node.childNodes.length - 1;
432
427
  }
433
428
 
@@ -566,7 +561,7 @@ function mergeContainers ( node ) {
566
561
  if ( prev && areAlike( prev, node ) ) {
567
562
  if ( !isContainer( prev ) ) {
568
563
  if ( isListItem ) {
569
- block = doc.createElement( 'DIV' );
564
+ block = createElement( doc, 'DIV' );
570
565
  block.appendChild( empty( prev ) );
571
566
  prev.appendChild( block );
572
567
  } else {
@@ -583,7 +578,7 @@ function mergeContainers ( node ) {
583
578
  mergeContainers( first );
584
579
  }
585
580
  } else if ( isListItem ) {
586
- prev = doc.createElement( 'DIV' );
581
+ prev = createElement( doc, 'DIV' );
587
582
  node.insertBefore( prev, first );
588
583
  fixCursor( prev );
589
584
  }
@@ -616,43 +611,6 @@ var getNodeAfter = function ( node, offset ) {
616
611
 
617
612
  // ---
618
613
 
619
- var forEachTextNodeInRange = function ( range, fn ) {
620
- range = range.cloneRange();
621
- moveRangeBoundariesDownTree( range );
622
-
623
- var startContainer = range.startContainer,
624
- endContainer = range.endContainer,
625
- root = range.commonAncestorContainer,
626
- walker = new TreeWalker(
627
- root, SHOW_TEXT, function (/* node */) {
628
- return true;
629
- }, false ),
630
- textnode = walker.currentNode = startContainer;
631
-
632
- while ( !fn( textnode, range ) &&
633
- textnode !== endContainer &&
634
- ( textnode = walker.nextNode() ) ) {}
635
- };
636
-
637
- var getTextContentInRange = function ( range ) {
638
- var textContent = '';
639
- forEachTextNodeInRange( range, function ( textnode, range ) {
640
- var value = textnode.data;
641
- if ( value && ( /\S/.test( value ) ) ) {
642
- if ( textnode === range.endContainer ) {
643
- value = value.slice( 0, range.endOffset );
644
- }
645
- if ( textnode === range.startContainer ) {
646
- value = value.slice( range.startOffset );
647
- }
648
- textContent += value;
649
- }
650
- });
651
- return textContent;
652
- };
653
-
654
- // ---
655
-
656
614
  var insertNodeInRange = function ( range, node ) {
657
615
  // Insert at start.
658
616
  var startContainer = range.startContainer,
@@ -810,7 +768,7 @@ var insertTreeFragmentIntoRange = function ( range, frag ) {
810
768
  deleteContentsOfRange( range );
811
769
  }
812
770
 
813
- // Move range down into text ndoes
771
+ // Move range down into text nodes
814
772
  moveRangeBoundariesDownTree( range );
815
773
 
816
774
  // If inline, just insert at the current position.
@@ -818,11 +776,14 @@ var insertTreeFragmentIntoRange = function ( range, frag ) {
818
776
  insertNodeInRange( range, frag );
819
777
  range.collapse( false );
820
778
  }
821
- // Otherwise, split up to body, insert inline before and after split
822
- // and insert block in between split, then merge containers.
779
+ // Otherwise, split up to blockquote (if a parent) or body, insert inline
780
+ // before and after split and insert block in between split, then merge
781
+ // containers.
823
782
  else {
824
- var nodeAfterSplit = split( range.startContainer, range.startOffset,
825
- range.startContainer.ownerDocument.body ),
783
+ var splitPoint = range.startContainer,
784
+ nodeAfterSplit = split( splitPoint, range.startOffset,
785
+ getNearest( splitPoint.parentNode, 'BLOCKQUOTE' ) ||
786
+ splitPoint.ownerDocument.body ),
826
787
  nodeBeforeSplit = nodeAfterSplit.previousSibling,
827
788
  startContainer = nodeBeforeSplit,
828
789
  startOffset = startContainer.childNodes.length,
@@ -1097,6 +1058,18 @@ var expandRangeToBlockBoundaries = function ( range ) {
1097
1058
 
1098
1059
  var instances = [];
1099
1060
 
1061
+ function getSquireInstance ( doc ) {
1062
+ var l = instances.length,
1063
+ instance;
1064
+ while ( l-- ) {
1065
+ instance = instances[l];
1066
+ if ( instance._doc === doc ) {
1067
+ return instance;
1068
+ }
1069
+ }
1070
+ return null;
1071
+ }
1072
+
1100
1073
  function Squire ( doc ) {
1101
1074
  var win = doc.defaultView;
1102
1075
  var body = doc.body;
@@ -1353,12 +1326,7 @@ proto.setSelection = function ( range ) {
1353
1326
  if ( isIOS ) {
1354
1327
  this._win.focus();
1355
1328
  }
1356
- var sel;
1357
- if(this._sel === null){
1358
- sel = this._win.getSelection();
1359
- }else{
1360
- sel = this._sel;
1361
- }
1329
+ var sel = this._sel;
1362
1330
  sel.removeAllRanges();
1363
1331
  sel.addRange( range );
1364
1332
  }
@@ -1390,7 +1358,47 @@ proto.getSelection = function () {
1390
1358
  };
1391
1359
 
1392
1360
  proto.getSelectedText = function () {
1393
- return getTextContentInRange( this.getSelection() );
1361
+ var range = this.getSelection(),
1362
+ walker = new TreeWalker(
1363
+ range.commonAncestorContainer,
1364
+ SHOW_TEXT|SHOW_ELEMENT,
1365
+ function ( node ) {
1366
+ return isNodeContainedInRange( range, node, true );
1367
+ }
1368
+ ),
1369
+ startContainer = range.startContainer,
1370
+ endContainer = range.endContainer,
1371
+ node = walker.currentNode = startContainer,
1372
+ textContent = '',
1373
+ addedTextInBlock = false,
1374
+ value;
1375
+
1376
+ if ( !walker.filter( node ) ) {
1377
+ node = walker.nextNode();
1378
+ }
1379
+
1380
+ while ( node ) {
1381
+ if ( node.nodeType === TEXT_NODE ) {
1382
+ value = node.data;
1383
+ if ( value && ( /\S/.test( value ) ) ) {
1384
+ if ( node === endContainer ) {
1385
+ value = value.slice( 0, range.endOffset );
1386
+ }
1387
+ if ( node === startContainer ) {
1388
+ value = value.slice( range.startOffset );
1389
+ }
1390
+ textContent += value;
1391
+ addedTextInBlock = true;
1392
+ }
1393
+ } else if ( node.nodeName === 'BR' ||
1394
+ addedTextInBlock && !isInline( node ) ) {
1395
+ textContent += '\n';
1396
+ addedTextInBlock = false;
1397
+ }
1398
+ node = walker.nextNode();
1399
+ }
1400
+
1401
+ return textContent;
1394
1402
  };
1395
1403
 
1396
1404
  proto.getPath = function () {
@@ -1405,10 +1413,19 @@ var removeZWS = function ( root ) {
1405
1413
  var walker = new TreeWalker( root, SHOW_TEXT, function () {
1406
1414
  return true;
1407
1415
  }, false ),
1408
- node, index;
1416
+ parent, node, index;
1409
1417
  while ( node = walker.nextNode() ) {
1410
1418
  while ( ( index = node.data.indexOf( ZWS ) ) > -1 ) {
1411
- node.deleteData( index, 1 );
1419
+ if ( node.length === 1 ) {
1420
+ do {
1421
+ parent = node.parentNode;
1422
+ parent.removeChild( node );
1423
+ node = parent;
1424
+ } while ( isInline( node ) && !getLength( node ) );
1425
+ break;
1426
+ } else {
1427
+ node.deleteData( index, 1 );
1428
+ }
1412
1429
  }
1413
1430
  }
1414
1431
  };
@@ -1698,7 +1715,7 @@ proto._addFormat = function ( tag, attributes, range ) {
1698
1715
  // If the range is collapsed we simply insert the node by wrapping
1699
1716
  // it round the range and focus it.
1700
1717
  var el, walker, startContainer, endContainer, startOffset, endOffset,
1701
- textNode, needsFormat;
1718
+ node, needsFormat;
1702
1719
 
1703
1720
  if ( range.collapsed ) {
1704
1721
  el = fixCursor( this.createElement( tag, attributes ) );
@@ -1710,16 +1727,21 @@ proto._addFormat = function ( tag, attributes, range ) {
1710
1727
  // partially selected nodes) and if they're not already formatted
1711
1728
  // correctly we wrap them in the appropriate tag.
1712
1729
  else {
1713
- // We don't want to apply formatting twice so we check each text
1714
- // node to see if it has an ancestor with the formatting already.
1715
1730
  // Create an iterator to walk over all the text nodes under this
1716
1731
  // ancestor which are in the range and not already formatted
1717
1732
  // correctly.
1733
+ //
1734
+ // In Blink/WebKit, empty blocks may have no text nodes, just a <br>.
1735
+ // Therefore we wrap this in the tag as well, as this will then cause it
1736
+ // to apply when the user types something in the block, which is
1737
+ // presumably what was intended.
1718
1738
  walker = new TreeWalker(
1719
1739
  range.commonAncestorContainer,
1720
- SHOW_TEXT,
1740
+ SHOW_TEXT|SHOW_ELEMENT,
1721
1741
  function ( node ) {
1722
- return isNodeContainedInRange( range, node, true );
1742
+ return ( node.nodeType === TEXT_NODE ||
1743
+ node.nodeName === 'BR' ) &&
1744
+ isNodeContainedInRange( range, node, true );
1723
1745
  },
1724
1746
  false
1725
1747
  );
@@ -1731,41 +1753,53 @@ proto._addFormat = function ( tag, attributes, range ) {
1731
1753
  endContainer = range.endContainer;
1732
1754
  endOffset = range.endOffset;
1733
1755
 
1734
- // Make sure we start inside a text node.
1756
+ // Make sure we start with a valid node.
1735
1757
  walker.currentNode = startContainer;
1736
- if ( startContainer.nodeType !== TEXT_NODE ) {
1758
+ if ( !walker.filter( startContainer ) ) {
1737
1759
  startContainer = walker.nextNode();
1738
1760
  startOffset = 0;
1739
1761
  }
1740
1762
 
1763
+ // If there are no interesting nodes in the selection, abort
1764
+ if ( !startContainer ) {
1765
+ return range;
1766
+ }
1767
+
1741
1768
  do {
1742
- textNode = walker.currentNode;
1743
- needsFormat = !getNearest( textNode, tag, attributes );
1769
+ node = walker.currentNode;
1770
+ needsFormat = !getNearest( node, tag, attributes );
1744
1771
  if ( needsFormat ) {
1745
- if ( textNode === endContainer &&
1746
- textNode.length > endOffset ) {
1747
- textNode.splitText( endOffset );
1772
+ // <br> can never be a container node, so must have a text node
1773
+ // if node == (end|start)Container
1774
+ if ( node === endContainer && node.length > endOffset ) {
1775
+ node.splitText( endOffset );
1748
1776
  }
1749
- if ( textNode === startContainer && startOffset ) {
1750
- textNode = textNode.splitText( startOffset );
1777
+ if ( node === startContainer && startOffset ) {
1778
+ node = node.splitText( startOffset );
1751
1779
  if ( endContainer === startContainer ) {
1752
- endContainer = textNode;
1780
+ endContainer = node;
1753
1781
  endOffset -= startOffset;
1754
1782
  }
1755
- startContainer = textNode;
1783
+ startContainer = node;
1756
1784
  startOffset = 0;
1757
1785
  }
1758
1786
  el = this.createElement( tag, attributes );
1759
- replaceWith( textNode, el );
1760
- el.appendChild( textNode );
1787
+ replaceWith( node, el );
1788
+ el.appendChild( node );
1761
1789
  }
1762
1790
  } while ( walker.nextNode() );
1763
1791
 
1764
- // Make sure we finish inside a text node. Otherwise offset may have
1765
- // changed.
1792
+ // If we don't finish inside a text node, offset may have changed.
1766
1793
  if ( endContainer.nodeType !== TEXT_NODE ) {
1767
- endContainer = textNode;
1768
- endOffset = textNode.length;
1794
+ if ( node.nodeType === TEXT_NODE ) {
1795
+ endContainer = node;
1796
+ endOffset = node.length;
1797
+ } else {
1798
+ // If <br>, we must have just wrapped it, so it must have only
1799
+ // one child
1800
+ endContainer = node.parentNode;
1801
+ endOffset = 1;
1802
+ }
1769
1803
  }
1770
1804
 
1771
1805
  // Now set the selection to as it was before
@@ -2218,7 +2252,7 @@ var addLinks = function ( frag ) {
2218
2252
  }
2219
2253
  };
2220
2254
 
2221
- var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
2255
+ var allowedBlock = /^(?:A(?:DDRESS|RTICLE|SIDE|UDIO)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/;
2222
2256
 
2223
2257
  var fontSizes = {
2224
2258
  1: 10,
@@ -2555,7 +2589,7 @@ var cleanupBRs = function ( root ) {
2555
2589
 
2556
2590
  proto._ensureBottomLine = function () {
2557
2591
  var body = this._body,
2558
- last = body.lastChild;
2592
+ last = body.lastElementChild;
2559
2593
  if ( !last || last.nodeName !== this.defaultBlockTag || !isBlock( last ) ) {
2560
2594
  body.appendChild( this.createDefaultBlock() );
2561
2595
  }
@@ -2857,10 +2891,12 @@ var keyHandlers = {
2857
2891
  // Don't continue links over a block break; unlikely to be the
2858
2892
  // desired outcome.
2859
2893
  if ( nodeAfterSplit.nodeName === 'A' &&
2860
- !nodeAfterSplit.textContent ) {
2861
- replaceWith( nodeAfterSplit, empty( nodeAfterSplit ) );
2894
+ ( !nodeAfterSplit.textContent ||
2895
+ nodeAfterSplit.textContent === ZWS ) ) {
2896
+ child = self._doc.createTextNode( '' );
2897
+ replaceWith( nodeAfterSplit, child );
2862
2898
  nodeAfterSplit = child;
2863
- continue;
2899
+ break;
2864
2900
  }
2865
2901
 
2866
2902
  while ( child && child.nodeType === TEXT_NODE && !child.data ) {
@@ -3283,6 +3319,50 @@ proto.insertImage = function ( src ) {
3283
3319
  return img;
3284
3320
  };
3285
3321
 
3322
+ // Insert HTML at the cursor location. If the selection is not collapsed
3323
+ // insertTreeFragmentIntoRange will delete the selection so that it is replaced
3324
+ // by the html being inserted.
3325
+ proto.insertHTML = function ( html ) {
3326
+ var range = this.getSelection(),
3327
+ frag = this._doc.createDocumentFragment(),
3328
+ div = this.createElement( 'DIV' );
3329
+
3330
+ // Parse HTML into DOM tree
3331
+ div.innerHTML = html;
3332
+ frag.appendChild( empty( div ) );
3333
+
3334
+ // Record undo checkpoint
3335
+ this._recordUndoState( range );
3336
+ this._getRangeAndRemoveBookmark( range );
3337
+
3338
+ try {
3339
+ frag.normalize();
3340
+ addLinks( frag );
3341
+ cleanTree( frag, true );
3342
+ cleanupBRs( frag );
3343
+ removeEmptyInlines( frag );
3344
+ fixContainer( frag );
3345
+
3346
+ var node = frag;
3347
+ while ( node = getNextBlock( node ) ) {
3348
+ fixCursor( node );
3349
+ }
3350
+
3351
+ insertTreeFragmentIntoRange( range, frag );
3352
+ if ( !canObserveMutations ) {
3353
+ this._docWasChanged();
3354
+ }
3355
+ range.collapse( false );
3356
+ this._ensureBottomLine();
3357
+
3358
+ this.setSelection( range );
3359
+ this._updatePath( range, true );
3360
+ } catch ( error ) {
3361
+ this.didError( error );
3362
+ }
3363
+ return this;
3364
+ };
3365
+
3286
3366
  // --- Formatting ---
3287
3367
 
3288
3368
  var command = function ( method, arg, arg2 ) {
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squire-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - candle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-02 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rails
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ~>
18
- - !ruby/object:Gem::Version
19
- version: 4.0.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ~>
25
- - !ruby/object:Gem::Version
26
- version: 4.0.0
11
+ date: 2015-04-20 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: Squire Editor for rails
28
14
  email:
29
15
  - progted@gmail.com