Repository: deltaspike Updated Branches: refs/heads/master 9d0ad6b6b -> 2cbbfcaa1
DELTASPIKE-953 Refactor ClientWindow client side Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/2cbbfcaa Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/2cbbfcaa Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/2cbbfcaa Branch: refs/heads/master Commit: 2cbbfcaa1bfe9ca817476107697b5d505aac3254 Parents: 9d0ad6b Author: Thomas Andraschko <[email protected]> Authored: Tue Jul 14 22:45:51 2015 +0200 Committer: Thomas Andraschko <[email protected]> Committed: Tue Jul 14 22:45:51 2015 +0200 ---------------------------------------------------------------------- .../component/window/WindowIdHtmlRenderer.java | 6 +- .../resources/deltaspike/windowhandler.js | 488 +++++++++++-------- 2 files changed, 277 insertions(+), 217 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2cbbfcaa/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/component/window/WindowIdHtmlRenderer.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/component/window/WindowIdHtmlRenderer.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/component/window/WindowIdHtmlRenderer.java index 6b9ce31..1232c60 100644 --- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/component/window/WindowIdHtmlRenderer.java +++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/component/window/WindowIdHtmlRenderer.java @@ -73,8 +73,7 @@ public class WindowIdHtmlRenderer extends Renderer ResponseWriter writer = context.getResponseWriter(); writer.startElement("script", component); writer.writeAttribute("type", "text/javascript", null); - writer.write("window.deltaspikeWindowId='" + windowId + "';"); - writer.write("window.deltaspikeClientWindowRenderMode='" + clientWindowRenderMode + "';"); + writer.write("dswh.init('" + windowId + "','" + clientWindowRenderMode + "'"); // see #729 if (clientWindow.isInitialRedirectSupported(context)) @@ -83,7 +82,7 @@ public class WindowIdHtmlRenderer extends Renderer if (cookie != null && cookie instanceof Cookie) { Cookie servletCookie = (Cookie) cookie; - writer.write("window.deltaspikeInitialRedirectWindowId='" + servletCookie.getValue() + "';"); + writer.write(",{'initialRedirectWindowId':'" + servletCookie.getValue() + "'}"); // expire/remove cookie servletCookie.setMaxAge(0); @@ -91,6 +90,7 @@ public class WindowIdHtmlRenderer extends Renderer } } + writer.write(");"); writer.endElement("script"); } http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2cbbfcaa/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/deltaspike/windowhandler.js ---------------------------------------------------------------------- diff --git a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/deltaspike/windowhandler.js b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/deltaspike/windowhandler.js index 38b1ee7..5722bff 100644 --- a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/deltaspike/windowhandler.js +++ b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/deltaspike/windowhandler.js @@ -16,249 +16,309 @@ * specific language governing permissions and limitations * under the License. */ -(function() { -//wrapping so that all internal functions are privately scoped -function isHtml5() { - try { - return !!localStorage.getItem; - } catch(e) { - return false; - } -} +window.dswh = window.dswh || { + + windowId : null, + clientWindowRenderMode : null, + cfg: null, + + init : function(windowId, clientWindowRenderMode, cfg) { + this.windowId = windowId; + this.clientWindowRenderMode = clientWindowRenderMode; + this.cfg = cfg; -// some browsers don't understand JSON - guess which one ... :( -function stringify(someArray) { - if (JSON) { - return JSON.stringify(someArray); - } - return someArray.join("|||"); -} + var targetStrategy = this.strategy[clientWindowRenderMode]; + if (targetStrategy) { + targetStrategy.validate(); + + // early init + // this is required if e.g. the onload attr is defined on the body tag and our onload handler won't be called + // ATTENTION: the ds:windowId component must be placed as last body tag + targetStrategy.init(false); -// store the current body in the html5 localstorage -function storeWindowTree() { - // first we store all CSS we also need on the intermediate page - var headNodes = document.getElementsByTagName("head")[0].childNodes; - var oldSS = new Array(); - var j = 0; - for (var i = 0; i < headNodes.length; i++) { - var tagName = headNodes[i].tagName; - if (tagName && equalsIgnoreCase(tagName, "link") && - equalsIgnoreCase(headNodes[i].getAttribute("type"), "text/css")) { + // JSF ajax callback + jsf.ajax.addOnEvent(function(event) { + if (event.status === "success") { + targetStrategy.init(true); + } + }); - // sort out media="print" and stuff - var media = headNodes[i].getAttribute("media"); - if (!media || equalsIgnoreCase(media, "all") || equalsIgnoreCase(media, 'screen')) { - oldSS[j++] = headNodes[i].getAttribute("href"); + // PF ajax callback + if (window.$ && window.PrimeFaces) { + $(document).on('pfAjaxComplete', function () { + targetStrategy.init(true); + }); } + + // init via onload + // just as fallback if ds:windowId is not placed at last body tag + var oldWindowOnLoad = window.onload; + window.onload = function(evt) { + try { + (oldWindowOnLoad) ? oldWindowOnLoad(evt) : null; + } finally { + targetStrategy.init(false); + } + }; } - } - localStorage.setItem(window.name + '_css', stringify(oldSS)); - var body = document.getElementsByTagName("body")[0]; - localStorage.setItem(window.name + '_body', body.innerHTML); - //X TODO: store ALL attributes of the body tag - localStorage.setItem(window.name + '_bodyAttrs', body.getAttribute("class")); - return true; -} + }, -function equalsIgnoreCase(source, destination) { - //either both are not set or null - if (!source && !destination) { - return true; - } - //source or dest is set while the other is not - if (!source || !destination) return false; + strategy : { + + 'CLIENTWINDOW' : { + + validate : function() { + this.cleanupCookies(); + this.assertWindowId(); + }, + + init : function(ajax) { + this.overwriteOnClickEvents(); - //in any other case we do a strong string comparison - return source.toLowerCase() === destination.toLowerCase(); -} + dswh.utils.appendHiddenWindowIdToForms(); + }, + + assertWindowId : function() { + // ensure that windowIds get checked even if no windowhandler.html is used + if (!window.name || window.name.length < 1) { + window.name = 'tempWindowId'; + window.location = dswh.utils.setUrlParam(window.location.href, 'dswid', null); + } + }, + + overwriteOnClickEvents : function() { + if (dswh.utils.isHtml5()) { + var links = document.getElementsByTagName("a"); + for (var i = 0; i < links.length; i++) { + if (!links[i].onclick) { + links[i].onclick = function() { + dswh.strategy.CLIENTWINDOW.storeWindowTree(); + return true; + }; + } else { + // prevent double decoration + if (!("" + links[i].onclick).match(".*storeWindowTree().*")) { + //the function wrapper is important otherwise the + //last onclick handler would be assigned to oldonclick + (function storeEvent() { + var oldonclick = links[i].onclick; + links[i].onclick = function(evt) { + //ie handling added + evt = evt || window.event; -/** This method will be called onWindowLoad and after AJAX success */ -function applyWindowId() { - if (window.deltaspikeClientWindowRenderMode === 'CLIENTWINDOW' && isHtml5()) { // onClick handling - var links = document.getElementsByTagName("a"); - for (var i = 0; i < links.length; i++) { - if (!links[i].onclick) { - links[i].onclick = function() {storeWindowTree(); return true;}; - } else { - // prevent double decoration - if (!("" + links[i].onclick).match(".*storeWindowTree().*")) { - //the function wrapper is important otherwise the - //last onclick handler would be assigned to oldonclick - (function storeEvent() { - var oldonclick = links[i].onclick; - links[i].onclick = function(evt) { - //ie handling added - evt = evt || window.event; + return dswh.strategy.CLIENTWINDOW.storeWindowTree() && oldonclick.bind(this)(evt); + }; + })(); + } + } + } + } + }, + + /** + * store the current body in the html5 localstorage + */ + storeWindowTree : function() { + // first we store all CSS we also need on the intermediate page + var headNodes = document.getElementsByTagName("head")[0].childNodes; + var oldSS = new Array(); + var j = 0; + for (var i = 0; i < headNodes.length; i++) { + var tagName = headNodes[i].tagName; + if (tagName + && dswh.utils.equalsIgnoreCase(tagName, "link") + && dswh.utils.equalsIgnoreCase(headNodes[i].getAttribute("type"), "text/css")) { - return storeWindowTree() && oldonclick.bind(this)(evt); - }; - })(); + // sort out media="print" and stuff + var media = headNodes[i].getAttribute("media"); + if (!media + || dswh.utils.equalsIgnoreCase(media, "all") + || dswh.utils.equalsIgnoreCase(media, 'screen')) { + oldSS[j++] = headNodes[i].getAttribute("href"); + } + } + } + localStorage.setItem(window.name + '_css', dswh.utils.stringify(oldSS)); + var body = document.getElementsByTagName("body")[0]; + localStorage.setItem(window.name + '_body', body.innerHTML); + //X TODO: store ALL attributes of the body tag + localStorage.setItem(window.name + '_bodyAttrs', body.getAttribute("class")); + return true; + }, + + cleanupCookies : function() { + var dsrid = dswh.utils.getUrlParameter(window.location.href, 'dsrid'); + if (dsrid) { + dswh.utils.expireCookie('dsrwid-' + dsrid); } } - } - } - var forms = document.getElementsByTagName("form"); - for (var i = 0; i < forms.length; i++) { - var form = forms[i]; - var windowIdHolder = form.elements["dspwid"]; - if (!windowIdHolder) { - windowIdHolder = document.createElement("INPUT"); - windowIdHolder.name = "dspwid"; - windowIdHolder.type = "hidden"; - form.appendChild(windowIdHolder); - } + }, - windowIdHolder.value = window.deltaspikeWindowId; - } -} + 'LAZY' : { + + validate : function() { + this.cleanupCookies(); + this.assertWindowId(); + }, + + init : function(ajax) { + dswh.utils.appendHiddenWindowIdToForms(); + }, -function getUrlParameter(uri, name) { - // create an anchor object with the uri and let the browser parse it - var a = document.createElement('a'); - a.href = uri; + assertWindowId : function() { + var dswid = dswh.utils.getUrlParameter(window.location.href, 'dswid'); - // check if a query string is available - var queryString = a.search; - if (queryString && queryString.length > 0) { - // create an array of query parameters - substring(1) removes the ? at the beginning of the query - var queryParameters = queryString.substring(1).split("&"); - for (var i = 0; i < queryParameters.length; i++) { - var queryParameter = queryParameters[i].split("="); - if (queryParameter[0] === name) { - return queryParameter.length > 1 ? queryParameter[1] : ""; - } - } - } + // window.name is null which means that "open in new tab/window" was used + if (!window.name || window.name.length < 1) { - return null; -} -function setUrlParam(baseUrl, paramName, paramValue) { - var query = baseUrl; - var vars = query.split(/&|\?/g); - var newQuery = ""; - var iParam = 0; - var paramFound = false; - for (var i=0; vars != null && i < vars.length; i++) { - var pair = vars[i].split("="); - if (pair.length == 1) { - newQuery = pair[0]; - } else { - if (pair[0] != paramName) { - var amp = iParam++ > 0 ? "&" : "?"; - newQuery = newQuery + amp + pair[0] + "=" + pair[1]; - } else { - paramFound = true; - if (paramValue) { - var amp = iParam++ > 0 ? "&" : "?"; - newQuery = newQuery + amp + paramName + "=" + paramValue; - } - } - } - } - if (!paramFound && paramValue) { - var amp = iParam++ > 0 ? "&" : "?"; - newQuery = newQuery + amp + paramName + "=" + paramValue; - } - return newQuery; -} -// this method runs to ensure that windowIds get checked even if no windowhandler.html is used -function assertWindowId() { - if (window.deltaspikeClientWindowRenderMode === 'CLIENTWINDOW') { - if (!window.name || window.name.length < 1) { - window.name = 'tempWindowId'; - window.location = setUrlParam(window.location.href, 'dswid', null); - } - } - else if (window.deltaspikeClientWindowRenderMode === 'LAZY') { - var dswid = getUrlParameter(window.location.href, 'dswid'); - - // window.name is null which means that "open in new tab/window" was used - if (!window.name || window.name.length < 1) { + // url param available? + if (dswid) { + // initial redirect case + // the windowId is valid - we don't need to a second request + if (dswh.cfg.initialRedirectWindowId && dswid === dswh.cfg.initialRedirectWindowId) { + window.name = dswh.cfg.initialRedirectWindowId; + } + else { + // -- url param available, we must recreate a new windowId to be sure that it is new and valid -- + + // set tempWindowId to remember the current state + window.name = 'tempWindowId'; + // we remove the dswid if available and redirect to the same url again to create a new windowId + window.location = dswh.utils.setUrlParam(window.location.href, 'dswid', null); + } + } + else if (dswh.windowId) { + // -- no dswid in the url -> an initial request without initial redirect -- - // url param available? - if (dswid) { - // initial redirect case - // the windowId is valid - we don't need to a second request - if (window.deltaspikeInitialRedirectWindowId && dswid === window.deltaspikeInitialRedirectWindowId) { - window.name = window.deltaspikeInitialRedirectWindowId; + // this means that the initial redirect is disabled and we can just use the windowId as window.name + window.name = dswh.windowId; + } } else { - // -- url param available, we must recreate a new windowId to be sure that it is new and valid -- - - // set tempWindowId to remember the current state - window.name = 'tempWindowId'; - // we remove the dswid if avilable and redirect to the same url again the create a new windowId - window.location = setUrlParam(window.location.href, 'dswid', null); + if (window.name === 'tempWindowId') { + // we triggered the windowId recreation last request - use it now! + window.name = dswid; + } + else if (window.name !== dswid) { + // window.name doesn't match requested windowId + // -> redirect to the same view with current window.name / windowId + window.location = dswh.utils.setUrlParam(window.location.href, 'dswid', window.name); + } + } + }, + + cleanupCookies : function() { + var dswid = dswh.utils.getUrlParameter(window.location.href, 'dswid'); + if (dswid) { + dswh.utils.expireCookie('dsrwid-' + dswid); } - } - else if (window.deltaspikeWindowId) { - // -- no dswid in the url -> an initial request without initial redirect -- - - // this means that the initial redirect is disabled and we can just use the windowId as window.name - window.name = window.deltaspikeWindowId; } } - else { - if (window.name === 'tempWindowId') { - // we triggered the windowId recreation last request - use it now! - window.name = dswid; - } - else if (window.name !== dswid) { - // window.name doesn't match requested windowId - // -> redirect to the same view with current window.name / windowId - window.location = setUrlParam(window.location.href, 'dswid', window.name); + }, + + utils : { + + isHtml5 : function() { + try { + return !!localStorage.getItem; + } catch(e) { + return false; } - } - } -} + }, -function eraseRequestCookie() { - - var date = new Date(); - date.setTime(date.getTime()-(10*24*60*60*1000)); // - 10 day - var expires = ";max-age=0;expires="+date.toGMTString(); - - // CLIENT_WINDOW - var dsrid = getUrlParameter(window.location.href, 'dsrid'); - if (dsrid) { - var cookieName = 'dsrwid-' + dsrid; - document.cookie = cookieName+"="+expires+"; path=/"; - } + stringify : function(someArray) { + // some browsers don't understand JSON - guess which one ... :( + if (JSON) { + return JSON.stringify(someArray); + } + return someArray.join("|||"); + }, + + equalsIgnoreCase : function(source, destination) { + //either both are not set or null + if (!source && !destination) { + return true; + } + //source or dest is set while the other is not + if (!source || !destination) return false; - // LAZY - var dswid = getUrlParameter(window.location.href, 'dswid'); - if (dswid) { - var cookieName = 'dsrwid-' + dswid; - document.cookie = cookieName+"="+expires+"; path=/"; - } -} + //in any other case we do a strong string comparison + return source.toLowerCase() === destination.toLowerCase(); + }, + + getUrlParameter : function (uri, name) { + // create an anchor object with the uri and let the browser parse it + var a = document.createElement('a'); + a.href = uri; -var jsfAjaxHandler = function(event) { - if (event.status === "success") { - applyWindowId(); - } -}; + // check if a query string is available + var queryString = a.search; + if (queryString && queryString.length > 0) { + // create an array of query parameters - substring(1) removes the ? at the beginning of the query + var queryParameters = queryString.substring(1).split("&"); + for (var i = 0; i < queryParameters.length; i++) { + var queryParameter = queryParameters[i].split("="); + if (queryParameter[0] === name) { + return queryParameter.length > 1 ? queryParameter[1] : ""; + } + } + } -var pfAjaxHandler = function() { - applyWindowId(); -}; + return null; + }, -var oldWindowOnLoad = window.onload; + setUrlParam : function (baseUrl, paramName, paramValue) { + var query = baseUrl; + var vars = query.split(/&|\?/g); + var newQuery = ""; + var iParam = 0; + var paramFound = false; + for (var i=0; vars != null && i < vars.length; i++) { + var pair = vars[i].split("="); + if (pair.length == 1) { + newQuery = pair[0]; + } else { + if (pair[0] != paramName) { + var amp = iParam++ > 0 ? "&" : "?"; + newQuery = newQuery + amp + pair[0] + "=" + pair[1]; + } else { + paramFound = true; + if (paramValue) { + var amp = iParam++ > 0 ? "&" : "?"; + newQuery = newQuery + amp + paramName + "=" + paramValue; + } + } + } + } + if (!paramFound && paramValue) { + var amp = iParam++ > 0 ? "&" : "?"; + newQuery = newQuery + amp + paramName + "=" + paramValue; + } + return newQuery; + }, + + appendHiddenWindowIdToForms : function() { + var forms = document.getElementsByTagName("form"); + for (var i = 0; i < forms.length; i++) { + var form = forms[i]; + var dspwid = form.elements["dspwid"]; + if (!dspwid) { + dspwid = document.createElement("INPUT"); + dspwid.name = "dspwid"; + dspwid.type = "hidden"; + form.appendChild(dspwid); + } -window.onload = function(evt) { - if (window.deltaspikeClientWindowRenderMode === 'LAZY' || window.deltaspikeClientWindowRenderMode === 'CLIENTWINDOW') { - try { - (oldWindowOnLoad)? oldWindowOnLoad(evt): null; - } finally { - eraseRequestCookie(); // manually erase the old dsrid/dsrwid cookie because Firefox doesn't do it properly - assertWindowId(); - applyWindowId(); - jsf.ajax.addOnEvent(jsfAjaxHandler); - - if (window.$ && window.PrimeFaces) { - $(document).on('pfAjaxComplete', pfAjaxHandler); + dspwid.value = dswh.windowId; } + }, + + expireCookie : function(cookieName) { + var date = new Date(); + date.setTime(date.getTime()-(10*24*60*60*1000)); // - 10 day + var expires = ";max-age=0;expires=" + date.toGMTString(); + + document.cookie = cookieName + "=" + expires + "; path=/"; } } }; -})();
