pagejs_rails 0.0.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36d185f4eb0cc40aaa6f1ce3e214257cc91f921a
4
+ data.tar.gz: 9135a30d190f76011498fb0470fda3340d6c92f8
5
+ SHA512:
6
+ metadata.gz: 04ca5888e05d9f362856cea7c97abc5f528db901e614c63d909ea9c723ab2c267fef3faffe3e2b49d6a628e44056457ffdeb4f44b521a04808740ca7278a6f5b
7
+ data.tar.gz: a18192f9def8e5a75959c0833a4a7b4d9013e0de5088c83c284c434e7b67a0cddb26a31c34ccea336a2357ec8f3d8cacb567704d1dc94481692508949f4062cc
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pagejs_rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Guinsly Mondésir
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # PagejsRails
2
+
3
+ A Rails library implementation for the [visionmedia/page.js](http://visionmedia.github.io/page.js/) -- The Micro client-side router inspired by the Express router. [Rails Demo of page.js](https://github.com/guinslym/pagejs_rails_demo)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'pagejs_rails'
11
+ ```
12
+ config/ini
13
+ Rails.application.config.assets.precompile += %w( page.js )
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+
20
+ ## Usage
21
+ app/assets/javascript/application.js
22
+
23
+ //= require page
24
+
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it ( https://github.com/[my-github-username]/pagejs_rails/fork )
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+
@@ -0,0 +1,3 @@
1
+ module PagejsRails
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,11 @@
1
+ require "pagejs_rails/version"
2
+
3
+ module PagejsRails
4
+ module Rails
5
+ if defined?(::Rails) and Gem::Requirement.new('>= 3.1').satisfied_by?(Gem::Version.new ::Rails.version)
6
+ class Rails::Engine < ::Rails::Engine
7
+ # this class enables the asset pipeline
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pagejs_rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pagejs_rails"
8
+ spec.version = PagejsRails::VERSION
9
+ spec.authors = ["Guinsly Mondesir"]
10
+ spec.email = ["agmond@gmx.com.br"]
11
+ spec.summary = %q{A Rails library implementation for the visionmedia/page.js}
12
+ spec.description = %q{A Rails library implementation for the visionmedia/page.js -- The Micro client-side router inspired by the Express router.}
13
+ spec.homepage = "https://github.com/guinslym/pagejs_rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,772 @@
1
+ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.page=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ /* globals require, module */
3
+
4
+ 'use strict';
5
+
6
+ /**
7
+ * Module dependencies.
8
+ */
9
+
10
+ var pathtoRegexp = require('path-to-regexp');
11
+
12
+ /**
13
+ * Module exports.
14
+ */
15
+
16
+ module.exports = page;
17
+
18
+ /**
19
+ * To work properly with the URL
20
+ * history.location generated polyfill in https://github.com/devote/HTML5-History-API
21
+ */
22
+
23
+ var location = ('undefined' !== typeof window) && (window.history.location || window.location);
24
+
25
+ /**
26
+ * Perform initial dispatch.
27
+ */
28
+
29
+ var dispatch = true;
30
+
31
+ /**
32
+ * Decode URL components (query string, pathname, hash).
33
+ * Accommodates both regular percent encoding and x-www-form-urlencoded format.
34
+ */
35
+ var decodeURLComponents = true;
36
+
37
+ /**
38
+ * Base path.
39
+ */
40
+
41
+ var base = '';
42
+
43
+ /**
44
+ * Running flag.
45
+ */
46
+
47
+ var running;
48
+
49
+ /**
50
+ * HashBang option
51
+ */
52
+
53
+ var hashbang = false;
54
+
55
+ /**
56
+ * Previous context, for capturing
57
+ * page exit events.
58
+ */
59
+
60
+ var prevContext;
61
+
62
+ /**
63
+ * Register `path` with callback `fn()`,
64
+ * or route `path`, or redirection,
65
+ * or `page.start()`.
66
+ *
67
+ * page(fn);
68
+ * page('*', fn);
69
+ * page('/user/:id', load, user);
70
+ * page('/user/' + user.id, { some: 'thing' });
71
+ * page('/user/' + user.id);
72
+ * page('/from', '/to')
73
+ * page();
74
+ *
75
+ * @param {String|Function} path
76
+ * @param {Function} fn...
77
+ * @api public
78
+ */
79
+
80
+ function page(path, fn) {
81
+ // <callback>
82
+ if ('function' === typeof path) {
83
+ return page('*', path);
84
+ }
85
+
86
+ // route <path> to <callback ...>
87
+ if ('function' === typeof fn) {
88
+ var route = new Route(path);
89
+ for (var i = 1; i < arguments.length; ++i) {
90
+ page.callbacks.push(route.middleware(arguments[i]));
91
+ }
92
+ // show <path> with [state]
93
+ } else if ('string' === typeof path) {
94
+ page['string' === typeof fn ? 'redirect' : 'show'](path, fn);
95
+ // start [options]
96
+ } else {
97
+ page.start(path);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Callback functions.
103
+ */
104
+
105
+ page.callbacks = [];
106
+ page.exits = [];
107
+
108
+ /**
109
+ * Current path being processed
110
+ * @type {String}
111
+ */
112
+ page.current = '';
113
+
114
+ /**
115
+ * Number of pages navigated to.
116
+ * @type {number}
117
+ *
118
+ * page.len == 0;
119
+ * page('/login');
120
+ * page.len == 1;
121
+ */
122
+
123
+ page.len = 0;
124
+
125
+ /**
126
+ * Get or set basepath to `path`.
127
+ *
128
+ * @param {String} path
129
+ * @api public
130
+ */
131
+
132
+ page.base = function(path) {
133
+ if (0 === arguments.length) return base;
134
+ base = path;
135
+ };
136
+
137
+ /**
138
+ * Bind with the given `options`.
139
+ *
140
+ * Options:
141
+ *
142
+ * - `click` bind to click events [true]
143
+ * - `popstate` bind to popstate [true]
144
+ * - `dispatch` perform initial dispatch [true]
145
+ *
146
+ * @param {Object} options
147
+ * @api public
148
+ */
149
+
150
+ page.start = function(options) {
151
+ options = options || {};
152
+ if (running) return;
153
+ running = true;
154
+ if (false === options.dispatch) dispatch = false;
155
+ if (false === options.decodeURLComponents) decodeURLComponents = false;
156
+ if (false !== options.popstate) window.addEventListener('popstate', onpopstate, false);
157
+ if (false !== options.click) window.addEventListener('click', onclick, false);
158
+ if (true === options.hashbang) hashbang = true;
159
+ if (!dispatch) return;
160
+ var url = (hashbang && ~location.hash.indexOf('#!')) ? location.hash.substr(2) + location.search : location.pathname + location.search + location.hash;
161
+ page.replace(url, null, true, dispatch);
162
+ };
163
+
164
+ /**
165
+ * Unbind click and popstate event handlers.
166
+ *
167
+ * @api public
168
+ */
169
+
170
+ page.stop = function() {
171
+ if (!running) return;
172
+ page.current = '';
173
+ page.len = 0;
174
+ running = false;
175
+ window.removeEventListener('click', onclick, false);
176
+ window.removeEventListener('popstate', onpopstate, false);
177
+ };
178
+
179
+ /**
180
+ * Show `path` with optional `state` object.
181
+ *
182
+ * @param {String} path
183
+ * @param {Object} state
184
+ * @param {Boolean} dispatch
185
+ * @return {Context}
186
+ * @api public
187
+ */
188
+
189
+ page.show = function(path, state, dispatch) {
190
+ var ctx = new Context(path, state);
191
+ page.current = ctx.path;
192
+ if (false !== dispatch) page.dispatch(ctx);
193
+ if (false !== ctx.handled) ctx.pushState();
194
+ return ctx;
195
+ };
196
+
197
+ /**
198
+ * Goes back in the history
199
+ * Back should always let the current route push state and then go back.
200
+ *
201
+ * @param {String} path - fallback path to go back if no more history exists, if undefined defaults to page.base
202
+ * @param {Object} [state]
203
+ * @api public
204
+ */
205
+
206
+ page.back = function(path, state) {
207
+ if (page.len > 0) {
208
+ // this may need more testing to see if all browsers
209
+ // wait for the next tick to go back in history
210
+ history.back();
211
+ page.len--;
212
+ } else if (path) {
213
+ setTimeout(function() {
214
+ page.show(path, state);
215
+ });
216
+ }else{
217
+ setTimeout(function() {
218
+ page.show(base, state);
219
+ });
220
+ }
221
+ };
222
+
223
+
224
+ /**
225
+ * Register route to redirect from one path to other
226
+ * or just redirect to another route
227
+ *
228
+ * @param {String} from - if param 'to' is undefined redirects to 'from'
229
+ * @param {String} [to]
230
+ * @api public
231
+ */
232
+ page.redirect = function(from, to) {
233
+ // Define route from a path to another
234
+ if ('string' === typeof from && 'string' === typeof to) {
235
+ page(from, function(e) {
236
+ setTimeout(function() {
237
+ page.replace(to);
238
+ }, 0);
239
+ });
240
+ }
241
+
242
+ // Wait for the push state and replace it with another
243
+ if ('string' === typeof from && 'undefined' === typeof to) {
244
+ setTimeout(function() {
245
+ page.replace(from);
246
+ }, 0);
247
+ }
248
+ };
249
+
250
+ /**
251
+ * Replace `path` with optional `state` object.
252
+ *
253
+ * @param {String} path
254
+ * @param {Object} state
255
+ * @return {Context}
256
+ * @api public
257
+ */
258
+
259
+
260
+ page.replace = function(path, state, init, dispatch) {
261
+ var ctx = new Context(path, state);
262
+ page.current = ctx.path;
263
+ ctx.init = init;
264
+ ctx.save(); // save before dispatching, which may redirect
265
+ if (false !== dispatch) page.dispatch(ctx);
266
+ return ctx;
267
+ };
268
+
269
+ /**
270
+ * Dispatch the given `ctx`.
271
+ *
272
+ * @param {Object} ctx
273
+ * @api private
274
+ */
275
+
276
+ page.dispatch = function(ctx) {
277
+ var prev = prevContext,
278
+ i = 0,
279
+ j = 0;
280
+
281
+ prevContext = ctx;
282
+
283
+ function nextExit() {
284
+ var fn = page.exits[j++];
285
+ if (!fn) return nextEnter();
286
+ fn(prev, nextExit);
287
+ }
288
+
289
+ function nextEnter() {
290
+ var fn = page.callbacks[i++];
291
+
292
+ if (ctx.path !== page.current) {
293
+ ctx.handled = false;
294
+ return;
295
+ }
296
+ if (!fn) return unhandled(ctx);
297
+ fn(ctx, nextEnter);
298
+ }
299
+
300
+ if (prev) {
301
+ nextExit();
302
+ } else {
303
+ nextEnter();
304
+ }
305
+ };
306
+
307
+ /**
308
+ * Unhandled `ctx`. When it's not the initial
309
+ * popstate then redirect. If you wish to handle
310
+ * 404s on your own use `page('*', callback)`.
311
+ *
312
+ * @param {Context} ctx
313
+ * @api private
314
+ */
315
+
316
+ function unhandled(ctx) {
317
+ if (ctx.handled) return;
318
+ var current;
319
+
320
+ if (hashbang) {
321
+ current = base + location.hash.replace('#!', '');
322
+ } else {
323
+ current = location.pathname + location.search;
324
+ }
325
+
326
+ if (current === ctx.canonicalPath) return;
327
+ page.stop();
328
+ ctx.handled = false;
329
+ location.href = ctx.canonicalPath;
330
+ }
331
+
332
+ /**
333
+ * Register an exit route on `path` with
334
+ * callback `fn()`, which will be called
335
+ * on the previous context when a new
336
+ * page is visited.
337
+ */
338
+ page.exit = function(path, fn) {
339
+ if (typeof path === 'function') {
340
+ return page.exit('*', path);
341
+ }
342
+
343
+ var route = new Route(path);
344
+ for (var i = 1; i < arguments.length; ++i) {
345
+ page.exits.push(route.middleware(arguments[i]));
346
+ }
347
+ };
348
+
349
+ /**
350
+ * Remove URL encoding from the given `str`.
351
+ * Accommodates whitespace in both x-www-form-urlencoded
352
+ * and regular percent-encoded form.
353
+ *
354
+ * @param {str} URL component to decode
355
+ */
356
+ function decodeURLEncodedURIComponent(val) {
357
+ if (typeof val !== 'string') { return val; }
358
+ return decodeURLComponents ? decodeURIComponent(val.replace(/\+/g, ' ')) : val;
359
+ }
360
+
361
+ /**
362
+ * Initialize a new "request" `Context`
363
+ * with the given `path` and optional initial `state`.
364
+ *
365
+ * @param {String} path
366
+ * @param {Object} state
367
+ * @api public
368
+ */
369
+
370
+ function Context(path, state) {
371
+ if ('/' === path[0] && 0 !== path.indexOf(base)) path = base + (hashbang ? '#!' : '') + path;
372
+ var i = path.indexOf('?');
373
+
374
+ this.canonicalPath = path;
375
+ this.path = path.replace(base, '') || '/';
376
+ if (hashbang) this.path = this.path.replace('#!', '') || '/';
377
+
378
+ this.title = document.title;
379
+ this.state = state || {};
380
+ this.state.path = path;
381
+ this.querystring = ~i ? decodeURLEncodedURIComponent(path.slice(i + 1)) : '';
382
+ this.pathname = decodeURLEncodedURIComponent(~i ? path.slice(0, i) : path);
383
+ this.params = {};
384
+
385
+ // fragment
386
+ this.hash = '';
387
+ if (!hashbang) {
388
+ if (!~this.path.indexOf('#')) return;
389
+ var parts = this.path.split('#');
390
+ this.path = parts[0];
391
+ this.hash = decodeURLEncodedURIComponent(parts[1]) || '';
392
+ this.querystring = this.querystring.split('#')[0];
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Expose `Context`.
398
+ */
399
+
400
+ page.Context = Context;
401
+
402
+ /**
403
+ * Push state.
404
+ *
405
+ * @api private
406
+ */
407
+
408
+ Context.prototype.pushState = function() {
409
+ page.len++;
410
+ history.pushState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
411
+ };
412
+
413
+ /**
414
+ * Save the context state.
415
+ *
416
+ * @api public
417
+ */
418
+
419
+ Context.prototype.save = function() {
420
+ history.replaceState(this.state, this.title, hashbang && this.path !== '/' ? '#!' + this.path : this.canonicalPath);
421
+ };
422
+
423
+ /**
424
+ * Initialize `Route` with the given HTTP `path`,
425
+ * and an array of `callbacks` and `options`.
426
+ *
427
+ * Options:
428
+ *
429
+ * - `sensitive` enable case-sensitive routes
430
+ * - `strict` enable strict matching for trailing slashes
431
+ *
432
+ * @param {String} path
433
+ * @param {Object} options.
434
+ * @api private
435
+ */
436
+
437
+ function Route(path, options) {
438
+ options = options || {};
439
+ this.path = (path === '*') ? '(.*)' : path;
440
+ this.method = 'GET';
441
+ this.regexp = pathtoRegexp(this.path,
442
+ this.keys = [],
443
+ options.sensitive,
444
+ options.strict);
445
+ }
446
+
447
+ /**
448
+ * Expose `Route`.
449
+ */
450
+
451
+ page.Route = Route;
452
+
453
+ /**
454
+ * Return route middleware with
455
+ * the given callback `fn()`.
456
+ *
457
+ * @param {Function} fn
458
+ * @return {Function}
459
+ * @api public
460
+ */
461
+
462
+ Route.prototype.middleware = function(fn) {
463
+ var self = this;
464
+ return function(ctx, next) {
465
+ if (self.match(ctx.path, ctx.params)) return fn(ctx, next);
466
+ next();
467
+ };
468
+ };
469
+
470
+ /**
471
+ * Check if this route matches `path`, if so
472
+ * populate `params`.
473
+ *
474
+ * @param {String} path
475
+ * @param {Object} params
476
+ * @return {Boolean}
477
+ * @api private
478
+ */
479
+
480
+ Route.prototype.match = function(path, params) {
481
+ var keys = this.keys,
482
+ qsIndex = path.indexOf('?'),
483
+ pathname = ~qsIndex ? path.slice(0, qsIndex) : path,
484
+ m = this.regexp.exec(decodeURIComponent(pathname));
485
+
486
+ if (!m) return false;
487
+
488
+ for (var i = 1, len = m.length; i < len; ++i) {
489
+ var key = keys[i - 1];
490
+ var val = decodeURLEncodedURIComponent(m[i]);
491
+ if (val !== undefined || !(hasOwnProperty.call(params, key.name))) {
492
+ params[key.name] = val;
493
+ }
494
+ }
495
+
496
+ return true;
497
+ };
498
+
499
+ /**
500
+ * Handle "populate" events.
501
+ */
502
+
503
+ function onpopstate(e) {
504
+ if (e.state) {
505
+ var path = e.state.path;
506
+ page.replace(path, e.state);
507
+ } else {
508
+ page.show(location.pathname + location.hash);
509
+ }
510
+ }
511
+
512
+ /**
513
+ * Handle "click" events.
514
+ */
515
+
516
+ function onclick(e) {
517
+
518
+ if (1 !== which(e)) return;
519
+
520
+ if (e.metaKey || e.ctrlKey || e.shiftKey) return;
521
+ if (e.defaultPrevented) return;
522
+
523
+
524
+
525
+ // ensure link
526
+ var el = e.target;
527
+ while (el && 'A' !== el.nodeName) el = el.parentNode;
528
+ if (!el || 'A' !== el.nodeName) return;
529
+
530
+
531
+
532
+ // Ignore if tag has
533
+ // 1. "download" attribute
534
+ // 2. rel="external" attribute
535
+ if (el.getAttribute('download') || el.getAttribute('rel') === 'external') return;
536
+
537
+ // ensure non-hash for the same path
538
+ var link = el.getAttribute('href');
539
+ if (!hashbang && el.pathname === location.pathname && (el.hash || '#' === link)) return;
540
+
541
+
542
+
543
+ // Check for mailto: in the href
544
+ if (link && link.indexOf('mailto:') > -1) return;
545
+
546
+ // check target
547
+ if (el.target) return;
548
+
549
+ // x-origin
550
+ if (!sameOrigin(el.href)) return;
551
+
552
+
553
+
554
+ // rebuild path
555
+ var path = el.pathname + el.search + (el.hash || '');
556
+
557
+ // same page
558
+ var orig = path;
559
+
560
+ path = path.replace(base, '');
561
+ if (hashbang) path = path.replace('#!', '');
562
+
563
+
564
+
565
+ if (base && orig === path) return;
566
+
567
+ e.preventDefault();
568
+ page.show(orig);
569
+ }
570
+
571
+ /**
572
+ * Event button.
573
+ */
574
+
575
+ function which(e) {
576
+ e = e || window.event;
577
+ return null === e.which ? e.button : e.which;
578
+ }
579
+
580
+ /**
581
+ * Check if `href` is the same origin.
582
+ */
583
+
584
+ function sameOrigin(href) {
585
+ var origin = location.protocol + '//' + location.hostname;
586
+ if (location.port) origin += ':' + location.port;
587
+ return (href && (0 === href.indexOf(origin)));
588
+ }
589
+
590
+ page.sameOrigin = sameOrigin;
591
+
592
+ },{"path-to-regexp":2}],2:[function(require,module,exports){
593
+ var isArray = require('isarray');
594
+
595
+ /**
596
+ * Expose `pathtoRegexp`.
597
+ */
598
+ module.exports = pathtoRegexp;
599
+
600
+ /**
601
+ * The main path matching regexp utility.
602
+ *
603
+ * @type {RegExp}
604
+ */
605
+ var PATH_REGEXP = new RegExp([
606
+ // Match already escaped characters that would otherwise incorrectly appear
607
+ // in future matches. This allows the user to escape special characters that
608
+ // shouldn't be transformed.
609
+ '(\\\\.)',
610
+ // Match Express-style parameters and un-named parameters with a prefix
611
+ // and optional suffixes. Matches appear as:
612
+ //
613
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
614
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
615
+ '([\\/.])?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^)])*)\\))?|\\(((?:\\\\.|[^)])*)\\))([+*?])?',
616
+ // Match regexp special characters that should always be escaped.
617
+ '([.+*?=^!:${}()[\\]|\\/])'
618
+ ].join('|'), 'g');
619
+
620
+ /**
621
+ * Escape the capturing group by escaping special characters and meaning.
622
+ *
623
+ * @param {String} group
624
+ * @return {String}
625
+ */
626
+ function escapeGroup (group) {
627
+ return group.replace(/([=!:$\/()])/g, '\\$1');
628
+ }
629
+
630
+ /**
631
+ * Attach the keys as a property of the regexp.
632
+ *
633
+ * @param {RegExp} re
634
+ * @param {Array} keys
635
+ * @return {RegExp}
636
+ */
637
+ function attachKeys (re, keys) {
638
+ re.keys = keys;
639
+
640
+ return re;
641
+ };
642
+
643
+ /**
644
+ * Normalize the given path string, returning a regular expression.
645
+ *
646
+ * An empty array should be passed in, which will contain the placeholder key
647
+ * names. For example `/user/:id` will then contain `["id"]`.
648
+ *
649
+ * @param {(String|RegExp|Array)} path
650
+ * @param {Array} keys
651
+ * @param {Object} options
652
+ * @return {RegExp}
653
+ */
654
+ function pathtoRegexp (path, keys, options) {
655
+ if (!isArray(keys)) {
656
+ options = keys;
657
+ keys = null;
658
+ }
659
+
660
+ keys = keys || [];
661
+ options = options || {};
662
+
663
+ var strict = options.strict;
664
+ var end = options.end !== false;
665
+ var flags = options.sensitive ? '' : 'i';
666
+ var index = 0;
667
+
668
+ if (path instanceof RegExp) {
669
+ // Match all capturing groups of a regexp.
670
+ var groups = path.source.match(/\((?!\?)/g);
671
+
672
+ // Map all the matches to their numeric indexes and push into the keys.
673
+ if (groups) {
674
+ for (var i = 0; i < groups.length; i++) {
675
+ keys.push({
676
+ name: i,
677
+ delimiter: null,
678
+ optional: false,
679
+ repeat: false
680
+ });
681
+ }
682
+ }
683
+
684
+ // Return the source back to the user.
685
+ return attachKeys(path, keys);
686
+ }
687
+
688
+ // Map array parts into regexps and return their source. We also pass
689
+ // the same keys and options instance into every generation to get
690
+ // consistent matching groups before we join the sources together.
691
+ if (isArray(path)) {
692
+ var parts = [];
693
+
694
+ for (var i = 0; i < path.length; i++) {
695
+ parts.push(pathtoRegexp(path[i], keys, options).source);
696
+ }
697
+ // Generate a new regexp instance by joining all the parts together.
698
+ return attachKeys(new RegExp('(?:' + parts.join('|') + ')', flags), keys);
699
+ }
700
+
701
+ // Alter the path string into a usable regexp.
702
+ path = path.replace(PATH_REGEXP, function (match, escaped, prefix, key, capture, group, suffix, escape) {
703
+ // Avoiding re-escaping escaped characters.
704
+ if (escaped) {
705
+ return escaped;
706
+ }
707
+
708
+ // Escape regexp special characters.
709
+ if (escape) {
710
+ return '\\' + escape;
711
+ }
712
+
713
+ var repeat = suffix === '+' || suffix === '*';
714
+ var optional = suffix === '?' || suffix === '*';
715
+
716
+ keys.push({
717
+ name: key || index++,
718
+ delimiter: prefix || '/',
719
+ optional: optional,
720
+ repeat: repeat
721
+ });
722
+
723
+ // Escape the prefix character.
724
+ prefix = prefix ? '\\' + prefix : '';
725
+
726
+ // Match using the custom capturing group, or fallback to capturing
727
+ // everything up to the next slash (or next period if the param was
728
+ // prefixed with a period).
729
+ capture = escapeGroup(capture || group || '[^' + (prefix || '\\/') + ']+?');
730
+
731
+ // Allow parameters to be repeated more than once.
732
+ if (repeat) {
733
+ capture = capture + '(?:' + prefix + capture + ')*';
734
+ }
735
+
736
+ // Allow a parameter to be optional.
737
+ if (optional) {
738
+ return '(?:' + prefix + '(' + capture + '))?';
739
+ }
740
+
741
+ // Basic parameter support.
742
+ return prefix + '(' + capture + ')';
743
+ });
744
+
745
+ // Check whether the path ends in a slash as it alters some match behaviour.
746
+ var endsWithSlash = path[path.length - 1] === '/';
747
+
748
+ // In non-strict mode we allow an optional trailing slash in the match. If
749
+ // the path to match already ended with a slash, we need to remove it for
750
+ // consistency. The slash is only valid at the very end of a path match, not
751
+ // anywhere in the middle. This is important for non-ending mode, otherwise
752
+ // "/test/" will match "/test//route".
753
+ if (!strict) {
754
+ path = (endsWithSlash ? path.slice(0, -2) : path) + '(?:\\/(?=$))?';
755
+ }
756
+
757
+ // In non-ending mode, we need prompt the capturing groups to match as much
758
+ // as possible by using a positive lookahead for the end or next path segment.
759
+ if (!end) {
760
+ path += strict && endsWithSlash ? '' : '(?=\\/|$)';
761
+ }
762
+
763
+ return attachKeys(new RegExp('^' + path + (end ? '$' : ''), flags), keys);
764
+ };
765
+
766
+ },{"isarray":3}],3:[function(require,module,exports){
767
+ module.exports = Array.isArray || function (arr) {
768
+ return Object.prototype.toString.call(arr) == '[object Array]';
769
+ };
770
+
771
+ },{}]},{},[1])(1)
772
+ });
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pagejs_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Guinsly Mondesir
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: A Rails library implementation for the visionmedia/page.js -- The Micro
42
+ client-side router inspired by the Express router.
43
+ email:
44
+ - agmond@gmx.com.br
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - lib/pagejs_rails.rb
55
+ - lib/pagejs_rails/version.rb
56
+ - pagejs_rails.gemspec
57
+ - vendor/assets/javascripts/page.js
58
+ homepage: https://github.com/guinslym/pagejs_rails
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.2.2
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: A Rails library implementation for the visionmedia/page.js
82
+ test_files: []
83
+ has_rdoc: