├── .gitignore ├── Gruntfile.js ├── README.md ├── demoServer.js ├── demos ├── advanced │ ├── index.html │ ├── page2.html │ ├── page3.html │ ├── script.js │ └── style.css ├── basic │ ├── index.html │ ├── page2.html │ ├── page3.html │ ├── script.js │ └── style.css ├── jquery.pusher.js └── jquery.pusher.min.js ├── jquery-pusher.jquery.json ├── jquery.pusher.clean.js ├── jquery.pusher.js ├── jquery.pusher.min.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | lib-cov 4 | *.seed 5 | *.log 6 | *.csv 7 | *.dat 8 | *.out 9 | *.pid 10 | *.gz 11 | 12 | pids 13 | logs 14 | results 15 | 16 | npm-debug.log 17 | 18 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | jshint: { 7 | options: { 8 | browser: true 9 | }, 10 | all: ['jquery.pusher.js'] 11 | }, 12 | removelogging: { 13 | dist: { 14 | src: "jquery.pusher.js", 15 | dest: "jquery.pusher.clean.js" 16 | }, 17 | options: { 18 | namespace: 'window.console' 19 | } 20 | }, 21 | uglify: { 22 | minify: { 23 | files: { 24 | 'jquery.pusher.min.js': ['jquery.pusher.clean.js'] 25 | } 26 | }, 27 | options: { 28 | banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %>\nhttps://github.com/salvan13/jquery-pusher\nOriginal author: Antonio Salvati - @salvan13 - salvan13@gmail.com\nLicensed under the MIT license\n */\n' 29 | } 30 | }, 31 | copy: { 32 | main: { 33 | files: [ 34 | {expand: true, src: ['jquery.pusher.js'], dest: 'demos'}, 35 | {expand: true, src: ['jquery.pusher.min.js'], dest: 'demos'} 36 | ] 37 | } 38 | } 39 | }); 40 | 41 | grunt.loadNpmTasks('grunt-contrib-jshint'); 42 | grunt.loadNpmTasks('grunt-contrib-uglify'); 43 | grunt.loadNpmTasks('grunt-contrib-copy'); 44 | grunt.loadNpmTasks("grunt-remove-logging"); 45 | 46 | // Default task. 47 | grunt.registerTask('default', ['jshint', 'removelogging', 'uglify', 'copy']); 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jquery pusher plugin 2 | ================= 3 | 4 | Enable HTML5 History navigation in your web site easly. 5 | 6 | This plugin aims to enable the HTML5 navigation in sites without having to change anything server side. If the browser does not support HTML5 no fallback is provided, the site will be simply browsed in the old way. 7 | 8 | ###Basic usage 9 | ```js 10 | $("#menu").pusher({ 11 | handler: function() { 12 | this.updateText("title"); 13 | this.updateHtml("#content"); 14 | } 15 | }); 16 | ``` 17 | 18 | ###Demo 19 | [Basic][1] and [Advanced][2] 20 | 21 | ###Options 22 | Option | Dafault | Note 23 | --- | --- | --- 24 | handler | noop | function that defines the plugin main behavior, executed after the page load, if no errors occur 25 | before | `function(done) { done(); }` | function executed before ajax call that loads the page. **IMPORTANT**: the `done` function must be called, otherwise the execution does not continuous 26 | after | noop | function executed after the page load, everytime 27 | fail | `window.alert("Failed to load " + this.state.path);` | function executed after the page load, if errors occur 28 | watch | `"a"`| watched elements 29 | initialPath | `window.location.pathname` | first state path 30 | onStateCreation | noop | function executed everytime when new state is created, takes as parameters: the new state and the clicked element (if exists) , can be used to add additional values to the state 31 | 32 | ###Context 33 | In `handler`, `after`, `fail` and `before` function you can access the context with `this`. 34 | It contains: 35 | 36 | 1. `state` object: the current state 37 | 2. `get` function: get elements from the loaded page (if exists) 38 | 3. `updateText` function: replace text of the given selector from the loaded page to the actual page 39 | 4. `updateHtml` function: replace contents of the given selector from the loaded page to the actual page 40 | 41 | LICENSE 42 | --------- 43 | 44 | Copyright 2013 Antonio Salvati 45 | 46 | Released under the MIT License. 47 | 48 | 49 | [1]: http://www.antoniosalvati.it/public/jquery-pusher/demos/basic/ 50 | [2]: http://www.antoniosalvati.it/public/jquery-pusher/demos/advanced/ 51 | 52 | 53 | -------------------------------------------------------------------------------- /demoServer.js: -------------------------------------------------------------------------------- 1 | var connect = require('connect') 2 | , http = require('http'); 3 | 4 | var app = connect() 5 | .use(connect.static('demos')) 6 | .use(connect.directory('demos')); 7 | 8 | 9 | var port = 3000; 10 | http.createServer(app).listen(port); 11 | console.log('running on http://127.0.0.1:' + port + '/'); 12 | -------------------------------------------------------------------------------- /demos/advanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |
22 |

Mel ex consul scripta scribentur. Pro no debet putent regione. No sea labore contentiones intellegebat, ne mei laudem persius percipitur. Eum at argumentum scripserit, quo eu idque deleniti. Velit aeterno an sea, ex tation repudiare sea.
Pri wisi dicant accommodare in. Elitr argumentum ne ius, no tamquam sententiae qui. Vix aeque feugiat qualisque in, et pri wisi assueverit. Prima verterem appellantur at mea, elit iuvaret ut mea. Eam tale tantas tibique cu, ex novum doctus docendi pri. Ad saperet dolorum quo, qui albucius delicata an.
Enim habeo forensibus te usu, at sed sint invenire. Eu vel modus copiosae. Minim simul tollit eum at, et dicam singulis definitionem duo, no dolore periculis laboramus nec. Harum splendide ut vix, te vel accusam suavitate vituperatoribus, at usu eleifend complectitur. Tritani laboramus in mea. Quod tibique scaevola sit ei, mei wisi mucius discere an, per iisque facilis voluptua ut.

23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /demos/advanced/page2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page 2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |
22 |

back to index
external link
Libera resultato linguistas que o, veni laborava ha con, sed unic etiam internet da. Da iste europee excellente del. Instruite excellente non de, non in esser dictionario, ha sia union personas grammatica. Mundial summario su nos. Il brevissime linguistas intermediari que.
Le ultra westeuropee association uno, uno language intermediari su. Se uno latente ascoltar articulos, su iste terra cinque duo. Uno membros anglo-romanic de. Uso tentation anteriormente immediatemente in, al uso servi flexione. Pan toto sine contos su, sed tote prime denomination un, con un gode cadeva disuso.
Servi anglese le del, al titulo europa historiettas via, lo del scriber hereditage incorporate. De sitos parlar commun per, qui nostre effortio denominator de. Tu via durante appellate articulos, duo terra europee scientia ma. Duo le ultra language immediatemente. Malo como esser il qui, non capital language linguistic de.

23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /demos/advanced/page3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page 3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |
22 |

Jesio agona kayasada ila co, udeba sucon igoyo zu dun, hun line kozan emenna ma. Sucan pazocan ta fin, para renni conba dun di, tu ureli akizu mon. Uci du kozan apakan kinyaraji, ade zi tece keni hucada, keni genni zi ura. Sane unadi conba zi abu. Poli lakana sogane bia te, aci zu ruta azucio.
Ite ta lakana finyuri, veca jakine ura hu. Dulo kayasada bar ni. Ruba unama malen men je, te via tenka gasin amubi, uci huka bona jesio ri. Vi pecin malen ipe, on itone vadiri ine, fuga lasin atasada ire pe.
Je ruta boro urekada hin, dun ni zaga rima imagi. Uci ri adda utegin. Via dalen zovan apakan on. Akali sogane ma sun, puro udara tan ne, puro itone apa du.
Lana jenmo du via. Xen du nefida melangi. Kun ni keya ranin aletayo. Te ruba zofi aletayo ena, kon huro fuga adda pe. Goyo lire zenga pe vin.

23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /demos/advanced/script.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | 3 | $(document).pusher({ 4 | 5 | //watch on all 'a' in the document excpet external links 6 | watch: "a:not([href^='http'])", 7 | 8 | before: function(done) { 9 | //show loading before page load 10 | showLoading(done); 11 | }, 12 | after: function() { 13 | //hide loading when the page is loaded 14 | hideLoading(); 15 | }, 16 | handler: function() { 17 | //update the page title 18 | this.updateText("title"); 19 | 20 | //update the menu 21 | this.updateHtml("#menu"); 22 | 23 | //slide effect to show the loaded content 24 | slide(this.get("#content").contents()); 25 | }, 26 | fail: function() { 27 | //slide effect to show the problem 28 | slide("

Oops... failed to load page " + this.state.path + "

"); 29 | }, 30 | onStateCreation: function(state, elem) { 31 | //add some data to the state (we access that data in handler, after and fail in this.state ) 32 | var data = {}; 33 | if(elem) { 34 | data.mainMenu = elem.closest('#menu').length > 0; 35 | } 36 | state.myData = data; 37 | } 38 | }); 39 | 40 | 41 | //non related plugin functions 42 | 43 | var loading = $("
").attr("id", "loading").text("Loading...").hide(); 44 | $("body").append(loading); 45 | 46 | var showLoading = function(done) { 47 | $("#loading").fadeIn(function() { 48 | done(); 49 | }); 50 | }; 51 | 52 | var hideLoading = function() { 53 | $("#loading").fadeOut(); 54 | }; 55 | 56 | var slide = function(content) { 57 | var cnt = $("#content"); 58 | var next = $("#next"); 59 | next = next.length ? next : $("
").attr("id", "next"); 60 | next.html(content); 61 | next.insertAfter(cnt); 62 | next.animate({left: 0}, function(){ 63 | cnt.remove(); 64 | next.attr("id", "content"); 65 | }); 66 | 67 | }; 68 | 69 | }); 70 | -------------------------------------------------------------------------------- /demos/advanced/style.css: -------------------------------------------------------------------------------- 1 | * { box-sizing: border-box } 2 | 3 | #menu { 4 | float: left; 5 | width: 200px; 6 | } 7 | 8 | #wrapper { 9 | float: left; 10 | width: 500px; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | #content, #next { 16 | float: left; 17 | width: 500px; 18 | } 19 | 20 | #next { 21 | position: absolute; 22 | left: 500px; 23 | } 24 | 25 | #content > p, #next > p { 26 | padding: 20px; 27 | height: 400px; 28 | overflow: auto; 29 | } 30 | 31 | .index { 32 | background: #CCC; 33 | } 34 | 35 | .page2 { 36 | background: #992; 37 | } 38 | 39 | .page3 { 40 | background: #285; 41 | } 42 | 43 | .error { 44 | background: #881C1C; 45 | color: white; 46 | } 47 | 48 | #loading { 49 | background: #D73939; 50 | color: white; 51 | display: none; 52 | left: 210px; 53 | padding: 4px; 54 | position: fixed; 55 | top: 12px; 56 | } 57 | 58 | a { 59 | color: #3111EE; 60 | text-decoration: none; 61 | } 62 | 63 | a.active, a:hover { 64 | text-decoration: underline; 65 | } 66 | -------------------------------------------------------------------------------- /demos/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |

Index

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /demos/basic/page2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page 2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |

Page 2

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /demos/basic/page3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page 3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 |
21 |

Page 3

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /demos/basic/script.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | 3 | $("#menu").pusher({ 4 | handler: function() { 5 | this.updateText("title"); 6 | this.updateHtml("#content"); 7 | } 8 | }); 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /demos/basic/style.css: -------------------------------------------------------------------------------- 1 | #menu { 2 | float: left; 3 | width: 200px; 4 | } 5 | 6 | #content { 7 | float: left; 8 | width: 500px; 9 | } 10 | 11 | #content > p { 12 | padding: 20px; 13 | } 14 | 15 | .index { 16 | background: #CCC; 17 | } 18 | 19 | .page2 { 20 | background: #992; 21 | } 22 | 23 | .page3 { 24 | background: #285; 25 | } 26 | -------------------------------------------------------------------------------- /demos/jquery.pusher.js: -------------------------------------------------------------------------------- 1 | ;(function ( $, window, document ) { 2 | 3 | "use strict"; 4 | 5 | var pluginName = "pusher", 6 | defaults = { 7 | watch: "a", 8 | initialPath: window.location.pathname, 9 | before: function(done) { 10 | done(); 11 | }, 12 | handler: function() { 13 | }, 14 | after: function() { 15 | }, 16 | fail: function() { 17 | window.alert("Failed to load " + this.state.path); 18 | }, 19 | onStateCreation: function(state, elem) { 20 | } 21 | }; 22 | 23 | function Plugin(element, options) { 24 | this.element = element; 25 | this.options = $.extend({}, defaults, options); 26 | this._defaults = defaults; 27 | this._name = pluginName; 28 | this.init(); 29 | } 30 | 31 | Plugin.prototype = { 32 | 33 | init: function() { 34 | 35 | var self = this; 36 | 37 | if (!history.pushState) { 38 | return; 39 | } 40 | 41 | //create the initial state 42 | var initialState = createState({ 43 | path: self.options.initialPath 44 | }, self.options.onStateCreation); 45 | 46 | history.replaceState(initialState, null, initialState.path); 47 | 48 | //click event 49 | $(self.element).on('click', self.options.watch, function (e) { 50 | e.preventDefault(); 51 | 52 | var state = createState({ 53 | path: $(this).attr('href'), 54 | elem: $(this) 55 | }, self.options.onStateCreation); 56 | 57 | window.console.log("push", state); 58 | run(self, state, true); 59 | }); 60 | 61 | //popstate event 62 | window.addEventListener('popstate', function(e) { 63 | window.console.log("pop", e.state); 64 | run(self, e.state); 65 | }); 66 | 67 | } 68 | 69 | }; 70 | 71 | var createState = function(params, fn) { 72 | var state = {}; 73 | params = params || {}; 74 | state.path = params.path; 75 | state.time = new Date().getTime(); 76 | if(fn) { 77 | fn(state, params.elem); 78 | } 79 | return state; 80 | }; 81 | 82 | var run = function(plugin, state, push) { 83 | 84 | if(!state) { 85 | return; 86 | } 87 | 88 | window.console.log("run", state); 89 | 90 | var context = { 91 | state: state, 92 | get: function(query) { 93 | return get(context.res, query); 94 | }, 95 | updateText: function(query) { 96 | var el = $(query); 97 | this.get(query).each(function(i) { 98 | var txt = $(this).text(); 99 | el.eq(i).text(txt); 100 | }); 101 | }, 102 | updateHtml: function(query) { 103 | var el = $(query); 104 | this.get(query).each(function(i) { 105 | var cnt = $(this).contents(); 106 | el.eq(i).html(cnt); 107 | }); 108 | } 109 | }; 110 | 111 | var done = function() { 112 | $.ajax({ 113 | type: 'GET', 114 | url: state.path 115 | }).done(function (res) { 116 | context.res = res; 117 | if(push) { 118 | history.pushState(state, null, state.path); 119 | } 120 | plugin.options.handler.apply(context); 121 | }).fail(function () { 122 | plugin.options.fail.apply(context); 123 | }).always(function () { 124 | plugin.options.after.apply(context); 125 | }); 126 | }; 127 | 128 | plugin.options.before.apply(context, [done]); 129 | }; 130 | 131 | var get = function(data, query) { 132 | var html = $("").html(data); 133 | var res = html.find(query); 134 | window.console.log(res); 135 | return res; 136 | }; 137 | 138 | $.fn[pluginName] = function (options) { 139 | if (!$.data(document, "plugin_" + pluginName)) { 140 | $.data(document, "plugin_" + pluginName, new Plugin( this, options )); 141 | } 142 | }; 143 | 144 | })( jQuery, window, document ); 145 | -------------------------------------------------------------------------------- /demos/jquery.pusher.min.js: -------------------------------------------------------------------------------- 1 | /*! jquery-pusher 0.2.3 2013-07-21 2 | https://github.com/salvan13/jquery-pusher 3 | Original author: Antonio Salvati - @salvan13 - salvan13@gmail.com 4 | Licensed under the MIT license 5 | */ 6 | (function(t,n,e){"use strict";function i(n,e){this.element=n,this.options=t.extend({},o,e),this._defaults=o,this._name=a,this.init()}var a="pusher",o={watch:"a",initialPath:n.location.pathname,before:function(t){t()},handler:function(){},after:function(){},fail:function(){n.alert("Failed to load "+this.state.path)},onStateCreation:function(){}};i.prototype={init:function(){var e=this;if(history.pushState){var i=r({path:e.options.initialPath},e.options.onStateCreation);history.replaceState(i,null,i.path),t(e.element).on("click",e.options.watch,function(n){n.preventDefault();var i=r({path:t(this).attr("href"),elem:t(this)},e.options.onStateCreation);s(e,i,!0)}),n.addEventListener("popstate",function(t){s(e,t.state)})}}};var r=function(t,n){var e={};return t=t||{},e.path=t.path,e.time=(new Date).getTime(),n&&n(e,t.elem),e},s=function(n,e,i){if(e){var a={state:e,get:function(t){return u(a.res,t)},updateText:function(n){var e=t(n);this.get(n).each(function(n){var i=t(this).text();e.eq(n).text(i)})},updateHtml:function(n){var e=t(n);this.get(n).each(function(n){var i=t(this).contents();e.eq(n).html(i)})}},o=function(){t.ajax({type:"GET",url:e.path}).done(function(t){a.res=t,i&&history.pushState(e,null,e.path),n.options.handler.apply(a)}).fail(function(){n.options.fail.apply(a)}).always(function(){n.options.after.apply(a)})};n.options.before.apply(a,[o])}},u=function(n,e){var i=t("").html(n),a=i.find(e);return a};t.fn[a]=function(n){t.data(e,"plugin_"+a)||t.data(e,"plugin_"+a,new i(this,n))}})(jQuery,window,document); -------------------------------------------------------------------------------- /jquery-pusher.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-pusher", 3 | "title": "jQuery Pusher Plugin", 4 | "description": "This plugin aims to enable the HTML5 navigation in sites without having to change anything server side. If the browser does not support HTML5 no fallback is provided, the site will be simply browsed in the old way.", 5 | "version": "0.2.3", 6 | "keywords": ["ajax", "navigation", "history", "pushstate"], 7 | "homepage": "https://github.com/salvan13/jquery-pusher", 8 | "docs": "https://github.com/salvan13/jquery-pusher/blob/master/README.md", 9 | "demo": "http://www.antoniosalvati.it/public/jquery-pusher/demos/advanced/index.html", 10 | "bugs": "https://github.com/salvan13/jquery-pusher/issues", 11 | "author": { 12 | "name": "Antonio Salvati", 13 | "url": "http://www.antoniosalvati.it/" 14 | }, 15 | "licenses": [ 16 | { 17 | "type": "MIT", 18 | "url": "http://gilmoreorless.mit-license.org/2011/" 19 | } 20 | ], 21 | "dependencies": { 22 | "jquery": ">=1.7" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jquery.pusher.clean.js: -------------------------------------------------------------------------------- 1 | ;(function ( $, window, document ) { 2 | 3 | "use strict"; 4 | 5 | var pluginName = "pusher", 6 | defaults = { 7 | watch: "a", 8 | initialPath: window.location.pathname, 9 | before: function(done) { 10 | done(); 11 | }, 12 | handler: function() { 13 | }, 14 | after: function() { 15 | }, 16 | fail: function() { 17 | window.alert("Failed to load " + this.state.path); 18 | }, 19 | onStateCreation: function(state, elem) { 20 | } 21 | }; 22 | 23 | function Plugin(element, options) { 24 | this.element = element; 25 | this.options = $.extend({}, defaults, options); 26 | this._defaults = defaults; 27 | this._name = pluginName; 28 | this.init(); 29 | } 30 | 31 | Plugin.prototype = { 32 | 33 | init: function() { 34 | 35 | var self = this; 36 | 37 | if (!history.pushState) { 38 | return; 39 | } 40 | 41 | //create the initial state 42 | var initialState = createState({ 43 | path: self.options.initialPath 44 | }, self.options.onStateCreation); 45 | 46 | history.replaceState(initialState, null, initialState.path); 47 | 48 | //click event 49 | $(self.element).on('click', self.options.watch, function (e) { 50 | e.preventDefault(); 51 | 52 | var state = createState({ 53 | path: $(this).attr('href'), 54 | elem: $(this) 55 | }, self.options.onStateCreation); 56 | 57 | 58 | run(self, state, true); 59 | }); 60 | 61 | //popstate event 62 | window.addEventListener('popstate', function(e) { 63 | 64 | run(self, e.state); 65 | }); 66 | 67 | } 68 | 69 | }; 70 | 71 | var createState = function(params, fn) { 72 | var state = {}; 73 | params = params || {}; 74 | state.path = params.path; 75 | state.time = new Date().getTime(); 76 | if(fn) { 77 | fn(state, params.elem); 78 | } 79 | return state; 80 | }; 81 | 82 | var run = function(plugin, state, push) { 83 | 84 | if(!state) { 85 | return; 86 | } 87 | 88 | 89 | 90 | var context = { 91 | state: state, 92 | get: function(query) { 93 | return get(context.res, query); 94 | }, 95 | updateText: function(query) { 96 | var el = $(query); 97 | this.get(query).each(function(i) { 98 | var txt = $(this).text(); 99 | el.eq(i).text(txt); 100 | }); 101 | }, 102 | updateHtml: function(query) { 103 | var el = $(query); 104 | this.get(query).each(function(i) { 105 | var cnt = $(this).contents(); 106 | el.eq(i).html(cnt); 107 | }); 108 | } 109 | }; 110 | 111 | var done = function() { 112 | $.ajax({ 113 | type: 'GET', 114 | url: state.path 115 | }).done(function (res) { 116 | context.res = res; 117 | if(push) { 118 | history.pushState(state, null, state.path); 119 | } 120 | plugin.options.handler.apply(context); 121 | }).fail(function () { 122 | plugin.options.fail.apply(context); 123 | }).always(function () { 124 | plugin.options.after.apply(context); 125 | }); 126 | }; 127 | 128 | plugin.options.before.apply(context, [done]); 129 | }; 130 | 131 | var get = function(data, query) { 132 | var html = $("").html(data); 133 | var res = html.find(query); 134 | 135 | return res; 136 | }; 137 | 138 | $.fn[pluginName] = function (options) { 139 | if (!$.data(document, "plugin_" + pluginName)) { 140 | $.data(document, "plugin_" + pluginName, new Plugin( this, options )); 141 | } 142 | }; 143 | 144 | })( jQuery, window, document ); 145 | -------------------------------------------------------------------------------- /jquery.pusher.js: -------------------------------------------------------------------------------- 1 | ;(function ( $, window, document ) { 2 | 3 | "use strict"; 4 | 5 | var pluginName = "pusher", 6 | defaults = { 7 | watch: "a", 8 | initialPath: window.location.pathname, 9 | before: function(done) { 10 | done(); 11 | }, 12 | handler: function() { 13 | }, 14 | after: function() { 15 | }, 16 | fail: function() { 17 | window.alert("Failed to load " + this.state.path); 18 | }, 19 | onStateCreation: function(state, elem) { 20 | } 21 | }; 22 | 23 | function Plugin(element, options) { 24 | this.element = element; 25 | this.options = $.extend({}, defaults, options); 26 | this._defaults = defaults; 27 | this._name = pluginName; 28 | this.init(); 29 | } 30 | 31 | Plugin.prototype = { 32 | 33 | init: function() { 34 | 35 | var self = this; 36 | 37 | if (!history.pushState) { 38 | return; 39 | } 40 | 41 | //create the initial state 42 | var initialState = createState({ 43 | path: self.options.initialPath 44 | }, self.options.onStateCreation); 45 | 46 | history.replaceState(initialState, null, initialState.path); 47 | 48 | //click event 49 | $(self.element).on('click', self.options.watch, function (e) { 50 | e.preventDefault(); 51 | 52 | var state = createState({ 53 | path: $(this).attr('href'), 54 | elem: $(this) 55 | }, self.options.onStateCreation); 56 | 57 | window.console.log("push", state); 58 | run(self, state, true); 59 | }); 60 | 61 | //popstate event 62 | window.addEventListener('popstate', function(e) { 63 | window.console.log("pop", e.state); 64 | run(self, e.state); 65 | }); 66 | 67 | } 68 | 69 | }; 70 | 71 | var createState = function(params, fn) { 72 | var state = {}; 73 | params = params || {}; 74 | state.path = params.path; 75 | state.time = new Date().getTime(); 76 | if(fn) { 77 | fn(state, params.elem); 78 | } 79 | return state; 80 | }; 81 | 82 | var run = function(plugin, state, push) { 83 | 84 | if(!state) { 85 | return; 86 | } 87 | 88 | window.console.log("run", state); 89 | 90 | var context = { 91 | state: state, 92 | get: function(query) { 93 | return get(context.res, query); 94 | }, 95 | updateText: function(query) { 96 | var el = $(query); 97 | this.get(query).each(function(i) { 98 | var txt = $(this).text(); 99 | el.eq(i).text(txt); 100 | }); 101 | }, 102 | updateHtml: function(query) { 103 | var el = $(query); 104 | this.get(query).each(function(i) { 105 | var cnt = $(this).contents(); 106 | el.eq(i).html(cnt); 107 | }); 108 | } 109 | }; 110 | 111 | var done = function() { 112 | $.ajax({ 113 | type: 'GET', 114 | url: state.path 115 | }).done(function (res) { 116 | context.res = res; 117 | if(push) { 118 | history.pushState(state, null, state.path); 119 | } 120 | plugin.options.handler.apply(context); 121 | }).fail(function () { 122 | plugin.options.fail.apply(context); 123 | }).always(function () { 124 | plugin.options.after.apply(context); 125 | }); 126 | }; 127 | 128 | plugin.options.before.apply(context, [done]); 129 | }; 130 | 131 | var get = function(data, query) { 132 | var html = $("").html(data); 133 | var res = html.find(query); 134 | window.console.log(res); 135 | return res; 136 | }; 137 | 138 | $.fn[pluginName] = function (options) { 139 | if (!$.data(document, "plugin_" + pluginName)) { 140 | $.data(document, "plugin_" + pluginName, new Plugin( this, options )); 141 | } 142 | }; 143 | 144 | })( jQuery, window, document ); 145 | -------------------------------------------------------------------------------- /jquery.pusher.min.js: -------------------------------------------------------------------------------- 1 | /*! jquery-pusher 0.2.3 2013-07-21 2 | https://github.com/salvan13/jquery-pusher 3 | Original author: Antonio Salvati - @salvan13 - salvan13@gmail.com 4 | Licensed under the MIT license 5 | */ 6 | (function(t,n,e){"use strict";function i(n,e){this.element=n,this.options=t.extend({},o,e),this._defaults=o,this._name=a,this.init()}var a="pusher",o={watch:"a",initialPath:n.location.pathname,before:function(t){t()},handler:function(){},after:function(){},fail:function(){n.alert("Failed to load "+this.state.path)},onStateCreation:function(){}};i.prototype={init:function(){var e=this;if(history.pushState){var i=r({path:e.options.initialPath},e.options.onStateCreation);history.replaceState(i,null,i.path),t(e.element).on("click",e.options.watch,function(n){n.preventDefault();var i=r({path:t(this).attr("href"),elem:t(this)},e.options.onStateCreation);s(e,i,!0)}),n.addEventListener("popstate",function(t){s(e,t.state)})}}};var r=function(t,n){var e={};return t=t||{},e.path=t.path,e.time=(new Date).getTime(),n&&n(e,t.elem),e},s=function(n,e,i){if(e){var a={state:e,get:function(t){return u(a.res,t)},updateText:function(n){var e=t(n);this.get(n).each(function(n){var i=t(this).text();e.eq(n).text(i)})},updateHtml:function(n){var e=t(n);this.get(n).each(function(n){var i=t(this).contents();e.eq(n).html(i)})}},o=function(){t.ajax({type:"GET",url:e.path}).done(function(t){a.res=t,i&&history.pushState(e,null,e.path),n.options.handler.apply(a)}).fail(function(){n.options.fail.apply(a)}).always(function(){n.options.after.apply(a)})};n.options.before.apply(a,[o])}},u=function(n,e){var i=t("").html(n),a=i.find(e);return a};t.fn[a]=function(n){t.data(e,"plugin_"+a)||t.data(e,"plugin_"+a,new i(this,n))}})(jQuery,window,document); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-pusher", 3 | "version": "0.2.3", 4 | "devDependencies": { 5 | "grunt": "~0.4.0", 6 | "grunt-contrib-jshint": "~0.1.1", 7 | "grunt-contrib-uglify": "~0.1.1", 8 | "connect": "~2.7.11", 9 | "grunt-contrib-copy": "~0.4.1", 10 | "grunt-remove-logging": "~0.1.1" 11 | } 12 | } 13 | --------------------------------------------------------------------------------