retreaverjs-rails 0.2.6 → 0.2.7

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: 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
+ }));