|
|
@@ -1,369 +1,377 @@ |
|
|
|
(function() { |
|
|
|
var apps = {}; |
|
|
|
var themesLoaded = {}; |
|
|
|
var widgetsets = {}; |
|
|
|
|
|
|
|
|
|
|
|
(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() {}; |
|
|
|
//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); |
|
|
|
}; |
|
|
|
//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; |
|
|
|
//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]; |
|
|
|
}, |
|
|
|
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'); |
|
|
|
|
|
|
|
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]; |
|
|
|
}, |
|
|
|
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); |
|
|
|
|
|
|
|
// Time zone id (if available) |
|
|
|
try { |
|
|
|
params += '&v-tzid=' + encodeURIComponent(Intl.DateTimeFormat().resolvedOptions().timeZone); |
|
|
|
} catch (err) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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'); |
|
|
|
})(); |