andrew4582

site.spa.js

Apr 12th, 2012
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ///<reference path="~/Scripts/jquery-1.5.1-vsdoc.js" />
  2. /*
  3. Single Page Application scripts
  4.  
  5. $.spa(); // calls the init method with default options
  6.  
  7. $.spa({  // calls the init method with custom options
  8.     cache:true,
  9.     linkSelector : "a.mylink",
  10.     loadIntoSelector: "#mycontent",
  11.     beforeload: function(element,url) {
  12.         $("#mystatus").show();
  13.     },
  14.     error: function (element, url, status,errorThrown, xhr) {
  15.         element.html("Opps, an error: " + errorThrown);
  16.     },
  17.     afterload: function(element,url,response, status, xhr) {
  18.         $("#mystatus").hide();
  19.     }
  20. });
  21. */
  22. (function ($) {
  23.    
  24.     var settings = {
  25.         initialUrl: null,       /* The url that get's called when page loads for the first time*/
  26.         cache: false,            /* If true, the html is cached for all requests*/
  27.         ajaxCache: true,       /* Sets jquery's ajax cache setting, default is 'false'*/
  28.         ajaxType: "GET",        /* Sets jquery's ajax method type setting,default is 'GET'*/
  29.         debug: false,            /* If true, debug statements are written to the console*/
  30.         enabled: true,          /* If false, spa will not request anything*/
  31.         loadIntoSelector: "#content",   /* The element id or jquery selector statement that the request contents will be loaded into*/
  32.         linkSelector: ".app-link",      /* The element id or jquery selector statement that spa will subscribe to it's 'click' event to perform the request*/
  33.         beforeload: function (element, url) { return true; }, /* Fired before each request, return false to stop the request*/
  34.         afterload: function (element, url, response, status, xhr) { }, /* Fired after each request*/
  35.         error: function (element, url, status, errorThrown, xhr) { },  /* Fired after when an the request returns an error*/
  36.         settitle: function (element, url, title) { /* Fired after each request, return a string value to set the document's title*/
  37.             return title;
  38.         }
  39.     };
  40.  
  41.     /*Debug utility*/
  42.     function debug(msg) {
  43.         if (!settings.debug) return;
  44.        
  45.        
  46.  
  47.         if (window._debug) {
  48.             _debug(msg);
  49.         }
  50.         else {
  51.             if (window.console)
  52.                 if (window.console.debug)
  53.                     window.console.debug(msg);
  54.         }
  55.  
  56.     };
  57.  
  58.     var impl = {};
  59.  
  60.     impl = {
  61.         cache: new spaHash(),
  62.         /*Return's the url with a query string that will return a fresh request*/
  63.         cacheifyurl: function (url) {
  64.             if (url.indexOf("?") === -1) {
  65.                 url += "?";
  66.             } else {
  67.                 url += "&";
  68.             }
  69.             url += "t=_" + new Date().getTime();
  70.             return url;
  71.         },
  72.  
  73.         /*The object list of url's not to load, used for custom requests*/
  74.         noloads: new spaHash(),
  75.  
  76.         /*A hash of url/button elements to track and modifiy the ui for each request, basically to change the button states*/
  77.         buttons: new spaHash(),
  78.  
  79.         urlcache: new spaHash(),
  80.         notcached: new spaHash(),
  81.         currentreq: new spaHash(),
  82.     };
  83.  
  84.     impl.methods = {
  85.  
  86.         /*Initialization method,fires when the page loads up*/
  87.         init: function (options) {
  88.  
  89.             if (options) {
  90.                 $.extend(settings, options);
  91.             }
  92.  
  93.             debug("spa->init(): settings -> " + JSON.stringify(settings));
  94.  
  95.             var buttonLinkSelector = settings.linkSelector || "a.app-link";
  96.             $(buttonLinkSelector).each(function () {
  97.                 var ele = $(this);
  98.                 var url = ele.attr('data-href');
  99.  
  100.                 impl.methods.addUIButton(url, ele);
  101.             });
  102.  
  103.             /*find and add the urls to 'urlcache' list that have an attribute of 'cachereq = 1' */
  104.             $("*[cachereq='1']").each(function () {
  105.                 var ele = $(this);
  106.                 var url = ele.attr('data-href');
  107.                 impl.urlcache.setItem(url, ele);
  108.                 debug("button cache : " + ele.attr('id'));
  109.             });
  110.  
  111.             /*find and add the urls to 'notcached' list that have an attribute of 'cachereq = 0' */
  112.             $("*[cachereq='0']").each(function () {
  113.                 var ele = $(this);
  114.                 var url = ele.attr('data-href');
  115.                 impl.notcached.setItem(url, ele);
  116.                 debug("ignore cache : " + ele.attr('id'));
  117.             });
  118.  
  119.  
  120.             /*subscribe to each link/button 'click' event*/
  121.             $(buttonLinkSelector).live('click', function (e) {
  122.                
  123.                 var url = $(this).attr('data-href');
  124.                 var datacache = $(this).attr('data-cache');
  125.                 var cachereq = $(this).attr('cachereq');
  126.  
  127.                 debug("spa-> click() " + url);
  128.  
  129.                 impl.methods.load(url,null,cachereq);
  130.                 e.preventDefault();
  131.  
  132.             });
  133.  
  134.             /*attach to the $.history initilize callback*/
  135.             $.history.init(function (url) {
  136.                 impl.methods.loadElement(url);
  137.             });
  138.         },
  139.  
  140.         /*Loads a url and tracks the history*/
  141.         load: function (url, onload,cachereq) {
  142.  
  143.             if (!settings.enabled)
  144.                 return;
  145.  
  146.             if(cachereq === null){
  147.                 cachereq = cachereq || settings.cache;
  148.             }
  149.  
  150.             debug("load()-> cachereq: " + cachereq);
  151.  
  152.             if (onload) {
  153.                 if (impl.noloads.hasItem(url)) {
  154.                     onload(url, settings);
  155.                     debug("spa->load() hasItem  [true] -> " + url);
  156.                     return;
  157.                 }
  158.                 impl.noloads.setItem(url, onload);
  159.                 debug("spa->load() noloads " + url);
  160.             }
  161.             else {
  162.                 var notcached = impl.notcached.getItem(url);
  163.                 if (notcached != null) {
  164.                     debug("spa->load() NOT CACHED url: " + url);
  165.                     impl.methods.loadElement(url,cachereq);
  166.                     return;
  167.                 }
  168.                 else {
  169.                     debug("SPA->load()->impl.methods.loadElement(url) url:" + url);
  170.                     impl.methods.loadElement(url,cachereq);
  171.                 }
  172.             }
  173.             $.history.load(url);
  174.             //            debug("spa->load() url: " + url);
  175.         },
  176.        
  177.         /*Called from the $.history module to when history is moved back or forward*/
  178.         loadElement: function (url,cachereq) {
  179.            
  180.             cachereq = cachereq || false;
  181.  
  182.             debug("loadElement() url -> " + url);
  183.  
  184.             if (impl.noloads.hasItem(url)) {
  185.                 var onload = impl.noloads.getItem(url);
  186.                 if (onload) {
  187.                     onload(url, settings);
  188.                     debug("loadElement() onload called -> " + url);
  189.                     return false;
  190.                 }
  191.             }
  192.  
  193.             var inithistory = settings.initialUrl;
  194.             if (url == null || url == "") {
  195.                 url = inithistory;
  196.                 debug("settings.initialUrl -> " + settings.initialUrl);
  197.             }
  198.  
  199.             if (url == undefined || url == null || url == "")
  200.                 return false;
  201.  
  202.             var loadIntoSel = settings.loadIntoSelector || "#content";
  203.             var loadInto = $(loadIntoSel);
  204.  
  205.             if (settings.beforeload) {
  206.                 if (settings.beforeload(loadInto, url) === false) {
  207.                     return false;
  208.                 }
  209.             }
  210.  
  211.             impl.methods.loadUIState(url);
  212.  
  213.             /*get global cache settings*/
  214.             var cacheRequest = cachereq;
  215.             var loadUrl = url;
  216.            
  217.             var notcached = impl.notcached.getItem(url);
  218.             if (notcached != null) {
  219.                 cacheRequest = false;
  220.                 debug("NOT CACHED: " + url + " id: " + notcached);
  221.             } else {
  222.                 var cachedLink = impl.urlcache.getItem(url);
  223.                 if (cachedLink != null) {
  224.                     cacheRequest = true;
  225.                     debug("CACHED URL   :" + url + " id: " + cachedLink);
  226.                 }
  227.             }
  228.  
  229.             if (cacheRequest === true) { /*modifies the url that will cache request*/
  230.                 debug("CACHING -> " + url);
  231.                 var cachedhtml = impl.cache.getItem(url);
  232.                 if (cachedhtml) {
  233.                     debug("CACHE HIT -> " + url);
  234.                     loadInto.html(cachedhtml);
  235.                     /*calls the afterload() method*/
  236.                     if (settings.afterload) {
  237.                         settings.afterload($(loadInto), url, cachedhtml, null, null);
  238.                     }
  239.                     return;
  240.                 }
  241.             }
  242.  
  243.             var ajaxtype = settings.ajaxType || "GET";
  244.             var timestamp = new Date().getTime();
  245.             var running = impl.currentreq.getItem(url) || false;
  246.             if(running){
  247.                 impl.currentreq.setItem(url,false);
  248.                 return;
  249.             }
  250.  
  251.             impl.currentreq.setItem(url,true);
  252.  
  253.             debug("$.ajax " + ajaxtype + " ts:  " + timestamp + "   -> " + loadUrl);
  254.  
  255.             /*Calls $.ajax method*/
  256.             $.ajax({
  257.                 url: loadUrl,
  258.                 type: settings.ajaxType || "GET",
  259.                 cache: settings.ajaxCache || false,
  260.                 success: function (data, status, xhr) {
  261.                     try {
  262.  
  263.                         impl.currentreq.setItem(url,false);
  264.  
  265.                         debug("ts: " + timestamp);
  266.  
  267.                         /*load's html into 'loadInto' element*/
  268.                         loadInto.html(data);
  269.                         if (cacheRequest === true) {
  270.                             impl.cache.setItem(url, data);
  271.                         }
  272.                         /*looks for the title in the response and sets the document.title*/
  273.                         var spa_title = loadInto.find("#spa_title");
  274.                         var title = "";
  275.  
  276.                         if (spa_title) {
  277.                             title = spa_title.html();
  278.                         }
  279.                         if (settings.settitle) {
  280.                             document.title = settings.settitle(loadInto, url, title);
  281.                         } else {
  282.                             document.title = title;
  283.                         }
  284.                     } catch (e) {
  285.                         throw e;
  286.                     }
  287.                     finally {
  288.                         /*calls the afterload() method*/
  289.                         if (settings.afterload) {
  290.                             settings.afterload($(loadInto), url, data, status, xhr);
  291.                         }
  292.                     }
  293.                 },
  294.                 error: function (xhr, status, errorThrown) {
  295.  
  296.                     loadInto.empty();
  297.  
  298.                     try {
  299.                         var msg = "Sorry but there was an error: ";
  300.                         debug(msg + " " + errorThrown);
  301.  
  302.                         if (settings.error) {
  303.                             settings.error(loadInto, url, status, errorThrown, xhr);
  304.                         }
  305.                     } catch (e) {
  306.                         throw e;
  307.                     }
  308.                     finally {
  309.                         /*calls the afterload() method*/
  310.                         if (settings.afterload) {
  311.                             settings.afterload(loadInto, url, null, status, xhr);
  312.                         }
  313.                     }
  314.                 }
  315.             });
  316.         },
  317.         /*Add ui button with it's associated url to change it's state when the history is moved*/
  318.         addUIButton: function (url, button) {
  319.             if (!button) return false;
  320.  
  321.             impl.buttons.setItem(url, button);
  322.             debug("addUIButton -> id:" + button.attr("id"));
  323.  
  324.             return true;
  325.         },
  326.  
  327.         /*Changes the button states when a url is loaded*/
  328.         loadUIState: function (url) {
  329.  
  330.             /*set all buttons to thier default state*/
  331.             var buttonKeys = impl.buttons.getKeys();
  332.  
  333.             var selbutton = impl.buttons.getItem(url);
  334.             if (!selbutton) {
  335.                 return;
  336.             }
  337.  
  338.             $(".spa-button").each(function () {
  339.                 var btn = $(this);
  340.  
  341.                 btn.addClass("ui-state-default");
  342.                 btn.removeClass("ui-state-focus");
  343.                 btn.removeClass("ui-state-active");
  344.                 btn.removeClass("ui-state-hover");
  345.                 /*debug("Setting class : " + $(btn).attr("id"));*/
  346.             });
  347.  
  348.             /*set the button associated with the url to the 'hover state*/
  349.             if (selbutton) {
  350.                 selbutton.addClass("ui-state-focus");
  351.             }
  352.         }
  353.     };
  354.  
  355.     $.fn.spa = function (method) {
  356.  
  357.         if (impl.methods[method]) {
  358.             return impl.methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  359.         } else if (typeof method === 'object' || !method) {
  360.             return impl.methods.init.apply(this, arguments);
  361.         } else {
  362.             $.error('Method ' + method + ' does not exist on jQuery.spa');
  363.         }
  364.     };
  365.  
  366.     var self = $.extend($.fn.spa, impl.methods);
  367.  
  368.     $.spa = self;
  369.  
  370. })(jQuery);
  371.  
  372. /*A hash table*/
  373. function spaHash() {
  374.  
  375.     this.length = 0;
  376.     this.items = new Array();
  377.     for (var i = 0; i < arguments.length; i += 2) {
  378.         if (typeof (arguments[i + 1]) != 'undefined') {
  379.             this.items[arguments[i]] = arguments[i + 1];
  380.             this.length++;
  381.         }
  382.     }
  383.  
  384.     this.removeItem = function (in_key) {
  385.         var tmp_previous;
  386.         if (typeof (this.items[in_key]) != 'undefined') {
  387.             this.length--;
  388.             var tmp_previous = this.items[in_key];
  389.             delete this.items[in_key];
  390.         }
  391.  
  392.         return tmp_previous;
  393.     }
  394.  
  395.     this.getItem = function (in_key) {
  396.         return this.items[in_key];
  397.     }
  398.  
  399.     this.setItem = function (in_key, in_value) {
  400.         var tmp_previous;
  401.         if (typeof (in_value) != 'undefined') {
  402.             if (typeof (this.items[in_key]) == 'undefined') {
  403.                 this.length++;
  404.             } else {
  405.                 tmp_previous = this.items[in_key];
  406.             }
  407.  
  408.             this.items[in_key] = in_value;
  409.         }
  410.  
  411.         return tmp_previous;
  412.     }
  413.     this.getKeys = function () {
  414.         var tmp_keys = [];
  415.  
  416.         for (var key in this.items) {
  417.             tmp_keys.push(key);
  418.         }
  419.         return tmp_keys;
  420.     }
  421.  
  422.     this.hasItem = function (in_key) {
  423.         return typeof (this.items[in_key]) != 'undefined';
  424.     }
  425.  
  426.     this.clear = function () {
  427.         for (var i in this.items) {
  428.             delete this.items[i];
  429.         }
  430.  
  431.         this.length = 0;
  432.     }
  433. }
Advertisement
Add Comment
Please, Sign In to add comment