diff options
Diffstat (limited to 'server/src/main/resources/VAADIN/vaadinBootstrap.js')
-rw-r--r-- | server/src/main/resources/VAADIN/vaadinBootstrap.js | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/server/src/main/resources/VAADIN/vaadinBootstrap.js b/server/src/main/resources/VAADIN/vaadinBootstrap.js new file mode 100644 index 0000000000..89514dbcc2 --- /dev/null +++ b/server/src/main/resources/VAADIN/vaadinBootstrap.js @@ -0,0 +1,359 @@ +(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) { + if (widgetsets[widgetset]) { + return; + } + log("load widgetset", url, widgetset); + setTimeout(function() { + if (!isWidgetsetLoaded(widgetset)) { + 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(); + } + loadWidgetset(widgetsetUrl, widgetset); + + 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'); +})(); |