Last active
December 13, 2015 20:28
-
-
Save midned/4969899 to your computer and use it in GitHub Desktop.
Handle the routes in Javascript using HTML5 pushState (uses Zepto.js and https://github.com/balupton/History.js)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Create the router that will handle routes to 'site.com/app' | |
router = new Routy.Router 'app' | |
# also you can: | |
# router = new Routy.Router 'app', 'a.routy-link' | |
# to only listen clicks to links with the "routy-link" class | |
# or: | |
# router = new Routy.Router 'app', null, '#container' | |
# to listen clicks for every link inside the element with the "container" id | |
# this will handle 'app/' and 'app/home' | |
# and log 'Home' | |
router.register '/, home', -> | |
console.log 'Home' | |
# this will handle 'app/users' and 'app/users/list' | |
# and log 'List of users' | |
router.register 'users, users/list', -> | |
console.log 'List of users' | |
# TODO: add support to wildcards in the routes | |
router.register 'users/:id', (id)-> | |
console.log 'Viewing user #', id |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.Routy or = {} | |
History = window.History; | |
# The router, used to manage and store the actions | |
class Routy.Router | |
# List of registered actions | |
actions: [] | |
# Generate the router to a specific routing context | |
# @state_changers_selector: String containing the selector of the elements that will trigger the pushState event | |
# default: 'a' (all links) | |
# context_selector: String containing the selector of the container of the elements that will trigger the pushState event | |
# default: 'document' (will search inside the document) | |
constructor: (context, @state_changers_selector, context_selector)-> | |
# Let's clean the context variable | |
context or = '' | |
if context != '' | |
if context[0] == '/' | |
context = context.substr 1 | |
if context.substr(-1) == '/' | |
context = context.substr 0, context.length-1 | |
if context == '' | |
context = '/' | |
@context = context | |
@state_changers_selector or = 'a' | |
context_selector or = document | |
@context_selector = $ context_selector | |
console.log 'Initialized' | |
if History.enabled | |
@attach() | |
# Apply the current context to the specified url | |
apply_context: (url)-> | |
if url != '' | |
if url[0] != '/' | |
url = @context + '/' + url | |
else | |
url = @context + url | |
if url.substr(-1) != '/' | |
url = url + '/' | |
else | |
url = @context + '/' | |
url | |
# Listen for clicks in the elements that will trigger the pushState event | |
attach: -> | |
# 'cause "this" will be replaced with the clicked element | |
router = @ | |
@context_selector.on 'click', @state_changers_selector, (e)-> | |
e.preventDefault() | |
router.go @href, @title | |
# Create an anonymous function to call the router.run method so we can | |
# pass the router as "this" variable | |
History.Adapter.bind window, 'statechange', -> | |
router.run.apply router | |
# Redirect (using pushState) to a specific page | |
go: (url, title, data)-> | |
History.pushState data or {}, title or document.title, url | |
# Register a new action | |
register: (route, callback)-> | |
@actions.push new Routy.Action route, callback, @ | |
run: -> | |
uri = window.location.pathname | |
if uri != '' | |
if uri[0] == '/' | |
uri = uri.substr 1 | |
if uri.substr(-1) != '/' | |
uri = uri + '/' | |
for action in @actions | |
for route in action.route | |
if @matches route, uri | |
return action.call() | |
# Checks if the route matches with the current uri | |
# TODO: return an object with the result of the comparation and the arguments to pass to the action | |
matches: (route, uri)-> | |
route == uri | |
# Class representing an action | |
class Routy.Action | |
# Routes this action with handle | |
route: [] | |
# The callback to execute | |
callback: null | |
# Callback to execute before the action | |
before_callback: null | |
# Callback to execute after the action | |
after_callback: null | |
# Condition to execute the action | |
condition: null | |
# Create a new action | |
constructor: (routes, @callback, @router)-> | |
# so you can call it like: new Routy.Action(['/', 'home'], callback) | |
# or: new Routy.Action('/, home', callback); | |
routes = routes.split ', ' if typeof routes == 'string' | |
arr = [] | |
for route in routes | |
route = @router.apply_context route | |
arr.push route | |
@route = arr | |
console.log @route | |
# Call the action passing arguments to it | |
call: (args)-> | |
# for now we can call the action | |
result = true | |
# call the condition | |
if @condition | |
result = @condition.apply @, args | |
# if it returned false when can't call the action | |
false if ! result | |
# if we defined a callback to execute before the action | |
if @before_callback | |
# execute it passing the same arguments as the action | |
contents = @before_callback.apply @, args | |
# and if it returned some contents use it as | |
# the main action (then we can use "before_callback" to use route filters) | |
return contents if contents | |
# call the action callback and fetch the contents of it | |
contents = @callback.apply @, args | |
# if we defined some callback to execute after the main one | |
if @after_callback | |
# call it passing the returned content | |
@after_callback.apply @, [contents] | |
# Set a callback to execute before the action | |
before: (@before_callback)-> | |
@ | |
# Set a callback to execute after the action | |
after: (@after_callback)-> | |
@ | |
# Set a required condition to execute the action | |
when: (@condition)-> | |
@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment