Coder Social home page Coder Social logo

director's Introduction

Framework components for node.js and the browser

Example HTTP Server:

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.http);

app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

app.start(8080);

Example HTTPS Server:

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.http, {
  https: {
    cert: 'path/to/cert.pem',
    key: 'path/to/key.pem',
    ca: 'path/to/ca.pem'
  }
});

app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

app.start(8080);

Example CLI Application:

// example.js

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  dir: __dirname,
  usage: [
    'This is a basic flatiron cli application example!',
    '',
    'hello - say hello to somebody.'
  ]
});

app.cmd('hello', function () {
  app.prompt.get('name', function (err, result) {
    app.log.info('hello '+result.name+'!');
  })
})

app.start();

Run It:

% node example.js hello
prompt: name: world
info:   hello world!

Installation

Installing NPM (Node Package Manager)

  curl http://npmjs.org/install.sh | sh

Installing Flatiron

  [sudo] npm install flatiron

Installing Union (Required for flatiron.plugins.http)

  npm install union

Usage:

Start With flatiron.app:

flatiron.app is a broadway injection container. To be brief, what it does is allow plugins to modify the app object directly:

var flatiron = require('flatiron'),
    app = flatiron.app;

var hello = {
  attach: function (options) {
    this.hello = options.message || 'Why hello!';
  }
};

app.use(hello, {
  message: "Hi! How are you?"
});

// Will print, "Hi! How are you?"
console.log(app.hello);

Virtually all additional functionality in flatiron comes from broadway plugins, such as flatiron.plugins.http and flatiron.plugins.cli.

app.config

flatiron.app comes with a config plugin pre-loaded, which adds configuration management courtesy nconf. app.config has the same api as the nconf object.

The literal store is configured by default. If you want to use different stores you can easily attach them to the app.config instance.

// add the `env` store to the config
app.config.use('env');

// add the `file` store the the config
app.config.use('file', { file: 'path/to/config.json' });

// or using an alternate syntax
app.config.env().file({ file: 'path/to/config.json' });

// and removing stores
app.config.remove('literal');

app.log

flatiron.app will also load a log plugin during the init phase, which attaches a winston container to app.log. This logger is configured by combining the app.options.log property with the configuration retrieved from app.config.get('log').

Create An HTTP Server with flatiron.plugins.http(options):

This plugin adds http serving functionality to your flatiron app by attaching the following properties and methods:

Define Routes with app.router:

This is a director router configured to route http requests after the middlewares in app.http.before are applied. Example routes include:

// GET /
app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

// POST to /
app.router.post('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.write('Hey, you posted some cool data!\n');
  this.res.end(util.inspect(this.req.body, true, 2, true) + '\n');
});

// Parameterized routes
app.router.get('/sandwich/:type', function (type) {
  if (~['bacon', 'burger'].indexOf(type)) {
    this.res.writeHead(200, { 'Content-Type': 'text/plain' });
    this.res.end('Serving ' + type + ' sandwich!\n');
  }
  else {
    this.res.writeHead(404, { 'Content-Type': 'text/plain' });
    this.res.end('No such sandwich, sorry!\n');
  }
});

app.router can also route against regular expressions and more! To learn more about director's advanced functionality, visit director's project page.

Access The Server with app.server:

This is a union middleware kernel.

Modify the Server Options with app.http:

This object contains options that are passed to the union server, including app.http.before, app.http.after and app.http.headers.

These properties may be set by passing them through as options:

app.use(flatiron.plugins.http, {
  before: [],
  after: []
});

You can read more about these options on the union project page.

Start The Server with app.start(port, <host>, <callback(err)>)

This method will both call app.init (which will call any asynchronous initialization steps on loaded plugins) and start the http server with the given arguments. For example, the following will start your flatiron http server on port 8080:

app.start(8080);

Create a CLI Application with flatiron.plugins.cli(options)

This plugin turns your app into a cli application framework. For example, [jitsu] (https://github.com/nodejitsu/jitsu) uses flatiron and the cli plugin.

Valid options include:

{
  "argvOptions": {}, // A configuration hash passed to the cli argv parser.
  "usage": [ "foo", "bar" ], // A message to show for cli usage. Joins arrays with `\n`.
  "dir": require('path').join(__dirname, 'lib', 'commands'), // A directory with commands to lazy-load
  "notFoundUsage": false // Disable help messages when command not found
}

Add lazy-loaded CLI commands with options.dir and app.commands:

Flatiron CLI will automatically lazy-load modules defining commands in the directory specified by options.dir. For example:

// example2.js
var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  dir: path.join(__dirname, 'cmds')
});

app.start();
// cmd/highfive.js
var highfive = module.exports = function highfive (person, cb) {
  this.log.info('High five to ' + person + '!');
  cb(null);
};

In the command, you expose a function of arguments and a callback. this is set to app, and the routing is taken care of automatically.

Here it is in action:

% node example2.js highfive Flatiron 
info:   High five to Flatiron!

You can also define these commands by adding them directly to app.commands yourself:

// example2b.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli);

app.commands.highfive = function (person, cb) {
  this.log.info('High five to ' + person + '!');
  cb(null);
};

app.start();
% node example2b.js highfive Flatiron 
info:   High five to Flatiron!

Callback will always be the last argument provided to a function assigned to command

app.commands.highfive = function (person, cb) {
  this.log.info('High five to ' + person + '!');
  console.log(arguments);
}
% node example2b.js highfive Flatiron lol haha
info:    High five to Flatiron!
{
  '0': 'Flatiron',
  '1': 'lol',
  '2': 'haha',
  '3': [Function]
}

Define Ad-Hoc Commands With app.cmd(path, handler):

This adds the cli routing path path to the app's CLI router, using the director route handler handler, aliasing app.router.on. cmd routes are defined the same way as http routes, except that it uses (a space) for a delimiter instead of /.

For example:

// example.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    'usage: node test.js hello <person>',
    '',
    '  This will print "hello <person>"'
  ]
});

app.cmd('hello :person', function (person) {
  app.log.info('hello ' + person + '!');
});

app.start()

When you run this program correctly, it will say hello:

% node example.js hello person
info:   hello person!

If not, you get a friendly usage message:

% node test.js hello
help:   usage: node test.js hello <person>
help:
help:     This will print "hello <person>"

Check CLI Arguments with app.argv:

Once your app is started, app.argv will contain the optimist-parsed argv options hash, ready to go!

Here's an example:

// example3.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli);

app.start();

app.log.info(JSON.stringify(app.argv));

This prints:

% node example3.js
info:    {"_":[], "$0": "node ./example3.js"}

Awesome!

Add a Default Help Command with options.usage:

When attaching the CLI plugin, just specify options.usage to get a friendly default message for when there aren't any matching routes:

// example4.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    'Welcome to my app!',
    'Your command didn\'t do anything.',
    'This is expected.'
  ]
});

app.start();
% node example4.js 
help:   Welcome to my app!
help:   Your command didn't do anything.
help:   This is expected.

Start The Application with app.start(callback):

As seen in these examples, starting your app is as easy as app.start! this method takes a callback, which is called when an app.command completes. Here's a complete example demonstrating this behavior and how it integrates with options.usage:

// example5.js
var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    '`node example5.js error`: Throws an error.',
    '`node example5.js friendly`: Does not throw an error.'
  ]
});

app.commands.error = function (cb) {
  cb(new Error('I\'m an error!'));
};

app.commands.friendly = function (cb) {
  cb(null);
}

app.start(function (err) {
  if (err) {
    app.log.error(err.message || 'You didn\'t call any commands!');
    app.log.warn('NOT OK.');
    return process.exit(1);
  }
  app.log.info('OK.');
});

Here's how our app behaves:

% node example5.js friendly
info:   OK.

% node example5.js error
error:  I'm an error!
warn:   NOT OK.

% node example5.js
help:   `node example2b.js error`: Throws an error.
help:   `node example2b.js friendly`: Does not throw an error.
error:  You didn't call any commands!
warn:   NOT OK.

Read More About Flatiron!

Articles

Sub-Projects

Tests

Tests are written in vows:

  $ npm test

License: MIT

director's People

Contributors

3rd-eden avatar alfred-nsh avatar avianflu avatar beaugunderson avatar blakmatrix avatar bmeck avatar coen-hyde avatar dcneiner avatar domenic avatar dscape avatar ferlores avatar frekw avatar geddski avatar indexzero avatar indutny avatar jcrugzz avatar jfhbrook avatar julianduque avatar kevinswiber avatar longlho avatar luk- avatar marak avatar mmalecki avatar pksunkara avatar rvagg avatar southern avatar stolsma avatar tblobaum avatar vesln avatar yojimbo87 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

director's Issues

Error when router.on() (Client-side routing)

using: director-1.0.7.min.js

In chrome v16:

var router = new Router().init();
router.on('/:some', function () {...}); //=> TypeError: Cannot call method 'concat' of undefined

In FF v9

var router = new Router().init();
router.on('/:some', function () {...}); //=> TypeError: this.scope is undefined

In IE v9 does not work.

Routing for a non-match

I have the following in my application:

new Router({
    '/(\\w+)\\/' : selectRepository 
}).init();

function selectRepository(repo) {
    ...
}

I would like to match #/AAA, or #/BBB,.... However, if I put no hash, to hit the main page originally, as in http://localhost:8080/context/ it goes through the router, and in the parse method of SS.js, the first line (parse.shift) returns undefined. Then the method continues on and undefined becomes /undefined/ in leftovers, which matches my regular expression, but of course the routing will not work. I could of course check for undefined in my selectRepository function, but I really think this case should be handled internally and /undefined should not be handled as an acceptable case.

To fix this locally, I just added:

  if (partialpath === undefined) {
      return false;
  }

after

 var partialpath = path.shift(); 

of the parse method.

That said, this is probably just treating the symptom. I have not really delved in to understand all of the code, so, maybe something like:

leftovers = (partialpath ? ('/' + partialpath + '/') : '/') + path.join('/');

would be more correct.

Anyway, I am not a regex guru and so I could just have something wrong with my regex, or just be missing something in the usage entirely, as I just barely started using SugarSkull, so if there is a better way, please let me know.

Use director programmatically ( without CLI or HTTP or browser )

Is it currently possible to use director entirely in memory? Without needing any external interface?

We were attempting to use an API that looked like this:

var router = new director.Router();

router.on(/foo/, function () {
  console.log('sup');
});

router.dispatch('GET', '/foo', function (err) {
  console.log('sup', err);
});

Allow routing without the hash

Currently client-side director only supports hash-routing. It would be a nice sugar feature if it could support regular routing too.

this when using a resource

Hi,

I've got a question on how to handle this in the following (browser) scenario.

var MyApp = function(){
}

MyApp.prototype.start = function() {
console.log(this);
};

var app = new MyApplication();

routes = {
'/': 'start',
}

Router(routes).configure({resource:app}).init();

When I point my browser to "#/" start gets called, but the console.log(this) prints the a.Router object.

Is there a way to get this' set to the resource?

Thanks

Simple Tokens

@hij1nx I'm wondering if you'd be open to the idea of simple tokens. Here's what I mean:

Say you want to match the group name and project name from this URL: /project/mobile-team/iphone-app

With Regex

'/project\\/([a-z0-9-]+)\\/([a-z0-9-]+)': viewProject

With Simple Params

'/project/:group/:project': viewProject

Your readme mentions that simple tokens like this can't handle every situation, and that's true. But they handle probably 95% of the use cases for routing, and they're very easy to use. I'm sure that's why Express, Sammy, and CouchDB use them. Actually the only thing you gain from regex routes is the ability to distinguish from /articles/4 and /articles/four for example. But the increase in power comes at the cost of being more difficult to use.

I have an idea for a simple syntax that would allow both simple params AND regex distinction where you need it. Just include the regex filter after the simple param. So for example using the same URL /project/mobile-team/iphone-app you could:

Match any param

'/project/:group/:project': viewProject

Match only params of a certain type (with regex)

'/project/:group/:project(\\d+)': viewProject 
//would match /project/mobile-team/43 but not /project/mobile-team/iphone-app

The (\\d+) isn't a capture, but rather a definition of what type the simple param must be in order to match. What do you think? This lets your routes be simple and concise, and only use regular expressions in the rare cases where you need them. This would make sugarskull.js easier to use for developers (like me) who aren't experts with regular expressions, without losing any of the flexibility that sugarskull.js currently has.

If you're interested but don't have the time would you be open to a pull request for this?

Thanks!

'/:page': ':page'

Router({
  '/:page': ':page'
}).use({ 
  resource: {
    pizza: function() { ... },
    taco: function() { ... },
    muffins: function() { ... }
  }
})

this would be handy as it would save me from doing something redundant like this:

var pages = {
  pizza: function() { ... },
  taco: function() { ... },
  muffins: function() { ... }
}

Router({
  '/:page': {
    on: function(page) {
      pages[page]()
    }
  }
}).use({ 
  resource: pages
})

Routing event support for request/response

Wanted to implement http basic auth checking as a filter and I'm not able to using routing events.

Request and response objects are not available to routing events and according to the comments in the routing events code, we should not return anything from a routing event function.

Parameter dictionary support

So as I mentioned (too briefly) on twitter the other day, I think it
would be really neat if SugarSkull supported parameters to its URLs.
The main motivation for this is that the application I'm currently
working on (http://brasstacks.mozilla.com/gofaster/#/) has some views
that can take many parameters, for example:

http://brasstacks.mozilla.com/gofaster/#/executiontime/build/30
http://brasstacks.mozilla.com/gofaster/#/executiontime/test/60

In this example, only really the first part of the path
(executiontime) is really modelling a resource in my application. The
other two are more like parameters to the request. Obviously putting
them as fully fledged paths works (as that's what I'm doing right
now), but has the following disadvantages:

  1. It complicates the links I make on the main page (instead of just
    using defaults)
  2. More importantly, if I want to add an additional parameter (which
    I'm actually about to do), any previous links I made using the old
    structure will be invalidated.

I can think of a few ways around the above but they seem excessively
complicated. What I'm thinking of is adding the option of setting
parameters to sugar skull "URLs", so you could make queries like this:

http://brasstacks.mozilla.com/gofaster/#/executiontime
http://brasstacks.mozilla.com/gofaster/#/executiontime?type=build
http://brasstacks.mozilla.com/gofaster/#/executiontime?type=build&range=30

and the router would only parse the section up to the '?' character,
passing the set of parameters to the function as a dictionary called
params (if there are no parameters, the dictionary would obviously be
empty).

I guess this would break backwards compatibility since we'd now be
expecting the parameters variable to appear in everybody's functions
(but at least all people would have to do is update their code:
existing URLs would still work on the client side).

If I were to add something like that to a fork of your project, would
you accept it back into mainline?

Nested syntax with params

Would like to be able to define nested routes that support simple-tokens or regexps, pass all values forward.

'/a': {
   '/(\d+)': {
       on: function(b) { ... },
       '/(\d+)': {
           on: function(b, c) { ... }
       }
   }
}

Bump current master version and publish ??

First of all: A happy and good coding new year! :-)

And 2nd, is there a possibility for someone to bump the version on master and publish that new version to NPM? Need the query parameter fix thats already committed two weeks ago but not published yet.... ;-)

Thanks !!

Can't match ";" or "/" with a wildcard in routes

Director can not match these characters because regifyString will replace route wildcards with another regexp which does not match these characters.

The following server responds to /foo/bar with "hello world", but will 404 for /foo/bar;baz or /foo/bar/baz.

var union = require('union');
var director = require('director');
var router = new director.http.Router();

router.get(/\/foo\/(.*)/, function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' })
  this.res.end('hello world\n');
});

var server = union.createServer({
  before: [
    function (req, res) {
      var found = router.dispatch(req, res);
      if (!found) {
        res.emit('next');
      }
    }
  ]
});

server.listen(9090);

Problem with regex matching "\/"

Code example:

router.get(/sup/meh/, function () {
this.res.writeHead(200, { 'Content-Type': 'text/plain' })
this.res.end('hello world\n');
});

If I try to access: /sup/meh, I get this error:
/usr/local/lib/node_modules/director/lib/director/router.js:420
match = path.match(new RegExp('^' + exact));
^
SyntaxError: Invalid regular expression: /^/sup/: \ at end of pattern
at new RegExp (unknown source)
at [object Object].traverse (/usr/local/lib/node_modules/director/lib/director/router.js:420:26)

I've debugged a little bit and came to the conclusion that the problem is:
if (path.source) { // ~ line 200
path = path.source
}

The problem is when we split based on the '/' delimiter, the parts become:
'sup', 'meh'.. and when later on it tries to match 'sup' it obviously says there's a regex error.

My current quick fix: (Replacing / by /)
if (path.source) {
path = path.source.replace('/', '/');
}

Hope it helps

Multiple hash parameters

Is there a way to handle multiple hash parameters?

eg.
...index.html#/roadmap/7/2010

I tried to define it this way:
'/roadmap': {
   '/(\d+)': {
       on: displayRoadmap,
       '/(\d+)': {
           on: displayRoadmap
       }
   }
}

Hoping that it would call my function with one or two parameters based on matches:
function displayRoadmap(id, year) {
   ...
}

Thanks,
tvalletta

Trailing slashes not possible in director routes?

In theory, these two URLs are equally valid, and will generally mean the same thing:

  1. http://localhost:7000/api/
  2. http://localhost:7000/api

However, it seems that number 1 is not currently possible with Director.

I have this setup in my Flatiron app:

// In app.js
var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.http);

app.router.path('/api', require('./api').router);


// In api/index.js
var router = function () {
  this.get('/', function () {
    this.res.writeHead(200, { 'Content-Type': 'text/plain' });
    this.res.end('This is the entry point for the Ardon API.');
  });
};

module.exports = {
  router: router
};

I've tried different variations of that with slash or not slash in the app.router.path() and this.get() invocations, but the result is invariably the same. http://localhost:7000/api works as it should, http://localhost:7000/api/ returns the text “undefined” with a 404 not found header.

Multiple Routers and URL params

Looks like if I try to make multiple routers (like in Sammy.js) the second one overrides/disables the first. Any chance of adding support for multiple concurrent routers?

Http Router doesn't work with URL parameters

When testing with: http://development:9090/test/foo?test=test the attached route function to /test/foo isn't executed. But if I change the request to http://development:9090/test/foo it is.

I debugged the code and found that the whole URL (+ the parameters after ?) is fed into the traverse function by the dispatch function. If I change that to only the part before ? then it works. Can make a patch for it but don't know if the current behavior is the correct one. If this is the correct behavior then what do I need to do to get URLs with parameters working with Director?

Not totally clear how to use state from README

I think I'd like to use state for something I'm working on, but it's not very clear how to do this from the documentation. Basically I have a small app with two routes:

'/builds': {
  '/:buildid': {
    on: function(buildid) { ... }
    '/jobs': {
      '/:jobid': {
        on: function(buildid, jobid) { ... }
      }
    }
  }
}

The second is a superset of the first (that is, the first one should be loaded before the second). I can make this happen by recursing forward. So far so good. The problem is that when going backward (e.g. transitioning from /builds/foo/jobs/bar to /builds/foo), SugarSkull think it needs to call the "on" function for /builds/foo (when in fact it's already loaded). I'm gathering that this is something that I can use state for, but it's not clear to me how from the documentation.

Problem 1: How do I access the state dictionary from inside my router functions?
Problem 2: How do I assign route-specific information (e.g. a buildid in the example above) to a state dictionary?

HTTP routing functions getting passed the route?

Either this is a bug in the code or in the docs. Should the route name be available to the registered function? Right now it's coming out as undefined.

From the docs:

function helloWorld(route) {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' })
  this.res.end('hello world from (' + route + ')');
}

When running the demo code and hitting curl http://localhost:8080/hello, the print statement comes out as:
hello world from (undefined)

Routing table created incorrectly when passed to the constructor

I've copied the sample code from the docs and added a little logging.

https://gist.github.com/1367702

After starting the server, http://localhost:8080/hello, the route passed to the constructor on lines 20 and 21, returns a 404.

The logging statement on line 47 prints the routing table which is broken for the routes passed to the constructor. For a method it seems to have "et" instead of "get".

data:   {
data:       bonjour: { get: [Function] },
data:       hello: {
data:           et: { on: [Function] }
data:       },
data:       hola: { get: [Function] }
data:   }

This is using Node 0.6.1 and SugarSkull version 1.0.1 from npm.

Routes recurse

Say I have two routes: /blogpost and /blogpost/edit. Currently, if /blogpost/edit is hit, the "on" function for both the routes are called. There might be use-cases for both to be called, but the majority of use-cases will be entirely different functionality, so recursing the child urls is not expected. /blogpost will show the blog post, and /edit will show a form, for example.

If there already is a way to control if the recursion will happen, I'm not aware of it. If there isn't, there should be. :)

Let me know if I wasn't clear enough.

Overlapping simple tokens issue

If you have overlapping route that include simple tokens, only the routes that END in a simple token will be routed. No errors are displayed or callbacks are hit.

The routes are listed below:

'/foo/:id' : function(){
            console.log("foo2 ", arguments);
        },

        '/foo/:id/bar' : function(){
            console.log("bar", arguments);
        },
        '/foo/:id/bar/:id2' : function(){
            console.log("bar2", arguments);
        },

        '/foo/:id/bar/:id2/baz' : function(){
            console.log("baz", arguments);
        },
        '/foo/:id/bar/:id2/baz/:id3' : function(){
            console.log("baz2", arguments);
        }

Initialization always fires 'notfound' handler

The Router init() method executes a call to route() without passing a parameter. This causes the route to be 'undefined' which ultimately causes a call to the notfound handler upon initialization.

// init method
this.init = function() {
listener.init(route);
route();
return this;
};

//in parse method
if(route === undefined && path.length === 0) {
self.noroute(partialpath);
return false;
};

Is the initial route() call necessary? Should the 'notfound' handler be added only initialization? That seems clunky.

Thanks!

HTML5 History API Support

Feature Request: Support for HTML5 History API on an opt-in basis, with graceful fallback to hash version in lame browsers. Similar to the backbone and sammy routers. The main use case is for web apps that also want SEO (think twitter) and that build a server side solution for it. With Node being able to run your front end's same backbone models and templating it's not much more work. Having the option to handle the routing in sugarskull would be nice.

router.get(/\//, handler) breaks

What I'm trying to do is match against the root directory ("/").

It's entirely possible that this shouldn't work, but if so the way to match against a root directory (using .get and friends) is non-obvious.

http routing recurse doesn't work

Either settings 'backword' or 'forward' don't work in http routing.

My env:

$ node -v
v0.6.6
$ npm list
├── [email protected]

Example code:

  var http = require('http'),
      director = require('director');

  var router = new director.http.Router(
  {
    '/hello':
    {
      '/hello2':
      {
        get: function(route)
        {
            this.res.write('hello2\n');
        }
      },
      get: function(route)
      {
        this.res.write('hello\n');
      }
    }
  }).configure(
  {
    recurse: 'backward',
    before: function(){ this.res.writeHead(200, { 'Content-Type': 'text/plain' }); },
    on: function(){ this.res.end(); }
  });

  var server = http.createServer(function (req, res) {
    router.dispatch(req, res, function (err) {
      if (err) {
        res.writeHead(404);
        res.end();
      }
    });
  });

  server.listen(8080);

Result:

$ curl http://localhost:8080/hello/hello2
hello2

[build 1.0.7] Adhoc routing in browser broken

I wanted to use this adhoc routing but it seems te be broken... How is this possible btw? We're creating builds that are not working correctly :S

See commit ef3b3bf.

Adhoc routing results in Uncaught TypeError: Cannot call method 'concat' of undefined

Global Routes

The ability to add global routes to be fired whenever any part of the hash contains the fragment

e.g.

router = Router({

    '*/global/*: {
        on: killDog
    },
    '/home': {
        on: goHome,
        '/users': {
            on: loadUser
        }
    }

}).init();

would match...

http://someapp.com/#/global/

http://someapp.com/#/home/users/global/

http://someapp.com/#/home/global/users/

similarly, if you could define it as global part of a subsequent route

router = Router({

    '/home': {
        on: goHome,
        '/users': {
            on: loadUser
        },
        '*/global/*: {
            on: killDog
        }
    }

}).init();

Would match

http://someapp.com/#/home/users/global/

http://someapp.com/#/home/global/users/

http://someapp.com/#/home/users/:token/global

but not

http://someapp.com/#/global/

http://someapp.com/#/some-other-route/global/

It would be beneficial to pass the before and after fragments via arrays

e.g.

function killDog([ before, match, fragments], [after, match, fragments]  ){

}

Not sure if I'm missing something but I have tried to achieve a similar result using regex and recurse, to no avail.

Addition of query string parameters causes existing/previously working routes to no longer fire.

Original URL that worked:
http://localhost:3201/games/PS3/MostPopular/All%20PS3%20Games

'/:platform/:filter/([^.]*)': {
get: function (platform, filter, category) {
renderer.getGameslist(filter, platform, category.replace(/&/g, '%26'), 1, 20, this.req, this.res);
}
},

When I add query string parameters like in the following URL , the above route no longer is triggered.
http://localhost:3201/games/PS3/MostPopular/All%20PS3%20Games?pageNumber=2&pageSize=20

Leave function won't fire on hashchange

First, let me say, great library. Exactly what I think this world needs :)

Im having a little issue. when I navigate away from a certain page, i have leave event, and it just won't fire. Is there something specific I need to do?

example code doesn't work.

encountered many problems, trying what was in the readme.

Router({})
TypeError: Object #<Object> has no method 'configure'
    at /home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/router.js:124:8
    at /home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/http/index.js:14:21
    at Object.<anonymous> (/home/dominic/source/dev/experiement/ss.js:4:9)
    at Module._compile (module.js:411:26)
    at Object..js (module.js:417:10)
    at Module.load (module.js:343:31)
    at Function._load (module.js:302:12)
    at Array.<anonymous> (module.js:430:10)
    at EventEmitter._tickCallback (node.js:126:26)

new Router({}).init()
TypeError: Object [object Object] has no method 'init'
    at Object.<anonymous> (/home/dominic/source/dev/experiement/ss.js:9:4)
    at Module._compile (module.js:411:26)
    at Object..js (module.js:417:10)
    at Module.load (module.js:343:31)
    at Function._load (module.js:302:12)
    at Array.<anonymous> (module.js:430:10)
    at EventEmitter._tickCallback (node.js:126:26)
var Router = require('sugarskull').http.Router
  , http = require('http')

function respond () {
  console.error('it worked')
  this.res.writeHeader(200); this.res.end('aoneuhaoenuhoneiurkpborkbropkbr')   
}

var r = new Router({
  on: respond,
  '/\//': respond,
  '/': respond,

})

http.createServer(function (req, res) {
  r.dispatch(req, res, function (err) { throw err })
}).listen(8080)
                                        ^
Error: Could not find path: /
    at [object Object].dispatch (/home/dominic/source/dev/experiement/node_modules/sugarskull/lib/sugarskull/http/index.js:60:16)
    at Server.<anonymous> (/home/dominic/source/dev/experiement/ss.js:21:5)
    at Server.emit (events.js:67:17)
    at HTTPParser.onIncoming (http.js:1134:12)
    at HTTPParser.onHeadersComplete (http.js:108:31)
    at Socket.ondata (http.js:1029:22)
    at Socket._onReadable (net.js:677:27)
    at IOWatcher.onReadable [as callback] (net.js:177:10)

this needs working examples!

IE8 regex routing

so the following two routes work in FF, Chrome, IE9, etc.

'/test\\/': function(){console.log('test hit')},
'/test\\/([a-z0-9-]+)': function(x){console.log('test hit with '+x)}

but only the first one works when my browser is put into "Document Mode: IE8 Standards"
i am partially suspecting regex differences ( http://stevenlevithan.com/demo/split.cfm )

my current project has an IE8+ requirement. is this something you would be willing to look into? i do understand that coding for old quirks is sometimes more hassle than its worth.

SIDENOTE: as i was testing different patterns i learned that this route works in all browsers:

'/foo': { '/bar': function(){console.log('FUBAR')} }

but this one does not work in any browsers:

'/foo/bar': function(){console.log('FUBAR')}

is this the designed/desired behavior?

recursion when used with webshims

When used alongwith webshims we get the error "too much recursion", specifically on firefox 3.6.23 .
Here is jsfiddle http://jsfiddle.net/zfTBS/1/ .

I have tried with latest versions of all libs but no luck. jquery(1.6.4), webshims (1.8.2) and SugarSkull latest.

I am not sure whether webshims/SugarSkull so might add same issue for webshims too.

Same thing works well on Chrome.

Thanks for this wonderful library. We love it.

with recurse on After is fired on On

for the router setup

router =Router( {
    'foo':{
        on: function(){},
        after: function(){}
    }
}).use({ recourse: forward }).init();

and the url:

#/foo

After will fired when the url is navigated to, and once the url has left.

Readme link missing

You can find a browser-specific build of director here which has all of the server code stripped away.

The text here links to the front page of the repo and not to the alluded to browser-specific version

Better Examples

Need to write some better examples of how SugarSkull works.

Stack overflow / event firing order

My mini-router here:
https://gist.github.com/1248332

Having 2 issues:

  1. my global 'after' event seems to be firing before 'on'
  • this was happening with the sample code from the SugarSkull dl too
  • what exactly does "after this route" mean? i.e. does this mean when another hashchange happens when you are already on the specified route?
  1. Getting a stack overflow error with regify on line 38 of SS.js when I try to use the resource param and define a methods object
  • this was happening for me on both Chrome and FF

Maybe I'm just defining something wrong?

ps. can you also specify what SS.min.js is? doesn't seem to just be a minified version of SS.js, or am I wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.