Created
August 15, 2011 21:34
-
-
Save psaia/1147926 to your computer and use it in GitHub Desktop.
A framework for creating single page JavaScript apps easily.
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
/* | |
Author: Pete Saia | |
*/ | |
/* Configuration | |
The name of the property should match the view (<section>) | |
ID. The route is the desired hash URI. The controller will be | |
called upon displaying the section html. For the route do | |
not add a leading or trailing slash. | |
Example: | |
firstsegment/secondsegment | |
To link to a page just create an anchor with the "rel" | |
attribute set to "nofollow" and the href with the name | |
of the desired property which is also the div of the | |
desired section. You can make use of parameters by using | |
the pipe symbol "|". That's it. | |
Example: | |
<a href="roundtable_target_audiences" rel="internal">Foo</a> | |
Initiate with: | |
var BOOTSTRAP = { | |
'config': { | |
container_selector: '#main', | |
view_selector: 'section' | |
}, | |
'default': { | |
default_view: 'home', // View to load when there is no hash. | |
route: '', | |
controller: function () { | |
// Some functions. | |
} | |
}, | |
'controllers': { | |
'home': { | |
route: 'home', | |
controller: function () { | |
// Some functions. | |
} | |
}, | |
'portfolio': { | |
route: 'portfolio', | |
controller: function () { | |
// Some other functions. | |
} | |
}, | |
'portfolio_photography': { | |
route: 'portfolio/photography', | |
controller: function () { | |
// Some more functions. | |
} | |
}, | |
} | |
}; | |
// Start. | |
$(function () { | |
var heroApp = new Hero(BOOTSTRAP); | |
}); | |
-----------------------------------------------------------*/ | |
/* Hero | |
* | |
* Make single page JavaScript apps like a hero. | |
* Author: Pete Saia | |
* | |
* hero.js | |
------------------------------------------------*/ | |
var Hero = function (bs) { | |
// Load bootstrap. | |
this.bootstrap = bs; | |
// Assign DOM elements. | |
this.container = this.bootstrap['config'].container_selector; | |
this.$views = $(this.container).find(this.bootstrap['config'].view_selector); | |
// Start. | |
this.init(); | |
this.bind_links(); | |
}; | |
/* | |
* Initiate. | |
* @return void | |
*/ | |
Hero.prototype.init = function (page) { | |
var that = this; | |
// Remove views from DOM. | |
this.$views.remove(); | |
// This is using the hashchange plugin for browser history. | |
jQuery(window).hashchange(function(e) { | |
that.load(that._is_view(that._get_hash(), 'uri')); | |
}); | |
// Manual trigger load. | |
this.load(that._is_view(that._get_hash(), 'uri')); | |
}; | |
/* | |
* Handle links. | |
* @return void | |
*/ | |
Hero.prototype.bind_links = function () { | |
var that = this; | |
$('a[rel="nofollow"]').live('click', function () { | |
var prop = $(this).attr('href'); | |
// If the link is valid change the hash which will cause the page | |
// to change via hashchange(). | |
if (that._is_view(prop, 'property')) { | |
that._set_hash(that.bootstrap['controllers'][prop].route); | |
} else { | |
if (window.console) { | |
console.log('Property name is not valid.'); | |
} | |
} | |
return false; | |
}); | |
}; | |
/* | |
* Display a specific section based on route property. | |
* @return void | |
*/ | |
Hero.prototype.load = function (page) { | |
if (page.length > 0 && page !== 'default') { | |
this._display_view(page, this.bootstrap['controllers'][page].controller); | |
} else { | |
// Show default page, load default_view and default controller. | |
this._display_view(this.bootstrap['default'].default_view, this.bootstrap['default'].controller); | |
} | |
}; | |
/* | |
* Check if hash URI or property name is valid. | |
* @return false or the name of the page property (page id) | |
*/ | |
Hero.prototype._is_view = function (str, type) { | |
var property_name = false, | |
route_str = ''; | |
if (type === 'uri') { | |
for (prop in this.bootstrap['controllers']) { | |
route_str = this.bootstrap['controllers'][prop].route; | |
// Dealing with parameter, so remove it. | |
if (-str.indexOf('|')) { | |
str = str.replace(/\|.*/, ''); | |
} | |
// Check if route exists in bootstrap. | |
if (route_str === str) { | |
property_name = prop; | |
break; | |
} | |
} | |
} else if (type === 'property') { | |
for (prop in this.bootstrap['controllers']) { | |
// Check if property exists in bootstrap. | |
if (prop === str) { | |
property_name = prop; | |
break; | |
} | |
} | |
} | |
return property_name; | |
}; | |
/* | |
* Display HTML | |
* @return void | |
*/ | |
Hero.prototype._display_view = function (div_id, callback) { | |
var that = this, | |
$current_div = $(this.container).find(this.bootstrap['config'].view_selector); | |
if ($current_div.length > 0 && $current_div.attr('id') !== div_id) { | |
// Remove the old, insert the new. | |
$current_div.fadeOut('fast', function () { | |
$(this).remove(); | |
that.$views.each(function () { | |
if ($(this).attr('id') === div_id) { | |
$(that.container).append($(this)); | |
$(this).fadeIn('fast'); | |
$(this).css('opacity', '1'); | |
$('body').attr('id', 'section_' + div_id); | |
callback(); | |
} | |
}); | |
}); | |
} else { | |
// There is no old so just insert the new. | |
this.$views.each(function () { | |
if ($(this).attr('id') === div_id) { | |
$(that.container).append($(this)); | |
$(this).fadeIn('fast'); | |
$('body').attr('id', 'section_' + div_id); | |
callback(); | |
} | |
}); | |
} | |
}; | |
/* | |
* Get the current hash uri. | |
* @return string | |
*/ | |
Hero.prototype._get_hash = function () { | |
var str = ''; | |
// If there is a hash. | |
if (window.location.hash) { | |
// Trim and remove hash. | |
str = $.trim(window.location.hash.replace('#', '')); | |
// Remove leading and trailing slash. | |
str = str.replace(/^\/|\/$/g, ''); | |
} | |
return str; | |
}; | |
/* | |
* Set new hash. | |
* @return void | |
*/ | |
Hero.prototype._set_hash = function (str) { | |
// Add hash. | |
window.location.hash = '/' + str; | |
}; | |
/* Hero | |
* Start sample app. | |
------------------------------------------------*/ | |
var BOOTSTRAP = { | |
// Interface configurations. | |
'config': { | |
container_selector: '#main', | |
view_selector: 'section' | |
}, | |
// The default landing page with no hash. | |
'default': { | |
default_view: 'home', // View to load when there is no hash. | |
route: '', | |
controller: function () { | |
splash_lbox(); | |
cycle_diagram(); | |
indicator('hide'); | |
} | |
}, | |
// Normal views. Methods coming from page-methods.js. | |
'controllers': { | |
'home': { | |
route: 'home', | |
controller: function () { | |
cycle_diagram(); | |
indicator('hide'); | |
} | |
}, | |
'roundtable': { | |
route: 'roundtable', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'roundtable_target_audiences': { | |
route: 'roundtable/target-audiences', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'roundtable_validators': { | |
route: 'roundtable/network-of-validators', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'roundtable_topics': { | |
route: 'roundtable/topic-areas', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'roundtable_content_types': { | |
route: 'roundtable/content-types', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'news': { | |
route: 'news', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'news_nyt': { | |
route: 'news/nyt-study', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp': { | |
route: 'news/foreign_press-study', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp_1': { | |
route: 'news/foreign_press-study|1', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp_2': { | |
route: 'news/foreign_press-study|2', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp_3': { | |
route: 'news/foreign_press-study|3', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp_4': { | |
route: 'news/foreign_press-study|4', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'news_fp_5': { | |
route: 'news/foreign_press-study|5', | |
controller: function () { | |
indicator('show'); | |
carousel(); | |
} | |
}, | |
'sharing': { | |
route: 'sharing', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'sharing_content': { | |
route: 'sharing/content', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'sharing_nyt': { | |
route: 'sharing/nyt', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
'sharing_google': { | |
route: 'sharing/google', | |
controller: function () { | |
indicator('show'); | |
} | |
}, | |
} | |
}; | |
$(function () { | |
// Go. | |
new Hero(BOOTSTRAP); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment