squire-rails 0.0.3 → 0.0.4

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
  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