Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first version

  • Loading branch information...
commit 8b8445f89860d9173ec37080ffce287d3c202dc7 1 parent 84ec0f8
@vic authored
View
33 Jakefile.coffee
@@ -0,0 +1,33 @@
+#!node_modules/jake/bin/cli.js default
+
+jsp = require("uglify-js").parser
+pro = require("uglify-js").uglify
+coffee = require 'coffee-script'
+fs = require 'fs'
+path = require 'path'
+pkgJSON = JSON.parse fs.readFileSync path.join(__dirname, 'package.json'), 'utf-8'
+
+files = [
+ 'require.js'
+]
+
+new jake.PackageTask pkgJSON.name, pkgJSON.version, ->
+ @packageFiles.include files
+ @needTarGz = true
+
+new jake.NpmPublishTask pkgJSON.name, files
+
+file 'knockout-routes.js', ['index.coffee'], ->
+ fs.writeFileSync 'knockout-routes.js', coffee.compile(fs.readFileSync('index.coffee').toString())
+
+file 'knockout-routes.min.js', ['knockout-routes.js'], ->
+ orig_code = fs.readFileSync('knockout-routes.js').toString()
+ ast = jsp.parse(orig_code)
+ ast = pro.ast_mangle(ast)
+ ast = pro.ast_squeeze(ast)
+ final_code = pro.gen_code(ast)
+ fs.writeFileSync 'knockout-routes.min.js', final_code
+
+
+task 'default', ['knockout-routes.min.js']
+
View
5 README.md
@@ -1,4 +1,7 @@
knockout-routes
===============
-Routes for client-side apps powered by Knockout and History.js
+Routes for client-side apps powered by Knockout and History.js
+
+See http://vic.github.com/knockout-routes
+
View
81 index.coffee
@@ -0,0 +1,81 @@
+ko.routes = (mapping)->
+
+ named = /:\w+/g
+ splat = /\*\w+/g
+ namedOrSplat = /[:\*]\w+/
+ namedOrSplatGroup = /(:|\*)(\w+)/g
+ namedGroup = '\([^/]+\)'
+ splatGroup = '\(.*?\)'
+ suid = /[\?]&_suid=\d+/
+ sigil = ko.observable('')
+
+ Routes = ->
+ Routes.prototype = {}
+
+ current_url = ko.observable()
+ routes = new Routes
+
+ for own name, route of mapping when typeof route == 'string'
+ ((name, route)->
+ params = {}
+ names = (s.slice(1) for s in (route.match(namedOrSplatGroup) || []))
+
+ (params[m] = ko.observable()) for m in names
+
+ parts = []
+ for part, i in route.split(namedOrSplat)
+ ((part, i)->
+ parts.push(-> part)
+ parts.push(params[names[i]]) if names[i]
+ )(part, i)
+
+ groups = route.replace(named, namedGroup).replace(splat, splatGroup)
+ regexp = new RegExp "^[#\?/]*?#{groups}$"
+
+ url = ko.computed
+ write: (u, data = null, trigger = true, replace = false, title = null)->
+ u = u.replace(suid, '')
+ matches = u.match(regexp)
+ if matches
+ current_url url()
+ unless data
+ data = {}
+ data[names[i]] = value for value, i in matches.slice(1)
+ params[k](v) for own k, v of data when params[k]
+ state(data, trigger, replace, title)
+ read: -> sigil() + (p() for p in parts).join('')
+
+ state = (->
+ json = ko.observable(false)
+ ko.computed
+ write: (d, trigger = true, replace = false, title = null)->
+ json d
+ params[k](v) for own k, v of d when params[k]
+ if trigger
+ if replace
+ History.replaceState d, title, url()
+ else
+ History.pushState d, title, url()
+ read: -> json()
+ )()
+
+ state.url = url
+ state.param = params
+ state.active = ko.computed read: -> url() == current_url()
+
+ routes[name] = state
+ )(name, route)
+
+ Routes.prototype.ready = (_sigil)->
+ sigil _sigil if _sigil
+ state = History.getState()
+ url = state.hash
+ r.url(url, false, false) for own n, r of routes
+
+ History.Adapter.bind window, 'statechange', ->
+ state = History.getState()
+ url = state.hash
+ r.url(url, state.data) for own n, r of routes
+
+ routes
+
View
182 knockout-routes.js
@@ -0,0 +1,182 @@
+(function() {
+ var __hasProp = {}.hasOwnProperty;
+
+ ko.routes = function(mapping) {
+ var Routes, current_url, name, named, namedGroup, namedOrSplat, namedOrSplatGroup, route, routes, sigil, splat, splatGroup, suid;
+ named = /:\w+/g;
+ splat = /\*\w+/g;
+ namedOrSplat = /[:\*]\w+/;
+ namedOrSplatGroup = /(:|\*)(\w+)/g;
+ namedGroup = '\([^/]+\)';
+ splatGroup = '\(.*?\)';
+ suid = /[\?]&_suid=\d+/;
+ sigil = ko.observable('');
+ Routes = function() {};
+ Routes.prototype = {};
+ current_url = ko.observable();
+ routes = new Routes;
+ for (name in mapping) {
+ if (!__hasProp.call(mapping, name)) continue;
+ route = mapping[name];
+ if (typeof route === 'string') {
+ (function(name, route) {
+ var groups, i, m, names, params, part, parts, regexp, s, state, url, _fn, _i, _j, _len, _len1, _ref;
+ params = {};
+ names = (function() {
+ var _i, _len, _ref, _results;
+ _ref = route.match(namedOrSplatGroup) || [];
+ _results = [];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ s = _ref[_i];
+ _results.push(s.slice(1));
+ }
+ return _results;
+ })();
+ for (_i = 0, _len = names.length; _i < _len; _i++) {
+ m = names[_i];
+ params[m] = ko.observable();
+ }
+ parts = [];
+ _ref = route.split(namedOrSplat);
+ _fn = function(part, i) {
+ parts.push(function() {
+ return part;
+ });
+ if (names[i]) {
+ return parts.push(params[names[i]]);
+ }
+ };
+ for (i = _j = 0, _len1 = _ref.length; _j < _len1; i = ++_j) {
+ part = _ref[i];
+ _fn(part, i);
+ }
+ groups = route.replace(named, namedGroup).replace(splat, splatGroup);
+ regexp = new RegExp("^[#\?/]*?" + groups + "$");
+ url = ko.computed({
+ write: function(u, data, trigger, replace, title) {
+ var k, matches, v, value, _k, _len2, _ref1;
+ if (data == null) {
+ data = null;
+ }
+ if (trigger == null) {
+ trigger = true;
+ }
+ if (replace == null) {
+ replace = false;
+ }
+ if (title == null) {
+ title = null;
+ }
+ u = u.replace(suid, '');
+ matches = u.match(regexp);
+ if (matches) {
+ current_url(url());
+ if (!data) {
+ data = {};
+ _ref1 = matches.slice(1);
+ for (i = _k = 0, _len2 = _ref1.length; _k < _len2; i = ++_k) {
+ value = _ref1[i];
+ data[names[i]] = value;
+ }
+ }
+ for (k in data) {
+ if (!__hasProp.call(data, k)) continue;
+ v = data[k];
+ if (params[k]) {
+ params[k](v);
+ }
+ }
+ return state(data, trigger, replace, title);
+ }
+ },
+ read: function() {
+ var p;
+ return sigil() + ((function() {
+ var _k, _len2, _results;
+ _results = [];
+ for (_k = 0, _len2 = parts.length; _k < _len2; _k++) {
+ p = parts[_k];
+ _results.push(p());
+ }
+ return _results;
+ })()).join('');
+ }
+ });
+ state = (function() {
+ var json;
+ json = ko.observable(false);
+ return ko.computed({
+ write: function(d, trigger, replace, title) {
+ var k, v;
+ if (trigger == null) {
+ trigger = true;
+ }
+ if (replace == null) {
+ replace = false;
+ }
+ if (title == null) {
+ title = null;
+ }
+ json(d);
+ for (k in d) {
+ if (!__hasProp.call(d, k)) continue;
+ v = d[k];
+ if (params[k]) {
+ params[k](v);
+ }
+ }
+ if (trigger) {
+ if (replace) {
+ return History.replaceState(d, title, url());
+ } else {
+ return History.pushState(d, title, url());
+ }
+ }
+ },
+ read: function() {
+ return json();
+ }
+ });
+ })();
+ state.url = url;
+ state.param = params;
+ state.active = ko.computed({
+ read: function() {
+ return url() === current_url();
+ }
+ });
+ return routes[name] = state;
+ })(name, route);
+ }
+ }
+ Routes.prototype.ready = function(_sigil) {
+ var n, r, state, url, _results;
+ if (_sigil) {
+ sigil(_sigil);
+ }
+ state = History.getState();
+ url = state.hash;
+ _results = [];
+ for (n in routes) {
+ if (!__hasProp.call(routes, n)) continue;
+ r = routes[n];
+ _results.push(r.url(url, false, false));
+ }
+ return _results;
+ };
+ History.Adapter.bind(window, 'statechange', function() {
+ var n, r, state, url, _results;
+ state = History.getState();
+ url = state.hash;
+ _results = [];
+ for (n in routes) {
+ if (!__hasProp.call(routes, n)) continue;
+ r = routes[n];
+ _results.push(r.url(url, state.data));
+ }
+ return _results;
+ });
+ return routes;
+ };
+
+}).call(this);
View
1  knockout-routes.min.js
@@ -0,0 +1 @@
+(function(){var e={}.hasOwnProperty;ko.routes=function(t){var n,r,i,s,o,u,a,f,l,c,h,p,d;s=/:\w+/g,h=/\*\w+/g,u=/[:\*]\w+/,a=/(:|\*)(\w+)/g,o="([^/]+)",p="(.*?)",d=/[\?]&_suid=\d+/,c=ko.observable(""),n=function(){},n.prototype={},r=ko.observable(),l=new n;for(i in t){if(!e.call(t,i))continue;f=t[i],typeof f=="string"&&function(t,n){var i,f,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A;g={},m=function(){var e,t,r,i;r=n.match(a)||[],i=[];for(e=0,t=r.length;e<t;e++)E=r[e],i.push(E.slice(1));return i}();for(N=0,k=m.length;N<k;N++)v=m[N],g[v]=ko.observable();b=[],A=n.split(u),T=function(e,t){b.push(function(){return e});if(m[t])return b.push(g[m[t]])};for(f=C=0,L=A.length;C<L;f=++C)y=A[f],T(y,f);return i=n.replace(s,o).replace(h,p),w=new RegExp("^[#?/]*?"+i+"$"),x=ko.computed({write:function(t,n,i,s,o){var u,a,l,c,h,p,v;n==null&&(n=null),i==null&&(i=!0),s==null&&(s=!1),o==null&&(o=null),t=t.replace(d,""),a=t.match(w);if(a){r(x());if(!n){n={},v=a.slice(1);for(f=h=0,p=v.length;h<p;f=++h)c=v[f],n[m[f]]=c}for(u in n){if(!e.call(n,u))continue;l=n[u],g[u]&&g[u](l)}return S(n,i,s,o)}},read:function(){var e;return c()+function(){var t,n,r;r=[];for(t=0,n=b.length;t<n;t++)e=b[t],r.push(e());return r}().join("")}}),S=function(){var t;return t=ko.observable(!1),ko.computed({write:function(n,r,i,s){var o,u;r==null&&(r=!0),i==null&&(i=!1),s==null&&(s=null),t(n);for(o in n){if(!e.call(n,o))continue;u=n[o],g[o]&&g[o](u)}if(r)return i?History.replaceState(n,s,x()):History.pushState(n,s,x())},read:function(){return t()}})}(),S.url=x,S.param=g,S.active=ko.computed({read:function(){return x()===r()}}),l[t]=S}(i,f)}return n.prototype.ready=function(t){var n,r,i,s,o;t&&c(t),i=History.getState(),s=i.hash,o=[];for(n in l){if(!e.call(l,n))continue;r=l[n],o.push(r.url(s,!1,!1))}return o},History.Adapter.bind(window,"statechange",function(){var t,n,r,i,s;r=History.getState(),i=r.hash,s=[];for(t in l){if(!e.call(l,t))continue;n=l[t],s.push(n.url(i,r.data))}return s}),l}}).call(this)
View
10 package.json
@@ -0,0 +1,10 @@
+{
+ "name": "knockout-routes.js",
+ "description": "Routes for client-side apps powered by Knockout and History.js",
+ "version": "0.0.1",
+ "dependencies": {
+ "coffee-script": "*",
+ "uglify-js": "*",
+ "jake": "*"
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.