npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

backbutton.js

v1.0.2

Published

Small, robust and versatile JavaScript router for single page apps

Downloads

8

Readme

backbutton.js

backbutton.js—The 1kb standalone router for client-side JavaScript applications

backbutton.js makes the browser back button functional in single page apps
backbutton.js makes it easy to implement client-side routing
backbutton.js works basically everywhere, including local files and old browsers(*)
backbutton.js allows for fast prototyping with little setup—achieve much with just a text editor and a local browser
backbutton.js is open source (MIT licensed), freely use it for any purpose

(*) tested in IE6+, FF3.6+, Safari 4+, iOS Safari 4+, Chrome 6+, Opera 12+, run tests online

Quick demonstration

Insert the following code in an HTML document and preview in a browser (or see it in action here):

<nav>
  <a href="#">Home</a>
  <a href="#services">Services</a>
  <a href="#about">About</a>
</nav>
<main id="view"></main>
<script src="https://cdn.jsdelivr.net/gh/tomaslangkaas/[email protected]/backbutton.js"></script>
<script>
  backbutton.routes([
    /^(services|about)$/, function(path){ // topic page route
      display('This is the ' + path + ' page.')
    },
    /.*/, function(){ // route anything else to the home page
      display('This is the home page');
    }
  ]);
  function display(message){
    document.getElementById('view').innerHTML = message;
  }
</script>

Setup

Load backbutton.js from a local copy:

<script src="path/to/JS/backbutton.js"></script>

or from CDN:

<script src="https://cdn.jsdelivr.net/gh/tomaslangkaas/[email protected]/backbutton.js"></script>

or npm:

npm install backbutton.js --save

How backbutton.js works

backbutton.js responds to changes in location.hash. App navigation is implemented by setting the value of location.hash, either from links, like <a href="#applicationPath>, or from code, like backbutton.navigate('applicationPath').

Routes are set up by providing backbutton.routes() with a routing table—an array of regular expressions and route callbacks:

backbutton.routes([
  /^$/, // triggered by blank path, like <a href="#">
  function(){
    /* home route callback for blank path */
  },
  
  /^search:(.*)/, // triggered by search:queryString, like <a href="#search:rabbits">
  function(queryString){
    /* search route callback */
  },
  
  /(.*)/, // catch-all, triggered by anything not captured by other routes
  function(path){
    /* anything else route callback */
  }
]);

Whenever location.hash changes, the routing table array works like a switch statement; backbutton.js loops through the routing table until it encounters the first regular expression that matches location.hash, then executes the corresponding callback function. Any captured sub-expressions are provided as arguments to the callback.

If the callback function provides a truthy return value, backbutton.routes() proceeds looping through the routing table until it encounters the next regular expression that matches. Otherwise, it stops. If no regular expression matches, nothing happens.

If a route callback returns a non-blank string, backbutton.routes() will match subsequent regular expressions against this string instead of location.hash, making it possible to implement route redirects or other types of conditional routing.

Auto start and manual start

When backbutton.routes() is provided with a routing table, backbutton.js automatically loops through the array, attempting to match the current location.hash against the table. This behaviour is to automatically start routing on route setup. To prevent this behaviour, pass false as a second argument: backbutton.routes(routingTable, false).

To manually trigger routing with the current value of location.hash, call backbutton.refresh(). This will notify all backbutton observers, including backbutton.routes(). Thus, these examples are equivalent, as they both immediately calls any route that corresponds to the current location.hash:

// auto start
backbutton.routes(routingTable);

// or manual start
backbutton.routes(routingTable, false);
backbutton.refresh();

The backbutton.js API

backbutton.js has a small, but versatile API:

  • backbutton.version is a string containing the version number.
  • backbutton.navigate() sets location.hash from code.
  • backbutton.current() gets the current location.hash.
  • backbutton.refresh() notifies all observers that location.hash has changed, while it has not. Calling this function does not create any new history entries.
  • backbutton.observe() registers observers to monitor changes in location.hash.
  • backbutton.routes() provides routing with regular expressions and callbacks.

backbutton.navigate(newHashString) and backbutton.current()

These two functions respectively sets and gets the value of location.hash. Use these functions to ensure cross-browser functionality, some old browsers have issues with setting and getting location.hash from code.

// before: current url is http://somedomain.com/somedocument

backbutton.navigate('someApplicationPath');

// after: current url is now http://somedomain.com/somedocument#someApplicationPath
// all active observers and the router in `backbutton.routes()` are notified about the change

var currentHash = backbutton.current(); // 'someApplicationPath'

backbutton.refresh()

This function notifies all active observers and the router in backbutton.routes() that location.hash has changed, while it has not. This can be used to manually trigger routing or observers on document load. Note that each call to backbutton.routes() automatically calls backbutton.refresh(), unless it is specifically told not to.

backbutton.observe(observerFunction)

This function registers an observer function, to be called whenever location.hash changes. backbutton.observe() returns an unregister function, used to unregister the observer. Call backbutton.observe() multiple times to register multiple observers.

var unobserve = backbutton.observe(function(currentLocationHashString){
  /* called whenever location.hash changes */
});

// remove the observer
unobserve();

Observers are notified after the router in backbutton.routes(). Observers are notified in the order they are registered. Observers are provided with the current value of location.hash as the only argument. In observer functions, the keyword this refers to backbutton.

backbutton.routes(routingTableArray [,autoStartBoolean])

backbutton.routes() is called to setup a routing table. A routing table is an array of regular expressions and route callbacks. When location.hash changes, the routing table is handled as a switch statement, for the first regular expression that matches the current value of location.hash, the corresponding route callback is called.

Auto start and manual start

Each time a routing table is set with backbutton.routes(), backbutton.refresh() is automatically called to call routes (and observers) that match the current value of location.hash. To prevent this behavior, pass true as the second argument to backbutton.routes().

Route parameters

If a regular expression has sub-expressions that are captured, these are provided as arguments to the route handler.

backbutton.routes([
  /(\w+)\/(\w+)/, // matches the pattern "someCategory/someSubcategory"
  function(category, subcategory){
    // the captured sub-expressions are provided as separate arguments
  }
]);
Catch-all route

To capture any value of location.hash not captured by other routes, add a catch-all regular expression and route callback at the end of the routing table. This mimics the default: label in switch statements, and could be used to implement 404 page functionality.

Note that if there is no catch-all route, no route callback will be called on document load if the first location.hash is unsupported.

backbutton.routes([
  /(.*)/, // catch-all, triggered by anything not captured by other routes
  function(path){
    /* anything else route callback */
  }
]);
The this keyword

In route callbacks, this refers to backbutton.

backbutton.routes([
  /(.*)/, function(path){
    /* this code */
    backbutton.current();
    /* is equivalent to this code */
    this.current();
  }
]);
Conditional routing

The routing table array works like a switch statement. When location.hash changes, backbutton.js loops through the table until it encounters the first regular expression that matches the current value of location.hash, then calls the corresponding route callback.

If a route callback returns a falsy value (functions return undefined by default), the loop stops.

However, if the route callback returns a truthy value, like true, the loop continues until it encounters the next regular expression that matches, then calls the corresponding route callback.

If a route callback returns a non-blank string (that is, any string except ""), subsequent regular expressions are matched against this string instead of location.hash, making it possible to do route redirects.

Utilizing these mechanisms, it is quite easy to create quite complex routing behaviour, with routes that checks for specific conditions, routes that are only accessible under specific conditions, and routes that redirect under specific conditions.

See the source code of the backbutton.js tests for examples of conditional routing in action.

Change the routing table at runtime

The routing table array is passed by reference to backbutton.routes(). By keeping another reference elsewhere to the routing table array, it is possible to change routing by changing the array. Regular expressions and/or route callbacks can be replaced or removed at runtime by using the .splice() method of arrays.

The current routing table array could also be replaced at any time by calling backbutton.routes() with a new routing table array.

Internally, backbutton.routes() creates an observer function that loops through the provided routing table. When backbutton.routes() is provided with a routing table array, it returns the prior router, that is, the prior observer function. To reinstate the prior router, call backbutton.routes with the prior observer function as the first argument.

See the source code of the backbutton.js tests for examples of routing table manipulation at runtime.