retreaverjs-rails 0.2.6 → 0.2.7

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: 3885137c8fe180bd0b33e52826f5b26523dc8ca1
4
- data.tar.gz: 9ad2f9a3b1c520459db7d64a98c666c3c8102b69
3
+ metadata.gz: 54b061407ff02088179e557ef6ec1c329a76bc32
4
+ data.tar.gz: 1801601229a32b13860da2fcb247aaf8427c041e
5
5
  SHA512:
6
- metadata.gz: 47f7256897d21e8a218c5f60a6a5c3f7478c4debbfdb63e9d3acc5a17d95adfd45aa99d06978b3d13651ff5c0743f1fdebfc665e876b246d6f9f60c5f00cc221
7
- data.tar.gz: a114c84069a0068da6e8b7779b8f32989beff73077391f29abb55a93205d261c0c94241952a9ebf3852a75ca49939754519e51408e6591dc1b4863cb2b8a5721
6
+ metadata.gz: 5188c2adb2c6d55c88dd90d42ecdff3701bc17944becb4d4f5a909bef3ae1a4075042b1f33b7abf87862ccd7723d3367a3772269f7a8e0c88699cb596b6313fa
7
+ data.tar.gz: 848aed3a5af97fbeccb756391c95e8cd337be2e6967f6a2163393c804683d4d5cb92d9c82612b454190081da28327ed65cf59b3145b3d94331a61754f67cf574
@@ -1,5 +1,5 @@
1
1
  module Retreaver
2
2
  module Rails
3
- VERSION = '0.2.6'
3
+ VERSION = '0.2.7'
4
4
  end
5
5
  end
data/package.json CHANGED
@@ -25,6 +25,11 @@
25
25
  "name": "Jason Kay",
26
26
  "email": "jason@retreaver.com",
27
27
  "url": "http://retreaver.com/"
28
+ },
29
+ {
30
+ "name": "Ahmed El-Daly",
31
+ "email": "aeldaly@gmail.com",
32
+ "url": "http://retreaver.com/"
28
33
  }
29
34
  ],
30
35
  "licenses": [
@@ -38,7 +43,6 @@
38
43
  "node": ">= 0.6.x"
39
44
  },
40
45
  "dependencies": {
41
- "findandreplacedomtext": "^0.4.4"
42
46
  },
43
47
  "devDependencies": {
44
48
  "grunt": "~0.4.5",
@@ -0,0 +1,635 @@
1
+ /**
2
+ * findAndReplaceDOMText v 0.4.3
3
+ * @author James Padolsey http://james.padolsey.com
4
+ * @license http://unlicense.org/UNLICENSE
5
+ *
6
+ * Matches the text of a DOM node against a regular expression
7
+ * and replaces each match (or node-separated portions of the match)
8
+ * in the specified element.
9
+ */
10
+
11
+ if (typeof(Retreaver) === 'undefined') {
12
+ var Retreaver = {};
13
+ }
14
+
15
+ if (typeof(Retreaver.Vendor) === 'undefined') {
16
+ Retreaver.Vendor = {};
17
+ }
18
+
19
+ (function (root, factory) {
20
+ if (typeof module === 'object' && module.exports) {
21
+ // Node/CommonJS
22
+ module.exports = factory();
23
+ } else if (typeof define === 'function' && define.amd) {
24
+ // AMD. Register as an anonymous module.
25
+ define(factory);
26
+ } else {
27
+ // Browser globals
28
+ root.findAndReplaceDOMText = factory();
29
+ }
30
+ }(Retreaver.Vendor, function factory() {
31
+
32
+ var PORTION_MODE_RETAIN = 'retain';
33
+ var PORTION_MODE_FIRST = 'first';
34
+
35
+ var doc = document;
36
+ var hasOwn = {}.hasOwnProperty;
37
+
38
+ function escapeRegExp(s) {
39
+ return String(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
40
+ }
41
+
42
+ function exposed() {
43
+ // Try deprecated arg signature first:
44
+ return deprecated.apply(null, arguments) || findAndReplaceDOMText.apply(null, arguments);
45
+ }
46
+
47
+ function deprecated(regex, node, replacement, captureGroup, elFilter) {
48
+ if ((node && !node.nodeType) && arguments.length <= 2) {
49
+ return false;
50
+ }
51
+ var isReplacementFunction = typeof replacement == 'function';
52
+
53
+ if (isReplacementFunction) {
54
+ replacement = (function(original) {
55
+ return function(portion, match) {
56
+ return original(portion.text, match.startIndex);
57
+ };
58
+ }(replacement));
59
+ }
60
+
61
+ // Awkward support for deprecated argument signature (<0.4.0)
62
+ var instance = findAndReplaceDOMText(node, {
63
+
64
+ find: regex,
65
+
66
+ wrap: isReplacementFunction ? null : replacement,
67
+ replace: isReplacementFunction ? replacement : '$' + (captureGroup || '&'),
68
+
69
+ prepMatch: function(m, mi) {
70
+
71
+ // Support captureGroup (a deprecated feature)
72
+
73
+ if (!m[0]) throw 'findAndReplaceDOMText cannot handle zero-length matches';
74
+
75
+ if (captureGroup > 0) {
76
+ var cg = m[captureGroup];
77
+ m.index += m[0].indexOf(cg);
78
+ m[0] = cg;
79
+ }
80
+
81
+ m.endIndex = m.index + m[0].length;
82
+ m.startIndex = m.index;
83
+ m.index = mi;
84
+
85
+ return m;
86
+ },
87
+ filterElements: elFilter
88
+ });
89
+
90
+ exposed.revert = function() {
91
+ return instance.revert();
92
+ };
93
+
94
+ return true;
95
+ }
96
+
97
+ /**
98
+ * findAndReplaceDOMText
99
+ *
100
+ * Locates matches and replaces with replacementNode
101
+ *
102
+ * @param {Node} node Element or Text node to search within
103
+ * @param {RegExp} options.find The regular expression to match
104
+ * @param {String|Element} [options.wrap] A NodeName, or a Node to clone
105
+ * @param {String|Function} [options.replace='$&'] What to replace each match with
106
+ * @param {Function} [options.filterElements] A Function to be called to check whether to
107
+ * process an element. (returning true = process element,
108
+ * returning false = avoid element)
109
+ */
110
+ function findAndReplaceDOMText(node, options) {
111
+ return new Finder(node, options);
112
+ }
113
+
114
+ exposed.NON_PROSE_ELEMENTS = {
115
+ br:1, hr:1,
116
+ // Media / Source elements:
117
+ script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1,
118
+ // Input elements
119
+ input:1, textarea:1, select:1, option:1, optgroup: 1, button:1
120
+ };
121
+
122
+ exposed.NON_CONTIGUOUS_PROSE_ELEMENTS = {
123
+
124
+ // Elements that will not contain prose or block elements where we don't
125
+ // want prose to be matches across element borders:
126
+
127
+ // Block Elements
128
+ address:1, article:1, aside:1, blockquote:1, dd:1, div:1,
129
+ dl:1, fieldset:1, figcaption:1, figure:1, footer:1, form:1, h1:1, h2:1, h3:1,
130
+ h4:1, h5:1, h6:1, header:1, hgroup:1, hr:1, main:1, nav:1, noscript:1, ol:1,
131
+ output:1, p:1, pre:1, section:1, ul:1,
132
+ // Other misc. elements that are not part of continuous inline prose:
133
+ br:1, li: 1, summary: 1, dt:1, details:1, rp:1, rt:1, rtc:1,
134
+ // Media / Source elements:
135
+ script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1,
136
+ // Input elements
137
+ input:1, textarea:1, select:1, option:1, optgroup:1, button:1,
138
+ // Table related elements:
139
+ table:1, tbody:1, thead:1, th:1, tr:1, td:1, caption:1, col:1, tfoot:1, colgroup:1
140
+
141
+ };
142
+
143
+ exposed.NON_INLINE_PROSE = function(el) {
144
+ return hasOwn.call(exposed.NON_CONTIGUOUS_PROSE_ELEMENTS, el.nodeName.toLowerCase());
145
+ };
146
+
147
+ // Presets accessed via `options.preset` when calling findAndReplaceDOMText():
148
+ exposed.PRESETS = {
149
+ prose: {
150
+ forceContext: exposed.NON_INLINE_PROSE,
151
+ filterElements: function(el) {
152
+ return !hasOwn.call(exposed.NON_PROSE_ELEMENTS, el.nodeName.toLowerCase());
153
+ }
154
+ }
155
+ };
156
+
157
+ exposed.Finder = Finder;
158
+
159
+ /**
160
+ * Finder -- encapsulates logic to find and replace.
161
+ */
162
+ function Finder(node, options) {
163
+
164
+ var preset = options.preset && exposed.PRESETS[options.preset];
165
+
166
+ options.portionMode = options.portionMode || PORTION_MODE_RETAIN;
167
+
168
+ if (preset) {
169
+ for (var i in preset) {
170
+ if (hasOwn.call(preset, i) && !hasOwn.call(options, i)) {
171
+ options[i] = preset[i];
172
+ }
173
+ }
174
+ }
175
+
176
+ this.node = node;
177
+ this.options = options;
178
+
179
+ // Enable match-preparation method to be passed as option:
180
+ this.prepMatch = options.prepMatch || this.prepMatch;
181
+
182
+ this.reverts = [];
183
+
184
+ this.matches = this.search();
185
+
186
+ if (this.matches.length) {
187
+ this.processMatches();
188
+ }
189
+
190
+ }
191
+
192
+ Finder.prototype = {
193
+
194
+ /**
195
+ * Searches for all matches that comply with the instance's 'match' option
196
+ */
197
+ search: function() {
198
+
199
+ var match;
200
+ var matchIndex = 0;
201
+ var offset = 0;
202
+ var regex = this.options.find;
203
+ var textAggregation = this.getAggregateText();
204
+ var matches = [];
205
+ var self = this;
206
+
207
+ regex = typeof regex === 'string' ? RegExp(escapeRegExp(regex), 'g') : regex;
208
+
209
+ matchAggregation(textAggregation);
210
+
211
+ function matchAggregation(textAggregation) {
212
+ for (var i = 0, l = textAggregation.length; i < l; ++i) {
213
+
214
+ var text = textAggregation[i];
215
+
216
+ if (typeof text !== 'string') {
217
+ // Deal with nested contexts: (recursive)
218
+ matchAggregation(text);
219
+ continue;
220
+ }
221
+
222
+ if (regex.global) {
223
+ while (match = regex.exec(text)) {
224
+ matches.push(self.prepMatch(match, matchIndex++, offset));
225
+ }
226
+ } else {
227
+ if (match = text.match(regex)) {
228
+ matches.push(self.prepMatch(match, 0, offset));
229
+ }
230
+ }
231
+
232
+ offset += text.length;
233
+ }
234
+ }
235
+
236
+ return matches;
237
+
238
+ },
239
+
240
+ /**
241
+ * Prepares a single match with useful meta info:
242
+ */
243
+ prepMatch: function(match, matchIndex, characterOffset) {
244
+
245
+ if (!match[0]) {
246
+ throw new Error('findAndReplaceDOMText cannot handle zero-length matches');
247
+ }
248
+
249
+ match.endIndex = characterOffset + match.index + match[0].length;
250
+ match.startIndex = characterOffset + match.index;
251
+ match.index = matchIndex;
252
+
253
+ return match;
254
+ },
255
+
256
+ /**
257
+ * Gets aggregate text within subject node
258
+ */
259
+ getAggregateText: function() {
260
+
261
+ var elementFilter = this.options.filterElements;
262
+ var forceContext = this.options.forceContext;
263
+
264
+ return getText(this.node);
265
+
266
+ /**
267
+ * Gets aggregate text of a node without resorting
268
+ * to broken innerText/textContent
269
+ */
270
+ function getText(node) {
271
+
272
+ if (node.nodeType === 3) {
273
+ return [node.data];
274
+ }
275
+
276
+ if (elementFilter && !elementFilter(node)) {
277
+ return [];
278
+ }
279
+
280
+ var txt = [''];
281
+ var i = 0;
282
+
283
+ if (node = node.firstChild) do {
284
+
285
+ if (node.nodeType === 3) {
286
+ txt[i] += node.data;
287
+ continue;
288
+ }
289
+
290
+ var innerText = getText(node);
291
+
292
+ if (
293
+ forceContext &&
294
+ node.nodeType === 1 &&
295
+ (forceContext === true || forceContext(node))
296
+ ) {
297
+ txt[++i] = innerText;
298
+ txt[++i] = '';
299
+ } else {
300
+ if (typeof innerText[0] === 'string') {
301
+ // Bridge nested text-node data so that they're
302
+ // not considered their own contexts:
303
+ // I.e. ['some', ['thing']] -> ['something']
304
+ txt[i] += innerText.shift();
305
+ }
306
+ if (innerText.length) {
307
+ txt[++i] = innerText;
308
+ txt[++i] = '';
309
+ }
310
+ }
311
+ } while (node = node.nextSibling);
312
+
313
+ return txt;
314
+
315
+ }
316
+
317
+ },
318
+
319
+ /**
320
+ * Steps through the target node, looking for matches, and
321
+ * calling replaceFn when a match is found.
322
+ */
323
+ processMatches: function() {
324
+
325
+ var matches = this.matches;
326
+ var node = this.node;
327
+ var elementFilter = this.options.filterElements;
328
+
329
+ var startPortion,
330
+ endPortion,
331
+ innerPortions = [],
332
+ curNode = node,
333
+ match = matches.shift(),
334
+ atIndex = 0, // i.e. nodeAtIndex
335
+ matchIndex = 0,
336
+ portionIndex = 0,
337
+ doAvoidNode,
338
+ nodeStack = [node];
339
+
340
+ out: while (true) {
341
+
342
+ if (curNode.nodeType === 3) {
343
+
344
+ if (!endPortion && curNode.length + atIndex >= match.endIndex) {
345
+
346
+ // We've found the ending
347
+ endPortion = {
348
+ node: curNode,
349
+ index: portionIndex++,
350
+ text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex),
351
+ indexInMatch: atIndex - match.startIndex,
352
+ indexInNode: match.startIndex - atIndex, // always zero for end-portions
353
+ endIndexInNode: match.endIndex - atIndex,
354
+ isEnd: true
355
+ };
356
+
357
+ } else if (startPortion) {
358
+ // Intersecting node
359
+ innerPortions.push({
360
+ node: curNode,
361
+ index: portionIndex++,
362
+ text: curNode.data,
363
+ indexInMatch: atIndex - match.startIndex,
364
+ indexInNode: 0 // always zero for inner-portions
365
+ });
366
+ }
367
+
368
+ if (!startPortion && curNode.length + atIndex > match.startIndex) {
369
+ // We've found the match start
370
+ startPortion = {
371
+ node: curNode,
372
+ index: portionIndex++,
373
+ indexInMatch: 0,
374
+ indexInNode: match.startIndex - atIndex,
375
+ endIndexInNode: match.endIndex - atIndex,
376
+ text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex)
377
+ };
378
+ }
379
+
380
+ atIndex += curNode.data.length;
381
+
382
+ }
383
+
384
+ doAvoidNode = curNode.nodeType === 1 && elementFilter && !elementFilter(curNode);
385
+
386
+ if (startPortion && endPortion) {
387
+
388
+ curNode = this.replaceMatch(match, startPortion, innerPortions, endPortion);
389
+
390
+ // processMatches has to return the node that replaced the endNode
391
+ // and then we step back so we can continue from the end of the
392
+ // match:
393
+
394
+ atIndex -= (endPortion.node.data.length - endPortion.endIndexInNode);
395
+
396
+ startPortion = null;
397
+ endPortion = null;
398
+ innerPortions = [];
399
+ match = matches.shift();
400
+ portionIndex = 0;
401
+ matchIndex++;
402
+
403
+ if (!match) {
404
+ break; // no more matches
405
+ }
406
+
407
+ } else if (
408
+ !doAvoidNode &&
409
+ (curNode.firstChild || curNode.nextSibling)
410
+ ) {
411
+ // Move down or forward:
412
+ if (curNode.firstChild) {
413
+ nodeStack.push(curNode);
414
+ curNode = curNode.firstChild;
415
+ } else {
416
+ curNode = curNode.nextSibling;
417
+ }
418
+ continue;
419
+ }
420
+
421
+ // Move forward or up:
422
+ while (true) {
423
+ if (curNode.nextSibling) {
424
+ curNode = curNode.nextSibling;
425
+ break;
426
+ }
427
+ curNode = nodeStack.pop();
428
+ if (curNode === node) {
429
+ break out;
430
+ }
431
+ }
432
+
433
+ }
434
+
435
+ },
436
+
437
+ /**
438
+ * Reverts ... TODO
439
+ */
440
+ revert: function() {
441
+ // Reversion occurs backwards so as to avoid nodes subsequently
442
+ // replaced during the matching phase (a forward process):
443
+ for (var l = this.reverts.length; l--;) {
444
+ this.reverts[l]();
445
+ }
446
+ this.reverts = [];
447
+ },
448
+
449
+ prepareReplacementString: function(string, portion, match) {
450
+ var portionMode = this.options.portionMode;
451
+ if (
452
+ portionMode === PORTION_MODE_FIRST &&
453
+ portion.indexInMatch > 0
454
+ ) {
455
+ return '';
456
+ }
457
+ string = string.replace(/\$(\d+|&|`|')/g, function($0, t) {
458
+ var replacement;
459
+ switch(t) {
460
+ case '&':
461
+ replacement = match[0];
462
+ break;
463
+ case '`':
464
+ replacement = match.input.substring(0, match.startIndex);
465
+ break;
466
+ case '\'':
467
+ replacement = match.input.substring(match.endIndex);
468
+ break;
469
+ default:
470
+ replacement = match[+t];
471
+ }
472
+ return replacement;
473
+ });
474
+
475
+ if (portionMode === PORTION_MODE_FIRST) {
476
+ return string;
477
+ }
478
+
479
+ if (portion.isEnd) {
480
+ return string.substring(portion.indexInMatch);
481
+ }
482
+
483
+ return string.substring(portion.indexInMatch, portion.indexInMatch + portion.text.length);
484
+ },
485
+
486
+ getPortionReplacementNode: function(portion, match) {
487
+
488
+ var replacement = this.options.replace || '$&';
489
+ var wrapper = this.options.wrap;
490
+
491
+ if (wrapper && wrapper.nodeType) {
492
+ // Wrapper has been provided as a stencil-node for us to clone:
493
+ var clone = doc.createElement('div');
494
+ clone.innerHTML = wrapper.outerHTML || new XMLSerializer().serializeToString(wrapper);
495
+ wrapper = clone.firstChild;
496
+ }
497
+
498
+ if (typeof replacement == 'function') {
499
+ replacement = replacement(portion, match);
500
+ if (replacement && replacement.nodeType) {
501
+ return replacement;
502
+ }
503
+ return doc.createTextNode(String(replacement));
504
+ }
505
+
506
+ var el = typeof wrapper == 'string' ? doc.createElement(wrapper) : wrapper;
507
+
508
+ replacement = doc.createTextNode(
509
+ this.prepareReplacementString(
510
+ replacement, portion, match
511
+ )
512
+ );
513
+
514
+ if (!replacement.data) {
515
+ return replacement;
516
+ }
517
+
518
+ if (!el) {
519
+ return replacement;
520
+ }
521
+
522
+ el.appendChild(replacement);
523
+
524
+ return el;
525
+ },
526
+
527
+ replaceMatch: function(match, startPortion, innerPortions, endPortion) {
528
+
529
+ var matchStartNode = startPortion.node;
530
+ var matchEndNode = endPortion.node;
531
+
532
+ var precedingTextNode;
533
+ var followingTextNode;
534
+
535
+ if (matchStartNode === matchEndNode) {
536
+
537
+ var node = matchStartNode;
538
+
539
+ if (startPortion.indexInNode > 0) {
540
+ // Add `before` text node (before the match)
541
+ precedingTextNode = doc.createTextNode(node.data.substring(0, startPortion.indexInNode));
542
+ node.parentNode.insertBefore(precedingTextNode, node);
543
+ }
544
+
545
+ // Create the replacement node:
546
+ var newNode = this.getPortionReplacementNode(
547
+ endPortion,
548
+ match
549
+ );
550
+
551
+ node.parentNode.insertBefore(newNode, node);
552
+
553
+ if (endPortion.endIndexInNode < node.length) { // ?????
554
+ // Add `after` text node (after the match)
555
+ followingTextNode = doc.createTextNode(node.data.substring(endPortion.endIndexInNode));
556
+ node.parentNode.insertBefore(followingTextNode, node);
557
+ }
558
+
559
+ node.parentNode.removeChild(node);
560
+
561
+ this.reverts.push(function() {
562
+ if (precedingTextNode === newNode.previousSibling) {
563
+ precedingTextNode.parentNode.removeChild(precedingTextNode);
564
+ }
565
+ if (followingTextNode === newNode.nextSibling) {
566
+ followingTextNode.parentNode.removeChild(followingTextNode);
567
+ }
568
+ newNode.parentNode.replaceChild(node, newNode);
569
+ });
570
+
571
+ return newNode;
572
+
573
+ } else {
574
+ // Replace matchStartNode -> [innerMatchNodes...] -> matchEndNode (in that order)
575
+
576
+
577
+ precedingTextNode = doc.createTextNode(
578
+ matchStartNode.data.substring(0, startPortion.indexInNode)
579
+ );
580
+
581
+ followingTextNode = doc.createTextNode(
582
+ matchEndNode.data.substring(endPortion.endIndexInNode)
583
+ );
584
+
585
+ var firstNode = this.getPortionReplacementNode(
586
+ startPortion,
587
+ match
588
+ );
589
+
590
+ var innerNodes = [];
591
+
592
+ for (var i = 0, l = innerPortions.length; i < l; ++i) {
593
+ var portion = innerPortions[i];
594
+ var innerNode = this.getPortionReplacementNode(
595
+ portion,
596
+ match
597
+ );
598
+ portion.node.parentNode.replaceChild(innerNode, portion.node);
599
+ this.reverts.push((function(portion, innerNode) {
600
+ return function() {
601
+ innerNode.parentNode.replaceChild(portion.node, innerNode);
602
+ };
603
+ }(portion, innerNode)));
604
+ innerNodes.push(innerNode);
605
+ }
606
+
607
+ var lastNode = this.getPortionReplacementNode(
608
+ endPortion,
609
+ match
610
+ );
611
+
612
+ matchStartNode.parentNode.insertBefore(precedingTextNode, matchStartNode);
613
+ matchStartNode.parentNode.insertBefore(firstNode, matchStartNode);
614
+ matchStartNode.parentNode.removeChild(matchStartNode);
615
+
616
+ matchEndNode.parentNode.insertBefore(lastNode, matchEndNode);
617
+ matchEndNode.parentNode.insertBefore(followingTextNode, matchEndNode);
618
+ matchEndNode.parentNode.removeChild(matchEndNode);
619
+
620
+ this.reverts.push(function() {
621
+ precedingTextNode.parentNode.removeChild(precedingTextNode);
622
+ firstNode.parentNode.replaceChild(matchStartNode, firstNode);
623
+ followingTextNode.parentNode.removeChild(followingTextNode);
624
+ lastNode.parentNode.replaceChild(matchEndNode, lastNode);
625
+ });
626
+
627
+ return lastNode;
628
+ }
629
+ }
630
+
631
+ };
632
+
633
+ return exposed;
634
+
635
+ }));