uri-router

3.0.5 • Public • Published

uri-router npm tests

A small framework for building URI driven DOM applications.

saucelabs

Example

index.html

<!doctype html>
<html>
  <body>
    <nav>
      <a href="/">home</a> |
      <a href="/about">about</a> |
      <a href="/contact">contact</a>
    </nav>
    <div id="pages"></div>
  </body>
  <script type="text/javascript" src="/app.js"></script> 
</html>

app.js

var router = require('uri-router')
var nav = require('./nav')
var home = require('./home')
var about = require('./about')
var contact = require('./contact')
 
router({
  routes: [
    ['.*', nav]
  ]
})
 
router({
  watch: 'pathname',
  outlet: document.querySelector('#pages'),
  routes: [
    ['/',           home],
    ['/about',     about],
    ['/contact', contact]
  ]
})

nav.js (a view that's already on the DOM)

module.exports = document.querySelector('nav')
 
var qsa = require('qsa-es5')
 
module.exports.show = function (uri) {
  qsa('a', this).forEach(function (a) {
    var active = a.getAttribute('href') === uri.pathname
    a.style.textDecoration = active ? 'underline' : 'none'
  })
}

home.js (a plain DOM element as a view)

module.exports = function () {
  var el = document.createElement('H1')
  el.textContent = 'Home'
  return el
}

about.js (a web component as a view)

var About = {
  prototype: Object.create(window.HTMLElement.prototype)
}
 
About.prototype.createdCallback = function () {
  var shadow = this.createShadowRoot()
  shadow.innerHTML = '<h1>About</h1>'
}
 
module.exports = document.registerElement('about-component', About)

contact.js (a view that uses lifecycle hooks to transition in and out)

module.exports = function () {
  var el = document.createElement('div')
  el.innerHTML = '<h1>Contact</h1>'
  el.show = show
  el.hide = hide
  el.style.transition = 'opacity 0.5s'
  return el
}
 
function show () {
  window.getComputedStyle(this).opacity
  this.style.opacity = '1'
}
 
function hide (uri, cb) {
  this.style.opacity = '0'
  this.addEventListener('transitionend', cb)
}

The code above is pretty basic, check out the example app for fancier things:

$ npm run example

Test

$ npm run test-local
# to run the tests at sauce, open a sauce-connect tunnel and do: 
$ SAUCE_USERNAME=x SAUCE_ACCESS_KEY=y npm run test

Require

var Router = require('uri-router')

Returns a function for creating routers. The first time uri-router is required, it will globally hijack all link clicks and form submissions targeting the origin and start listening for the popstate event.

Static methods

It's critical you do not use window.history.{pushState,replaceState,go,back}() directly! Use the static methods listed here instead.

Router.push(location, [replace])

Update window.location.

  • location String
  • replace Boolean; indicates to use replaceState instead of pushState

Router.replace(location)

Shortcut for Router.push(location, true).

Router.pop()

Like window.history.back() put queued properly.

Router.search(query, [replace])

Update window.location.search without clobbering the existing query.

example: assuming the search string is set to ?a=1, calling Router.search({ b: 2 }) would change it to ?a=1&b=2.

Instance methods

var r = Router(opts)

The constructor. opts is augmented, tracked and returned as r. Beware, r is NOT actually an instance of Router! I am open to changing this if there is a good reason.

r.destroy()

Hide any active views and stop the instance from updating on {push,replace,pop}state.

Instance properties

r.watch

Should be set to the name of a property on window.location, generally "pathname" or "hash"

r.routes

An array of regex / handler pairs like: ['regex', handler]. The handler can be an instance of HTMLElement, a newable constructor that inherits from HTMLElement, or a function with signature (uri, next). Handlers that are plain functions should either call next to be treated as middleware (falling through to succeeding routes) or return an instance of HTMLElement, but not both.

views generated by route handlers can optionally define show() and hide() methods, see lifecycle hooks for more details.

r.outlet

An optional DOM element. If an outlet is specified, location changes will trigger the removal of any existing elements, and the appending of any elements generated by the matched handler. If the same handler is matched more than once in a row, and handler.reusable === true, the existing view will simply get a show() hook rather than being removed and created again from scratch.

r.base

An optional prefix to ignore for r.watch. Useful for building abstract views with nested routers.

Lifecycle hooks

Any time window.location changes, all active views should expect to receive one or more of the following (optional) hooks:

view.show(uri)

Called on all active views when window.location changes. See URI Properties for properties available on uri.

view.hide(uri, cb)

Called after a view becomes inactive, but just before it is removed from the DOM. If the hide implementation accepts a callback, (and the router specifies an outlet) the router will defer removing the view from the DOM until the callback is executed.

URI properties

URI objects are passed to route handlers and lifecycle hooks. They define most of the properties described in the URL spec and some Router specific properties described here:

init

True when window.location has not changed since the page loaded.

back

True when the browser's back button has been clicked or Router.pop() was called.

replace

True when Router.replace initiated the location change.

watch

Alias for the dispatching router's watch property.

base

Alias for the dispatching router's base property.

top

If there are any capture groups in the route regex, this will be set to the value of the first group. You can use this to set r.base on nested routers.

params

An array of the capture group values from the route regex, excepting the first group, which is considered the base - see above.

query

A parsed querystring object.

Releases

  • 3.0.1
    • Added option Router.replaceOnClick to replace instead of push by default when handling link clicks
  • 3.x
    • Changed uri.base semantics and added a corresponding uri.top property
  • 2.x
    • Changed uri.init semantics
    • Expose the current uri
    • Set default watch property to "href"
  • 1.x
    • Complete rewrite, November 2015
  • 0.x
    • Initial prototype, August 2014

License

Copyright © 2014 Jesse Tane jesse.tane@gmail.com

This work is free. You can redistribute it and/or modify it under the terms of the WTFPL.

No Warranty. The Software is provided "as is" without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, merchantability, fitness for a particular purpose, or non-infringement.

Package Sidebar

Install

npm i uri-router

Weekly Downloads

1

Version

3.0.5

License

WTFPL

Last publish

Collaborators

  • jessetane