Skip to content

Instantly share code, notes, and snippets.

@alejandro-du
Last active January 26, 2017 11:07
Show Gist options
  • Save alejandro-du/b6b42cb7243e0f8f16e1ea634ecc637a to your computer and use it in GitHub Desktop.
Save alejandro-du/b6b42cb7243e0f8f16e1ea634ecc637a to your computer and use it in GitHub Desktop.
Function to "deatach" apps when required
(function() {
var apps = {};
var themesLoaded = {};
var widgetsets = {};
var log;
if (typeof console === "undefined" || !window.location.search.match(/[&?]debug(&|$)/)) {
//If no console.log present, just use a no-op
log = function() {};
} else if (typeof console.log === "function") {
//If it's a function, use it with apply
log = function() {
console.log.apply(console, arguments);
};
} else {
//In IE, its a native function for which apply is not defined, but it works without a proper 'this' reference
log = console.log;
}
var loadTheme = function(url, version) {
if(!themesLoaded[url]) {
log("loadTheme", url, version);
var href = url + '/styles.css';
if (version) {
href += '?v=' + version;
}
var stylesheet = document.createElement('link');
stylesheet.setAttribute('rel', 'stylesheet');
stylesheet.setAttribute('type', 'text/css');
stylesheet.setAttribute('href', href);
document.getElementsByTagName('head')[0].appendChild(stylesheet);
themesLoaded[url] = true;
}
};
var isWidgetsetLoaded = function(widgetset) {
var className = widgetset.replace(/\./g, "_");
return (typeof window[className]) != "undefined";
};
var loadWidgetset = function(url, widgetset, ready) {
if (widgetsets[widgetset]) {
return;
}
log("load widgetset", url, widgetset);
setTimeout(function() {
if (!isWidgetsetLoaded(widgetset)) {
if (ready) {
alert("Failed to load the widgetset: " + url);
} else {
if (window.confirm("Failed to load the widgetset. If using CDN for the widgetset, it is possible that compiling it takes up to a few minutes. Would you like to try again?")) {
window[widgetset] = undefined;
window.location.reload(false);
} else {
alert("Failed to load the widgetset: " + url);
}
}
}
}, 15000);
var scriptTag = document.createElement('script');
scriptTag.setAttribute('type', 'text/javascript');
scriptTag.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(scriptTag);
widgetsets[widgetset] = {
pendingApps: []
};
};
var isInitializedInDom = function(appId) {
var appDiv = document.getElementById(appId);
if (!appDiv) {
return false;
}
for ( var i = 0; i < appDiv.childElementCount; i++) {
var className = appDiv.childNodes[i].className;
// If the app div contains a child with the class
// "v-app-loading" we have only received the HTML
// but not yet started the widget set
// (UIConnector removes the v-app-loading div).
if (className && className.indexOf("v-app-loading") != -1) {
return false;
}
}
return true;
};
window.vaadin = window.vaadin || {
initApplication: function(appId, config) {
var testbenchId = appId.replace(/-\d+$/, '');
if (apps[appId]) {
if (window.vaadin && window.vaadin.clients && window.vaadin.clients[testbenchId] && window.vaadin.clients[testbenchId].initializing) {
throw "Application " + appId + " is already being initialized";
}
if (isInitializedInDom(appId)) {
throw "Application " + appId + " already initialized";
}
}
log("init application", appId, config);
window.vaadin.clients[testbenchId] = {
isActive: function() {
return true;
},
initializing: true
};
var getConfig = function(name) {
var value = config[name];
return value;
};
var fetchRootConfig = function(callback) {
log('Fetching root config');
var url = getConfig('browserDetailsUrl');
if (!url) {
// No special url defined, use the same URL that loaded this page (without the fragment)
url = window.location.href.replace(/#.*/,'');
}
// Timestamp to avoid caching
url += ((/\?/).test(url) ? "&" : "?") + "v-" + (new Date()).getTime();
var params = "v-browserDetails=1";
var rootId = getConfig("v-rootId");
if (rootId !== undefined) {
params += "&v-rootId=" + rootId;
}
// Tell the UI what theme it is configured to use
var theme = getConfig('theme');
if (theme !== undefined) {
params += '&theme=' + encodeURIComponent(theme);
}
params += "&v-appId=" + appId;
var extraParams = getConfig('extraParams')
if (extraParams !== undefined) {
params += extraParams;
}
params += '&' + vaadin.getBrowserDetailsParameters(appId, getConfig('sendUrlsAsParameters'));
var r;
try {
r = new XMLHttpRequest();
} catch (e) {
r = new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
r.open('POST', url, true);
r.onreadystatechange = function (aEvt) {
if (r.readyState == 4) {
// Save responseStatus so as Offline Applications know what happened
// when loading root configuration from server, and depending on the
// error status display an error message or the offline UI.
config.rootResponseStatus = r.status;
config.rootResponseText = r.responseText;
var text = r.responseText;
if (r.status == 200){
log("Got root config response", text);
var updatedConfig = JSON.parse(text);
// Copy new properties to the config object
for (var property in updatedConfig) {
if (updatedConfig.hasOwnProperty(property)) {
config[property] = updatedConfig[property];
}
}
// Try bootstrapping again, this time without fetching missing info
bootstrapApp(false);
} else {
log('Error', r.statusText, text);
//Let TB waitForVaadin work again
delete window.vaadin.clients[testbenchId];
// Show the error in the app's div
var appDiv = document.getElementById(appId);
appDiv.innerHTML = text;
appDiv.style['overflow'] = 'auto';
}
// Run the fetchRootConfig callback if present.
callback && callback(r);
}
};
// send parameters as POST data
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
r.send(params);
log('sending request to ', url);
};
//Export public data
var app = {
getConfig: getConfig,
// Used when the app was started in offline, so as it is possible
// to defer root configuration loading until network is available.
fetchRootConfig: fetchRootConfig
};
apps[appId] = app;
if (!window.name) {
window.name = appId + '-' + Math.random();
}
var bootstrapApp = function(mayDefer) {
var vaadinDir = getConfig('vaadinDir');
var versionInfo = getConfig('versionInfo');
var themeUri = vaadinDir + 'themes/' + getConfig('theme');
loadTheme(themeUri, versionInfo && versionInfo['vaadinVersion']);
var widgetset = getConfig('widgetset');
var widgetsetUrl = getConfig('widgetsetUrl');
if (!widgetsetUrl) {
widgetsetUrl = vaadinDir + 'widgetsets/' + widgetset + "/" + widgetset + ".nocache.js?" + new Date().getTime();
}
var widgetsetReady = getConfig('widgetsetReady');
loadWidgetset(widgetsetUrl, widgetset, widgetsetReady);
if (getConfig('uidl') === undefined) {
if (mayDefer) {
fetchRootConfig();
} else {
throw "May not defer bootstrap any more";
}
} else {
if (widgetsets[widgetset].callback) {
log("Starting from bootstrap", appId);
widgetsets[widgetset].callback(appId);
} else {
log("Setting pending startup", appId);
widgetsets[widgetset].pendingApps.push(appId);
}
}
};
bootstrapApp(true);
if (getConfig("debug")) {
// TODO debug state is now global for the entire page, but should somehow only be set for the current application
window.vaadin.debug = true;
}
return app;
},
clients: {},
getAppIds: function() {
var ids = [ ];
for (var id in apps) {
if (apps.hasOwnProperty(id)) {
ids.push(id);
}
}
return ids;
},
getApp: function(appId) {
return apps[appId];
},
removeApp: function(appId) {
delete apps[appId];
},
loadTheme: loadTheme,
registerWidgetset: function(widgetset, callback) {
log("Widgetset registered", widgetset);
var ws = widgetsets[widgetset];
if (ws && ws.pendingApps) {
ws.callback = callback;
for(var i = 0; i < ws.pendingApps.length; i++) {
var appId = ws.pendingApps[i];
log("Starting from register widgetset", appId);
callback(appId);
}
ws.pendingApps = null;
}
},
getBrowserDetailsParameters: function(parentElementId, sendUrlsAsParameters) {
// Screen height and width
var params = 'v-sh=' + window.screen.height;
params += '&v-sw=' + window.screen.width;
// Window height and width
var cw = 0;
var ch = 0;
if(typeof(window.innerWidth) == 'number') {
// Modern browsers
cw = window.innerWidth;
ch = window.innerHeight;
} else {
// IE 8
cw = document.documentElement.clientWidth;
ch = document.documentElement.clientHeight;
}
params += '&v-cw=' + cw + '&v-ch=' + ch;
var d = new Date();
params += '&v-curdate=' + d.getTime();
var tzo1 = d.getTimezoneOffset(); // current offset
var dstDiff = 0;
var rtzo = tzo1;
for (var m=12;m>0;m--) {
d.setUTCMonth(m);
var tzo2 = d.getTimezoneOffset();
if (tzo1 != tzo2) {
dstDiff = (tzo1 > tzo2 ? tzo1-tzo2 : tzo2-tzo1); // offset w/o DST
rtzo = (tzo1 > tzo2 ? tzo1 : tzo2); // offset w/o DST
break;
}
}
// Time zone offset
params += '&v-tzo=' + tzo1;
// DST difference
params += '&v-dstd=' + dstDiff;
// Raw time zone offset
params += '&v-rtzo=' + rtzo;
// DST in effect?
params += '&v-dston=' + (tzo1 != rtzo);
var pe = document.getElementById(parentElementId);
if (pe) {
params += '&v-vw=' + pe.offsetWidth;
params += '&v-vh=' + pe.offsetHeight;
}
// Location
if (sendUrlsAsParameters !== false) {
params += '&v-loc=' + encodeURIComponent(location.href);
}
// Window name
if (window.name) {
params += '&v-wn=' + encodeURIComponent(window.name);
}
// Detect touch device support
var supportsTouch = false;
try {
document.createEvent("TouchEvent");
supportsTouch = true;
} catch (e) {
// Chrome and IE10 touch detection
supportsTouch = 'ontouchstart' in window
|| navigator.msMaxTouchPoints;
}
if (supportsTouch) {
params += "&v-td=1";
}
return params;
}
};
log('Vaadin bootstrap loaded');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment