@zayesh/stay
Advanced tools
Comparing version 0.0.14 to 0.0.15
/** | ||
* stay v0.0.14 build 28.07.2015 | ||
* stay v0.0.15 build 31.07.2015 | ||
* https://github.com/vanruesc/stay | ||
@@ -104,5 +104,12 @@ * Copyright 2015 Raoul van Rueschen, Apache-2.0 | ||
var EventDispatcher = require("@zayesh/eventdispatcher"), | ||
local = new RegExp("^" + location.protocol + "//" + location.host); | ||
/** | ||
* The Stay module is the class. | ||
* | ||
* @module Stay | ||
*/ | ||
module.exports = Stay; | ||
var EventDispatcher = require("@zayesh/eventdispatcher"); | ||
/** | ||
@@ -114,3 +121,4 @@ * Use the native browser url parsing mechanism | ||
* @private | ||
* @param {string} url - The URL to parse. | ||
* @static | ||
* @param {String} url - The URL to parse. | ||
* @return {HTMLAnchorElement} An object containing the url parts. | ||
@@ -137,8 +145,10 @@ */ | ||
* @constructor | ||
* @param {Object} options - The options. | ||
* @param {array} [options.responseFields] - The content container IDs. These have to be the same as the data fields in the server response. | ||
* @param {string} [options.infix] - The special url pattern infix for the asynchronous content requests. | ||
* @param {number} [options.timeoutPost] - Hard timeout for POST. 0 means no timeout. Default is 60000 (ms). | ||
* @param {number} [options.timeoutGet] - Hard timeout for GET. 0 means no timeout. Default is 5000 (ms). | ||
* @param {boolean} [options.autoUpdate] - Whether Stay should automatically update the page content. Defaults to true. | ||
* @extends EventDispatcher | ||
* @throws {Error} An error is thrown if asynchronous requests are not supported. | ||
* @param {Object} [options] - The options. | ||
* @param {Array} [options.responseFields=["main", "navigation", "footer"]] - The content container IDs. These have to be the same as the data fields in the server response. | ||
* @param {String} [options.infix="/json"] - The special url pattern infix for the asynchronous content requests. | ||
* @param {Number} [options.timeoutPost=60000] - Hard timeout for POST. 0 means no timeout. | ||
* @param {Number} [options.timeoutGet=5000] - Hard timeout for GET. 0 means no timeout. | ||
* @param {Boolean} [options.autoUpdate=true] - Whether Stay should automatically update the page content. | ||
*/ | ||
@@ -152,8 +162,59 @@ | ||
/** | ||
* Regular expression to check if a url is local. | ||
* | ||
* @property local | ||
* @type RegExp | ||
* @private | ||
*/ | ||
this.local = new RegExp("^" + location.protocol + "//" + location.host); | ||
/** | ||
* The response fields are the IDs of the DOM elements | ||
* that need to be filled with the server response fields. | ||
* | ||
* @property responseFields | ||
* @type Array | ||
*/ | ||
this.responseFields = ["main", "navigation", "footer"]; | ||
/** | ||
* The infix to use for the asynchronous requests. | ||
* | ||
* @property infix | ||
* @type String | ||
*/ | ||
this.infix = "/json"; | ||
/** | ||
* POST timeout. | ||
* | ||
* @property timeoutPost | ||
* @type Number | ||
*/ | ||
this.timeoutPost = 60000; | ||
/** | ||
* GET timeout. | ||
* | ||
* @property timeoutGet | ||
* @type Number | ||
*/ | ||
this.timeoutGet = 5000; | ||
/** | ||
* Auto update flag. | ||
* | ||
* @property autoUpdate | ||
* @type Boolean | ||
*/ | ||
this.autoUpdate = true; | ||
// Overwrite default values. | ||
if(options !== undefined) | ||
@@ -168,12 +229,98 @@ { | ||
/** | ||
* Lock flag. | ||
* | ||
* @property locked | ||
* @type Boolean | ||
* @private | ||
*/ | ||
this.locked = false; | ||
/** | ||
* Back-forward flag. | ||
* | ||
* @property backForward | ||
* @type Boolean | ||
* @private | ||
*/ | ||
this.backForward = false; | ||
/** | ||
* The current absolute path. | ||
* | ||
* @property absolutePath | ||
* @type String | ||
* @private | ||
*/ | ||
this.absolutePath = null; | ||
/** | ||
* A list of references to the response field DOM elements. | ||
* | ||
* @property containers | ||
* @type Array | ||
* @private | ||
*/ | ||
this.containers = []; | ||
/** | ||
* A container which is filled by setting its innerHTML. | ||
* The created DOM elements are taken from this container | ||
* and appended to the response fields. | ||
* | ||
* @property intermediateContainer | ||
* @type HTMLDivElement | ||
* @private | ||
*/ | ||
this.intermediateContainer = null; | ||
/** | ||
* A list of navigation listeners for unbinding. | ||
* | ||
* @property navigationListeners | ||
* @type Array | ||
* @private | ||
*/ | ||
this.navigationListeners = []; | ||
/** | ||
* Signalises that a page navigation has started. | ||
* | ||
* @event navigate | ||
*/ | ||
this.eventNavigate = {type: "navigate"}; | ||
this.eventReceive = {type: "receive", response: null}; | ||
/** | ||
* Returns the parsed server response. | ||
* | ||
* @event receive | ||
* @param {Object} response - The server response, ready to be inserted into the respective response fields. | ||
* @param {number} status - The status of the xhr response. | ||
*/ | ||
this.eventReceive = {type: "receive", response: null, status: 0}; | ||
/** | ||
* Signalises that a page update has finished. | ||
* | ||
* @event load | ||
*/ | ||
this.eventLoad = {type: "load"}; | ||
/** | ||
* The internal XMLHttpRequest instance. | ||
* | ||
* @property xhr | ||
* @type XMLHttpRequest | ||
* @private | ||
*/ | ||
if(XMLHttpRequest !== undefined) | ||
@@ -188,4 +335,20 @@ { | ||
this.xhr.addEventListener("readystatechange", function(event) { self._handleResponse(this, event); }); | ||
this.xhr.addEventListener("timeout", function() | ||
/** | ||
* Triggers the internal response handler. | ||
* | ||
* @method handleResponse | ||
* @private | ||
* @param {Object} event - The event. | ||
*/ | ||
this.xhr.addEventListener("readystatechange", function handleResponse(event) { self._handleResponse(this, event); }); | ||
/** | ||
* Handles xhr timeouts, ignores the event object. | ||
* | ||
* @method handleTimeout | ||
* @private | ||
*/ | ||
this.xhr.addEventListener("timeout", function handleTimeout() | ||
{ | ||
@@ -209,5 +372,9 @@ var response = {}; | ||
* state mustn't be pushed. | ||
* | ||
* @method handleBackForward | ||
* @private | ||
* @param {Object} event - The event. | ||
*/ | ||
window.addEventListener("popstate", function(event) | ||
window.addEventListener("popstate", function handleBackForward(event) | ||
{ | ||
@@ -441,3 +608,3 @@ if(!self.locked && event.state !== null) | ||
{ | ||
if(local.test(links[i].href)) | ||
if(this.local.test(links[i].href)) | ||
{ | ||
@@ -451,3 +618,3 @@ links[i].addEventListener("click", self._switchPage); | ||
{ | ||
if(local.test(forms[i].action)) | ||
if(this.local.test(forms[i].action)) | ||
{ | ||
@@ -501,3 +668,3 @@ forms[i].addEventListener("submit", self._switchPage); | ||
* The response will be a json object or an error page. Anything else will | ||
* be treated as a json parse exception. | ||
* be caught as a json parse exception and announced in the first response field. | ||
* | ||
@@ -528,6 +695,7 @@ * @method _handleResponse | ||
response[this.responseFields[0]] = Stay.Error.UNPARSABLE; | ||
console.log(e); | ||
if(console !== undefined) { console.log(e); } | ||
} | ||
response.url = xhr.responseURL; | ||
this.eventReceive.status = xhr.status; | ||
this.eventReceive.response = response; | ||
@@ -547,2 +715,3 @@ this.dispatchEvent(this.eventReceive); | ||
* @property Error | ||
* @type Object | ||
* @private | ||
@@ -559,11 +728,3 @@ * @static | ||
/** | ||
* Export as module. | ||
* | ||
* @module Stay | ||
*/ | ||
module.exports = Stay; | ||
},{"@zayesh/eventdispatcher":1}]},{},[2])(2) | ||
}); |
/** | ||
* stay v0.0.14 build 28.07.2015 | ||
* stay v0.0.15 build 31.07.2015 | ||
* https://github.com/vanruesc/stay | ||
* Copyright 2015 Raoul van Rueschen, Apache-2.0 | ||
*/ | ||
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Stay=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){"use strict";function d(){this._listeners={}}d.prototype.addEventListener=function(a,b){void 0===this._listeners[a]&&(this._listeners[a]=[]),-1===this._listeners[a].indexOf(b)&&this._listeners[a].push(b)},d.prototype.hasEventListener=function(a,b){return void 0!==this._listeners[a]&&-1!==this._listeners[a].indexOf(b)},d.prototype.removeEventListener=function(a,b){var c,d=this._listeners,e=d[a];void 0!==e&&(c=e.indexOf(b),-1!==c&&e.splice(c,1))},d.prototype.dispatchEvent=function(a){var b,c,d=this._listeners,e=d[a.type];if(void 0!==e)for(a.target=this,b=0,c=e.length;c>b;++b)e[b].call(this,a)},b.exports=d},{}],2:[function(a,b,c){"use strict";function d(a){var b=document.createElement("a");return b.href=a,b}function Stay(a){var b=this;if(e.call(this),this.responseFields=["main","navigation","footer"],this.infix="/json",this.timeoutPost=6e4,this.timeoutGet=5e3,this.autoUpdate=!0,void 0!==a&&(void 0!==a.responseFields&&(this.responseFields=a.responseFields),void 0!==a.infix&&(this.infix=a.infix),void 0!==a.timeoutPost&&(this.timeoutPost=a.timeoutPost),void 0!==a.timeoutGet&&(this.timeoutGet=a.timeoutGet),void 0!==a.autoUpdate&&(this.autoUpdate=a.autoUpdate)),this.locked=!1,this.backForward=!1,this.absolutePath=null,this.containers=[],this.intermediateContainer=null,this.navigationListeners=[],this.eventNavigate={type:"navigate"},this.eventReceive={type:"receive",response:null},this.eventLoad={type:"load"},void 0===XMLHttpRequest)throw new Error("XMLHttpRequest functionality not available.");this.xhr=new XMLHttpRequest,this.xhr.addEventListener("readystatechange",function(a){b._handleResponse(this,a)}),this.xhr.addEventListener("timeout",function(){var a={};b.responseFields.length&&(a.title="Timeout Error",a[b.responseFields[0]]=Stay.Error.TIMEOUT,b.locked=!0,b.update(a))}),window.addEventListener("popstate",function(a){b.locked||null===a.state||(b.backForward=!0,b._navigate({href:a.state.url}))}),this._switchPage=function(a){var c=void 0!==a.preventDefault,d=!1;return"submit"===a.type?d=!0:a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(void 0!==a.which?d=1===a.which:void 0!==a.button&&(d=0===a.button)),d&&(c&&a.preventDefault(),b.locked||b._navigate(this)),!(d&&!c)},this.update({title:document.title,url:window.location.href}),this._updateListeners()}var e=a("@zayesh/eventdispatcher"),f=new RegExp("^"+location.protocol+"//"+location.host);Stay.prototype=Object.create(e.prototype),Stay.prototype.constructor=Stay,Stay.prototype.addResponseField=function(a){-1===this.responseFields.indexOf(a)&&this.responseFields.push(a)},Stay.prototype.removeResponseField=function(a){var b=this.responseFields.indexOf(a);-1!==b&&this.responseFields.splice(b,1)},Stay.prototype._navigate=function(a){var b,c,e,f=!1;this.locked=!0,a.action?(this.absolutePath=a.action,b=new FormData(a),f=!0):this.absolutePath=a.href,c=d(this.absolutePath).pathname,"/"!==c.charAt(0)&&(c="/"+c),e="/"===c?this.absolutePath.slice(0,this.absolutePath.length-1)+this.infix+c:this.absolutePath.replace(new RegExp(c),this.infix+c),this.eventNavigate.method=f?"POST":"GET",this.dispatchEvent(this.eventNavigate),this.xhr.open(this.eventNavigate.method,e,!0),f?(this.xhr.timeout=this.timeoutPost,this.xhr.send(b)):(this.xhr.timeout=this.timeoutGet,this.xhr.send())},Stay.prototype._updateView=function(a){var b,c,d,e,f=!1;if(null===this.intermediateContainer)this.intermediateContainer=document.createElement("div");else for(;this.intermediateContainer.children.length>0;)this.intermediateContainer.removeChild(this.intermediateContainer.children[0]);for(b=0,c=this.responseFields.length;c>b;++b)if(d=this.containers[this.responseFields[b]],d||(d=this.containers[this.responseFields[b]]=document.getElementById(this.responseFields[b])),e=a[this.responseFields[b]]){for(;d.children.length>0;)d.removeChild(d.children[0]);for(this.intermediateContainer.innerHTML=e;this.intermediateContainer.children.length>0;)d.appendChild(this.intermediateContainer.children[0]);f=!0}f&&this._updateListeners()},Stay.prototype._updateListeners=function(){var a,b,c=this,d=document.getElementsByTagName("a"),e=document.getElementsByTagName("form");for(a=0,b=this.navigationListeners.length;b>a;++a)this.navigationListeners[a][0].removeEventListener(this.navigationListeners[a][1],c._switchPage);for(a=0,b=d.length;b>a;++a)f.test(d[a].href)&&(d[a].addEventListener("click",c._switchPage),this.navigationListeners.push([d[a],"click"]));for(a=0,b=e.length;b>a;++a)f.test(e[a].action)&&(e[a].addEventListener("submit",c._switchPage),this.navigationListeners.push([e[a],"submit"]))},Stay.prototype.update=function(a){this._updateView(a),document.title=a.title,a.url&&(this.absolutePath=a.url.replace(this.infix,"")),this.backForward?this.backForward=!1:history.pushState({url:this.absolutePath},a.title,this.absolutePath),this.eventReceive.response=null,this.dispatchEvent(this.eventLoad),this.locked=!1},Stay.prototype._handleResponse=function(a){var b={};if(0===this.responseFields.length)b.title="Setup Error",b[this.responseFields[0]]=Stay.Error.NO_RESPONSE_FIELDS;else if(4===a.readyState){try{b=JSON.parse(a.responseText)}catch(c){b.title="Parse Error",b[this.responseFields[0]]=Stay.Error.UNPARSABLE,console.log(c)}b.url=a.responseURL,this.eventReceive.response=b,this.dispatchEvent(this.eventReceive),this.autoUpdate&&this.update(b)}},Stay.Error=Object.freeze({TIMEOUT:"<p>The server didn't respond in time. Please try again later!</p>",UNPARSABLE:"<p>The received content could not be parsed.</p>",NO_RESPONSE_FIELDS:"<p>No response fields have been specified!</p>"}),b.exports=Stay},{"@zayesh/eventdispatcher":1}]},{},[2])(2)}); | ||
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Stay=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){"use strict";function d(){this._listeners={}}d.prototype.addEventListener=function(a,b){void 0===this._listeners[a]&&(this._listeners[a]=[]),-1===this._listeners[a].indexOf(b)&&this._listeners[a].push(b)},d.prototype.hasEventListener=function(a,b){return void 0!==this._listeners[a]&&-1!==this._listeners[a].indexOf(b)},d.prototype.removeEventListener=function(a,b){var c,d=this._listeners,e=d[a];void 0!==e&&(c=e.indexOf(b),-1!==c&&e.splice(c,1))},d.prototype.dispatchEvent=function(a){var b,c,d=this._listeners,e=d[a.type];if(void 0!==e)for(a.target=this,b=0,c=e.length;c>b;++b)e[b].call(this,a)},b.exports=d},{}],2:[function(a,b,c){"use strict";function d(a){var b=document.createElement("a");return b.href=a,b}function Stay(a){var b=this;if(e.call(this),this.local=new RegExp("^"+location.protocol+"//"+location.host),this.responseFields=["main","navigation","footer"],this.infix="/json",this.timeoutPost=6e4,this.timeoutGet=5e3,this.autoUpdate=!0,void 0!==a&&(void 0!==a.responseFields&&(this.responseFields=a.responseFields),void 0!==a.infix&&(this.infix=a.infix),void 0!==a.timeoutPost&&(this.timeoutPost=a.timeoutPost),void 0!==a.timeoutGet&&(this.timeoutGet=a.timeoutGet),void 0!==a.autoUpdate&&(this.autoUpdate=a.autoUpdate)),this.locked=!1,this.backForward=!1,this.absolutePath=null,this.containers=[],this.intermediateContainer=null,this.navigationListeners=[],this.eventNavigate={type:"navigate"},this.eventReceive={type:"receive",response:null,status:0},this.eventLoad={type:"load"},void 0===XMLHttpRequest)throw new Error("XMLHttpRequest functionality not available.");this.xhr=new XMLHttpRequest,this.xhr.addEventListener("readystatechange",function(a){b._handleResponse(this,a)}),this.xhr.addEventListener("timeout",function(){var a={};b.responseFields.length&&(a.title="Timeout Error",a[b.responseFields[0]]=Stay.Error.TIMEOUT,b.locked=!0,b.update(a))}),window.addEventListener("popstate",function(a){b.locked||null===a.state||(b.backForward=!0,b._navigate({href:a.state.url}))}),this._switchPage=function(a){var c=void 0!==a.preventDefault,d=!1;return"submit"===a.type?d=!0:a.metaKey||a.shiftKey||a.altKey||a.ctrlKey||(void 0!==a.which?d=1===a.which:void 0!==a.button&&(d=0===a.button)),d&&(c&&a.preventDefault(),b.locked||b._navigate(this)),!(d&&!c)},this.update({title:document.title,url:window.location.href}),this._updateListeners()}b.exports=Stay;var e=a("@zayesh/eventdispatcher");Stay.prototype=Object.create(e.prototype),Stay.prototype.constructor=Stay,Stay.prototype.addResponseField=function(a){-1===this.responseFields.indexOf(a)&&this.responseFields.push(a)},Stay.prototype.removeResponseField=function(a){var b=this.responseFields.indexOf(a);-1!==b&&this.responseFields.splice(b,1)},Stay.prototype._navigate=function(a){var b,c,e,f=!1;this.locked=!0,a.action?(this.absolutePath=a.action,b=new FormData(a),f=!0):this.absolutePath=a.href,c=d(this.absolutePath).pathname,"/"!==c.charAt(0)&&(c="/"+c),e="/"===c?this.absolutePath.slice(0,this.absolutePath.length-1)+this.infix+c:this.absolutePath.replace(new RegExp(c),this.infix+c),this.eventNavigate.method=f?"POST":"GET",this.dispatchEvent(this.eventNavigate),this.xhr.open(this.eventNavigate.method,e,!0),f?(this.xhr.timeout=this.timeoutPost,this.xhr.send(b)):(this.xhr.timeout=this.timeoutGet,this.xhr.send())},Stay.prototype._updateView=function(a){var b,c,d,e,f=!1;if(null===this.intermediateContainer)this.intermediateContainer=document.createElement("div");else for(;this.intermediateContainer.children.length>0;)this.intermediateContainer.removeChild(this.intermediateContainer.children[0]);for(b=0,c=this.responseFields.length;c>b;++b)if(d=this.containers[this.responseFields[b]],d||(d=this.containers[this.responseFields[b]]=document.getElementById(this.responseFields[b])),e=a[this.responseFields[b]]){for(;d.children.length>0;)d.removeChild(d.children[0]);for(this.intermediateContainer.innerHTML=e;this.intermediateContainer.children.length>0;)d.appendChild(this.intermediateContainer.children[0]);f=!0}f&&this._updateListeners()},Stay.prototype._updateListeners=function(){var a,b,c=this,d=document.getElementsByTagName("a"),e=document.getElementsByTagName("form");for(a=0,b=this.navigationListeners.length;b>a;++a)this.navigationListeners[a][0].removeEventListener(this.navigationListeners[a][1],c._switchPage);for(a=0,b=d.length;b>a;++a)this.local.test(d[a].href)&&(d[a].addEventListener("click",c._switchPage),this.navigationListeners.push([d[a],"click"]));for(a=0,b=e.length;b>a;++a)this.local.test(e[a].action)&&(e[a].addEventListener("submit",c._switchPage),this.navigationListeners.push([e[a],"submit"]))},Stay.prototype.update=function(a){this._updateView(a),document.title=a.title,a.url&&(this.absolutePath=a.url.replace(this.infix,"")),this.backForward?this.backForward=!1:history.pushState({url:this.absolutePath},a.title,this.absolutePath),this.eventReceive.response=null,this.dispatchEvent(this.eventLoad),this.locked=!1},Stay.prototype._handleResponse=function(a){var b={};if(0===this.responseFields.length)b.title="Setup Error",b[this.responseFields[0]]=Stay.Error.NO_RESPONSE_FIELDS;else if(4===a.readyState){try{b=JSON.parse(a.responseText)}catch(c){b.title="Parse Error",b[this.responseFields[0]]=Stay.Error.UNPARSABLE,void 0!==console&&console.log(c)}b.url=a.responseURL,this.eventReceive.status=a.status,this.eventReceive.response=b,this.dispatchEvent(this.eventReceive),this.autoUpdate&&this.update(b)}},Stay.Error=Object.freeze({TIMEOUT:"<p>The server didn't respond in time. Please try again later!</p>",UNPARSABLE:"<p>The received content could not be parsed.</p>",NO_RESPONSE_FIELDS:"<p>No response fields have been specified!</p>"})},{"@zayesh/eventdispatcher":1}]},{},[2])(2)}); |
@@ -13,3 +13,3 @@ YUI.add("yuidoc-meta", function(Y) { | ||
"name": "Stay", | ||
"description": "Export as module." | ||
"description": "The Stay module is the class." | ||
} | ||
@@ -16,0 +16,0 @@ ] |
{ | ||
"project": { | ||
"name": "@zayesh/stay", | ||
"name": "stay", | ||
"description": "Stay is a small but effective library for the creation of dynamic xhr-driven web applications.", | ||
@@ -32,4 +32,4 @@ "version": "0.0.14", | ||
"file": "src\\stay.js", | ||
"line": 23, | ||
"description": "Export as module." | ||
"line": 31, | ||
"description": "The Stay module is the class." | ||
} | ||
@@ -47,6 +47,12 @@ }, | ||
"module": "Stay", | ||
"namespace": "", | ||
"file": "src\\stay.js", | ||
"line": 23, | ||
"line": 31, | ||
"description": "The Stay XHR System.\n\nUsed for requesting page content asynchronously\nwhile staying on the same page.\n\nEach request can have a hard timeout to avoid endless\nloading times that are often deemed to fail anyways.", | ||
"is_constructor": 1, | ||
"extends": "EventDispatcher", | ||
"throws": { | ||
"description": "An error is thrown if asynchronous requests are not supported.", | ||
"type": "Error" | ||
}, | ||
"params": [ | ||
@@ -57,2 +63,3 @@ { | ||
"type": "Object", | ||
"optional": true, | ||
"props": [ | ||
@@ -63,3 +70,4 @@ { | ||
"type": "Array", | ||
"optional": true | ||
"optional": true, | ||
"optdefault": "[\"main\", \"navigation\", \"footer\"]" | ||
}, | ||
@@ -70,21 +78,25 @@ { | ||
"type": "String", | ||
"optional": true | ||
"optional": true, | ||
"optdefault": "\"/json\"" | ||
}, | ||
{ | ||
"name": "timeoutPost", | ||
"description": "- Hard timeout for POST. 0 means no timeout. Default is 60000 (ms).", | ||
"description": "- Hard timeout for POST. 0 means no timeout.", | ||
"type": "Number", | ||
"optional": true | ||
"optional": true, | ||
"optdefault": "60000" | ||
}, | ||
{ | ||
"name": "timeoutGet", | ||
"description": "- Hard timeout for GET. 0 means no timeout. Default is 5000 (ms).", | ||
"description": "- Hard timeout for GET. 0 means no timeout.", | ||
"type": "Number", | ||
"optional": true | ||
"optional": true, | ||
"optdefault": "5000" | ||
}, | ||
{ | ||
"name": "autoUpdate", | ||
"description": "- Whether Stay should automatically update the page content. Defaults to true.", | ||
"description": "- Whether Stay should automatically update the page content.", | ||
"type": "Boolean", | ||
"optional": true | ||
"optional": true, | ||
"optdefault": "true" | ||
} | ||
@@ -99,3 +111,3 @@ ] | ||
"file": "src\\stay.js", | ||
"line": 6, | ||
"line": 13, | ||
"description": "Use the native browser url parsing mechanism\nto retrieve the parts of a url.", | ||
@@ -106,2 +118,3 @@ "itemtype": "method", | ||
"tagname": "", | ||
"static": 1, | ||
"params": [ | ||
@@ -118,13 +131,240 @@ { | ||
}, | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 58, | ||
"description": "Regular expression to check if a url is local.", | ||
"itemtype": "property", | ||
"name": "local", | ||
"type": "RegExp", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 68, | ||
"description": "The response fields are the IDs of the DOM elements\nthat need to be filled with the server response fields.", | ||
"itemtype": "property", | ||
"name": "responseFields", | ||
"type": "Array", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 78, | ||
"description": "The infix to use for the asynchronous requests.", | ||
"itemtype": "property", | ||
"name": "infix", | ||
"type": "String", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 87, | ||
"description": "POST timeout.", | ||
"itemtype": "property", | ||
"name": "timeoutPost", | ||
"type": "Number", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 96, | ||
"description": "GET timeout.", | ||
"itemtype": "property", | ||
"name": "timeoutGet", | ||
"type": "Number", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 105, | ||
"description": "Auto update flag.", | ||
"itemtype": "property", | ||
"name": "autoUpdate", | ||
"type": "Boolean", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 124, | ||
"description": "Lock flag.", | ||
"itemtype": "property", | ||
"name": "locked", | ||
"type": "Boolean", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 134, | ||
"description": "Back-forward flag.", | ||
"itemtype": "property", | ||
"name": "backForward", | ||
"type": "Boolean", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 144, | ||
"description": "The current absolute path.", | ||
"itemtype": "property", | ||
"name": "absolutePath", | ||
"type": "String", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 154, | ||
"description": "A list of references to the response field DOM elements.", | ||
"itemtype": "property", | ||
"name": "containers", | ||
"type": "Array", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 164, | ||
"description": "A container which is filled by setting its innerHTML.\nThe created DOM elements are taken from this container\nand appended to the response fields.", | ||
"itemtype": "property", | ||
"name": "intermediateContainer", | ||
"type": "HTMLDivElement", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 176, | ||
"description": "A list of navigation listeners for unbinding.", | ||
"itemtype": "property", | ||
"name": "navigationListeners", | ||
"type": "Array", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 186, | ||
"description": "Signalises that a page navigation has started.", | ||
"itemtype": "event", | ||
"name": "navigate", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 194, | ||
"description": "Returns the parsed server response.", | ||
"itemtype": "event", | ||
"name": "receive", | ||
"params": [ | ||
{ | ||
"name": "response", | ||
"description": "- The server response, ready to be inserted into the respective response fields.", | ||
"type": "Object" | ||
}, | ||
{ | ||
"name": "status", | ||
"description": "- The status of the xhr response.", | ||
"type": "Number" | ||
} | ||
], | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 204, | ||
"description": "Signalises that a page update has finished.", | ||
"itemtype": "event", | ||
"name": "load", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 212, | ||
"description": "The internal XMLHttpRequest instance.", | ||
"itemtype": "property", | ||
"name": "xhr", | ||
"type": "XMLHttpRequest", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 229, | ||
"description": "Triggers the internal response handler.", | ||
"itemtype": "method", | ||
"name": "handleResponse", | ||
"access": "private", | ||
"tagname": "", | ||
"params": [ | ||
{ | ||
"name": "event", | ||
"description": "- The event.", | ||
"type": "Object" | ||
} | ||
], | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 239, | ||
"description": "Handles xhr timeouts, ignores the event object.", | ||
"itemtype": "method", | ||
"name": "handleTimeout", | ||
"access": "private", | ||
"tagname": "", | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 259, | ||
"description": "Support browser functionality \"back\" and \"forward\".\nDepends on the boolean variable \"locked\" in order to\ndetermine whether this navigation should be executed.\nThe \"backForward\" flag tells the system that the next\nstate mustn't be pushed.", | ||
"class": "Stay" | ||
"itemtype": "method", | ||
"name": "handleBackForward", | ||
"access": "private", | ||
"tagname": "", | ||
"params": [ | ||
{ | ||
"name": "event", | ||
"description": "- The event.", | ||
"type": "Object" | ||
} | ||
], | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 113, | ||
"line": 280, | ||
"description": "This function is bound to all links and forms\nand executes the desired page navigation on left clicks.", | ||
@@ -142,7 +382,8 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 166, | ||
"line": 333, | ||
"description": "Adds a response field.", | ||
@@ -158,7 +399,8 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 181, | ||
"line": 348, | ||
"description": "Removes a response field.", | ||
@@ -174,7 +416,8 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 198, | ||
"line": 365, | ||
"description": "Navigates to the next target uri.", | ||
@@ -192,7 +435,8 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 248, | ||
"line": 415, | ||
"description": "Updates the containers with the new data.", | ||
@@ -210,7 +454,8 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 311, | ||
"line": 478, | ||
"description": "Binds event listeners to all links and forms.\nThis method is combined with the cleanup and basically refreshes \nthe navigation listeners.", | ||
@@ -221,7 +466,8 @@ "itemtype": "method", | ||
"tagname": "", | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 350, | ||
"line": 517, | ||
"description": "Updates the view, the navigation listeners and the history state.\nAlso emits an event to signilize that the page has been loaded.\n\nThe update function needs to be called after each navigation in \norder to unlock the system. This happens by default, but that\nbehaviour can be disabled. It is then the responsibility of the\nprogrammer to call stay.update() with the response data provided \nby the \"receive\" event.", | ||
@@ -237,8 +483,9 @@ "itemtype": "method", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 388, | ||
"description": "This function acts when the xhr object changes its readyState.\nThe response will be a json object or an error page. Anything else will \nbe treated as a json parse exception.", | ||
"line": 555, | ||
"description": "This function acts when the xhr object changes its readyState.\nThe response will be a json object or an error page. Anything else will \nbe caught as a json parse exception and announced in the first response field.", | ||
"itemtype": "method", | ||
@@ -255,10 +502,12 @@ "name": "_handleResponse", | ||
], | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
}, | ||
{ | ||
"file": "src\\stay.js", | ||
"line": 431, | ||
"line": 599, | ||
"description": "Enumeration of Error Messages.", | ||
"itemtype": "property", | ||
"name": "Error", | ||
"type": "Object", | ||
"access": "private", | ||
@@ -268,11 +517,7 @@ "tagname": "", | ||
"final": 1, | ||
"class": "Stay" | ||
"class": "Stay", | ||
"module": "Stay" | ||
} | ||
], | ||
"warnings": [ | ||
{ | ||
"message": "Missing item type\nSupport browser functionality \"back\" and \"forward\".\nDepends on the boolean variable \"locked\" in order to\ndetermine whether this navigation should be executed.\nThe \"backForward\" flag tells the system that the next\nstate mustn't be pushed.", | ||
"line": " src\\stay.js:96" | ||
} | ||
] | ||
"warnings": [] | ||
} |
@@ -78,3 +78,3 @@ "use strict"; | ||
compile: { | ||
name: "<%= pkg.name %>", | ||
name: "<%= name %>", | ||
description: "<%= pkg.description %>", | ||
@@ -81,0 +81,0 @@ version: "<%= pkg.version %>", |
{ | ||
"name": "@zayesh/stay", | ||
"description": "Stay is a small but effective library for the creation of dynamic xhr-driven web applications.", | ||
"keywords": [ | ||
"xhr", | ||
"xmlhttprequest", | ||
"ajax", | ||
"web", | ||
"application" | ||
], | ||
"version": "0.0.14", | ||
"keywords": ["xhr", "xmlhttprequest", "ajax", "web application"], | ||
"version": "0.0.15", | ||
"homepage": "https://github.com/vanruesc/stay", | ||
@@ -13,0 +7,0 @@ "author": { |
211
src/stay.js
"use strict"; | ||
var EventDispatcher = require("@zayesh/eventdispatcher"), | ||
local = new RegExp("^" + location.protocol + "//" + location.host); | ||
/** | ||
* The Stay module is the class. | ||
* | ||
* @module Stay | ||
*/ | ||
module.exports = Stay; | ||
var EventDispatcher = require("@zayesh/eventdispatcher"); | ||
/** | ||
@@ -12,3 +19,4 @@ * Use the native browser url parsing mechanism | ||
* @private | ||
* @param {string} url - The URL to parse. | ||
* @static | ||
* @param {String} url - The URL to parse. | ||
* @return {HTMLAnchorElement} An object containing the url parts. | ||
@@ -35,8 +43,10 @@ */ | ||
* @constructor | ||
* @param {Object} options - The options. | ||
* @param {array} [options.responseFields] - The content container IDs. These have to be the same as the data fields in the server response. | ||
* @param {string} [options.infix] - The special url pattern infix for the asynchronous content requests. | ||
* @param {number} [options.timeoutPost] - Hard timeout for POST. 0 means no timeout. Default is 60000 (ms). | ||
* @param {number} [options.timeoutGet] - Hard timeout for GET. 0 means no timeout. Default is 5000 (ms). | ||
* @param {boolean} [options.autoUpdate] - Whether Stay should automatically update the page content. Defaults to true. | ||
* @extends EventDispatcher | ||
* @throws {Error} An error is thrown if asynchronous requests are not supported. | ||
* @param {Object} [options] - The options. | ||
* @param {Array} [options.responseFields=["main", "navigation", "footer"]] - The content container IDs. These have to be the same as the data fields in the server response. | ||
* @param {String} [options.infix="/json"] - The special url pattern infix for the asynchronous content requests. | ||
* @param {Number} [options.timeoutPost=60000] - Hard timeout for POST. 0 means no timeout. | ||
* @param {Number} [options.timeoutGet=5000] - Hard timeout for GET. 0 means no timeout. | ||
* @param {Boolean} [options.autoUpdate=true] - Whether Stay should automatically update the page content. | ||
*/ | ||
@@ -50,8 +60,59 @@ | ||
/** | ||
* Regular expression to check if a url is local. | ||
* | ||
* @property local | ||
* @type RegExp | ||
* @private | ||
*/ | ||
this.local = new RegExp("^" + location.protocol + "//" + location.host); | ||
/** | ||
* The response fields are the IDs of the DOM elements | ||
* that need to be filled with the server response fields. | ||
* | ||
* @property responseFields | ||
* @type Array | ||
*/ | ||
this.responseFields = ["main", "navigation", "footer"]; | ||
/** | ||
* The infix to use for the asynchronous requests. | ||
* | ||
* @property infix | ||
* @type String | ||
*/ | ||
this.infix = "/json"; | ||
/** | ||
* POST timeout. | ||
* | ||
* @property timeoutPost | ||
* @type Number | ||
*/ | ||
this.timeoutPost = 60000; | ||
/** | ||
* GET timeout. | ||
* | ||
* @property timeoutGet | ||
* @type Number | ||
*/ | ||
this.timeoutGet = 5000; | ||
/** | ||
* Auto update flag. | ||
* | ||
* @property autoUpdate | ||
* @type Boolean | ||
*/ | ||
this.autoUpdate = true; | ||
// Overwrite default values. | ||
if(options !== undefined) | ||
@@ -66,12 +127,98 @@ { | ||
/** | ||
* Lock flag. | ||
* | ||
* @property locked | ||
* @type Boolean | ||
* @private | ||
*/ | ||
this.locked = false; | ||
/** | ||
* Back-forward flag. | ||
* | ||
* @property backForward | ||
* @type Boolean | ||
* @private | ||
*/ | ||
this.backForward = false; | ||
/** | ||
* The current absolute path. | ||
* | ||
* @property absolutePath | ||
* @type String | ||
* @private | ||
*/ | ||
this.absolutePath = null; | ||
/** | ||
* A list of references to the response field DOM elements. | ||
* | ||
* @property containers | ||
* @type Array | ||
* @private | ||
*/ | ||
this.containers = []; | ||
/** | ||
* A container which is filled by setting its innerHTML. | ||
* The created DOM elements are taken from this container | ||
* and appended to the response fields. | ||
* | ||
* @property intermediateContainer | ||
* @type HTMLDivElement | ||
* @private | ||
*/ | ||
this.intermediateContainer = null; | ||
/** | ||
* A list of navigation listeners for unbinding. | ||
* | ||
* @property navigationListeners | ||
* @type Array | ||
* @private | ||
*/ | ||
this.navigationListeners = []; | ||
/** | ||
* Signalises that a page navigation has started. | ||
* | ||
* @event navigate | ||
*/ | ||
this.eventNavigate = {type: "navigate"}; | ||
this.eventReceive = {type: "receive", response: null}; | ||
/** | ||
* Returns the parsed server response. | ||
* | ||
* @event receive | ||
* @param {Object} response - The server response, ready to be inserted into the respective response fields. | ||
* @param {number} status - The status of the xhr response. | ||
*/ | ||
this.eventReceive = {type: "receive", response: null, status: 0}; | ||
/** | ||
* Signalises that a page update has finished. | ||
* | ||
* @event load | ||
*/ | ||
this.eventLoad = {type: "load"}; | ||
/** | ||
* The internal XMLHttpRequest instance. | ||
* | ||
* @property xhr | ||
* @type XMLHttpRequest | ||
* @private | ||
*/ | ||
if(XMLHttpRequest !== undefined) | ||
@@ -86,4 +233,20 @@ { | ||
this.xhr.addEventListener("readystatechange", function(event) { self._handleResponse(this, event); }); | ||
this.xhr.addEventListener("timeout", function() | ||
/** | ||
* Triggers the internal response handler. | ||
* | ||
* @method handleResponse | ||
* @private | ||
* @param {Object} event - The event. | ||
*/ | ||
this.xhr.addEventListener("readystatechange", function handleResponse(event) { self._handleResponse(this, event); }); | ||
/** | ||
* Handles xhr timeouts, ignores the event object. | ||
* | ||
* @method handleTimeout | ||
* @private | ||
*/ | ||
this.xhr.addEventListener("timeout", function handleTimeout() | ||
{ | ||
@@ -107,5 +270,9 @@ var response = {}; | ||
* state mustn't be pushed. | ||
* | ||
* @method handleBackForward | ||
* @private | ||
* @param {Object} event - The event. | ||
*/ | ||
window.addEventListener("popstate", function(event) | ||
window.addEventListener("popstate", function handleBackForward(event) | ||
{ | ||
@@ -339,3 +506,3 @@ if(!self.locked && event.state !== null) | ||
{ | ||
if(local.test(links[i].href)) | ||
if(this.local.test(links[i].href)) | ||
{ | ||
@@ -349,3 +516,3 @@ links[i].addEventListener("click", self._switchPage); | ||
{ | ||
if(local.test(forms[i].action)) | ||
if(this.local.test(forms[i].action)) | ||
{ | ||
@@ -399,3 +566,3 @@ forms[i].addEventListener("submit", self._switchPage); | ||
* The response will be a json object or an error page. Anything else will | ||
* be treated as a json parse exception. | ||
* be caught as a json parse exception and announced in the first response field. | ||
* | ||
@@ -426,6 +593,7 @@ * @method _handleResponse | ||
response[this.responseFields[0]] = Stay.Error.UNPARSABLE; | ||
console.log(e); | ||
if(console !== undefined) { console.log(e); } | ||
} | ||
response.url = xhr.responseURL; | ||
this.eventReceive.status = xhr.status; | ||
this.eventReceive.response = response; | ||
@@ -445,2 +613,3 @@ this.dispatchEvent(this.eventReceive); | ||
* @property Error | ||
* @type Object | ||
* @private | ||
@@ -456,9 +625,1 @@ * @static | ||
}); | ||
/** | ||
* Export as module. | ||
* | ||
* @module Stay | ||
*/ | ||
module.exports = Stay; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
240064
3049