pagejs_rails 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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: