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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +3 -0
- data/lib/pagejs_rails/version.rb +3 -0
- data/lib/pagejs_rails.rb +11 -0
- data/pagejs_rails.gemspec +23 -0
- data/vendor/assets/javascripts/page.js +772 -0
- metadata +83 -0
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
data/Gemfile
ADDED
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
data/lib/pagejs_rails.rb
ADDED
@@ -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:
|