/* * To change this template, choose Tools | Templates * and open the template in the editor. */ (function () { if (typeof (WebCom) == 'undefined') { WebCom = {}; } /*private class*/ function Resource (/*RC_TYPE*/ type, /*ResourceLocator*/ locator, /*Object*/ _statusHandler) { this.type = type; this.locator = locator; var statusHandler = _statusHandler; this.getURL = function () { return this.locator.getURL(); }; this.getStatusHandler = function() { return statusHandler; } }; /*private class*/ function ResourceLocator (baseURL, fileName) { this.baseURL = baseURL; this.fileName = fileName; this.getBaseURL = function() { return this.baseURL; }; this.getURL = function () { if (this.fileName != "") { return this.baseURL + "/" + this.fileName; } else { return this.baseURL; } }; }; /*private class*/ function LibraryWrapper(_libHandle) { var libHandle = _libHandle; this.getResourceURL = function (/*String*/ resourcePath) { return libHandle.getResourceURL(resourcePath); }; this.loadResource = function (/*String*/ resourcePath, /*String*/ resourceType) { return libHandle.getResourceURL(resourcePath, resourceType); }; }; /*public class*/ function Library(/* [String runtimeName], String packageName, String version, String[] scripts, String[] styles*/) { var args = Array.prototype.slice.call(arguments); if (args.length == 5) { this.runtimeName = args.shift(); WebCom.ResourceLoader.makeNameSpace(this.runtimeName); //var libWrapper = new LibraryWrapper(this); //var constructorName = parts.join("_"); //eval(constructorName + ".prototype = libWrapper;"); // //eval(this.runtimeName + "= new " + constructorName + "();"); } this.packageName = args[0]; this.version = args[1]; this.scripts = args[2]; this.styles = args[3]; this.getRuntimeName = function () { return this.runtimeName; } this.getPackageName = function () { return this.packageName; }; this.getVersion = function () { return this.version; }; this.getScripts = function () { return this.scripts; }; this.getStyles = function () { return this.styles; }; this.getResourceURL = function (/*String*/ resourcePath) { return WebCom.ResourceLoader.getResourceURL(resourcePath, this); }; //TODO: review if we need to expose the defer flag as well this.loadResource = function (/*String*/ resourcePath, /*Object*/ statusHandler, /*String*/ _resourceType) { if (resourcePath == null) { throw new Error("resource path cannot be empty"); } var resourceType = _resourceType; if (resourceType != null) { if (!WebCom.ResourceLoader.isResourceSupported(resourceType)) { throw new Error("Unsuported resource type " + resourceType ); } } else { resourceType = WebCom.ResourceLoader.getResourceType(resourcePath); } //load it now. no deferral! WebCom.ResourceLoader._loadResource(this.packageName, this.version, resourceType, null, resourcePath, false, statusHandler); }; }; function WebCom_ResourceLoader() { var counter = 0; var RC_TYPE = { SCRIPT : "SCRIPT", STYLE : "STYLE" }; this.RC_TYPE = RC_TYPE; var C_LATEST_VERSION_IDENTIFIER = "latest"; var SHARED_URL = "http://assets.webservices.websitepros.com"; var SHARED_SECURE_URL = "https://secure.websitepros.com/assets.webservices.websitepros.com"; var versionsMixEnabled = false; var isShared = true; var isSecure = false; var resourceCache = {}; var librariesRegistry = {}; var resourcesQueue = []; var isDocumentClosed = false; var userAgent = navigator.userAgent.toLowerCase(); var browser = {msie: /msie/.test( userAgent ) && !/opera/.test( userAgent )}; var privateURI = ""; var queueInProgress = false; //holds the default extension per resource type var rcExtensionMap = {}; rcExtensionMap[RC_TYPE.SCRIPT] = "js"; rcExtensionMap[RC_TYPE.STYLE] = "css"; //holds the starting URI per resource type var rcBaseURIMap = {}; rcBaseURIMap[RC_TYPE.SCRIPT] = "javascript"; /** * Builds the locator for given named versioned resource. If _isShared * is not set then the loader's isShared member value is used. If shared the * resource will be relative to a shared URL. Otherwise it will be be relative * to the host page this loader was referenced from. Locator rules * * 1. Folders are per Java package convention * 2. Top package is appended per resource type (ie js/, css/) * 3. File name is built from last dot occurence till the end * * Examples: * * "com.jquery", null , false -> js/com/jquery/latest/jquery.js * "com.web.coolapp", null , false -> js/com/web/coolapp/coolapp.js * * @param name per Java package convention * @param version if null will default to 'latest' when resolving the URI * @param type * @param _isShared if true a shared URL will be used. otherwise the URL will * be relative to page this loader resides on */ /*private ResourceLocator*/ function getResourceLocator(/*string*/name, /*string*/ version, /*RC_TYPE*/ type, /*boolean*/ _isShared) { if (name == "") { throw new Error("Resource name cannot be empty!"); } if (typeof _isShared == 'undefined') { _isShared = isShared; } var url = ""; if (_isShared) { url = isSecure ? SHARED_SECURE_URL : SHARED_URL; } else { if (privateURI != "") { var location = window.location; url = location.protocol + "//" + location.host + ":" + location.port + "/" + privateURI; } else { url = window.location.toString(); url = url.substring(0, url.lastIndexOf("/")); } } var baseUri = ""; var baseName = ""; if (name.indexOf(".") != -1 ) { baseUri = name.replace(/\./g, '/'); var parts = name.split("."); baseName = parts[parts.length - 1]; } else { baseUri = baseName = name; } baseUri = url + "/" + rcBaseURIMap[type] + "/" + baseUri + "/" + version; return new ResourceLocator(baseUri, baseName + "." + rcExtensionMap[type]); }; function isResourceSupported(resourceType) { return resourceType !=null && resourceType.match(/^js|css$/) != null; }; function getResourceType (/*String*/ resourcePath) { if (resourcePath == null) { throw new Error("resource path cannot be empty"); } var extension; if (extension = resourcePath.match(/js|css$/) != null) { return (extension[0] == "js") ? RC_TYPE.SCRIPT : RC_TYPE.STYLE; } else { throw new Error("Unsuported resource type " + resourcePath ); } }; function loadResource(/*string*/ resourcePath) { var resource = new Resource(RC_TYPE.SCRIPT, new ResourceLocator(this.getResourceURL(resourcePath))); if (isDocumentClosed) { injectResourceIntoDOM_createElement(resource); } else { resourcesQueue.push( resource ); } }; /** * Loads the resource identified by name, version * and relativePath into current DOM. If deferred is true the * loading will occur at a later time when {@link #flushResourcesQueue} is * invoked. * * @param name per Java package convention * @param version if null will default to 'latest' when resolving the URI * @param type * @param _isShared if true a shared URL will be used. otherwise the URL will * be relative to page this loader resides on * @param relativePath relative to baseURL of name/version * @param deferred whether to inject it now into DOM or deferr it for later * * @throws Error if mixing is currently disabled and an attempt to mix * different version of a library is detected */ /*private*/ function _loadResource (/*string*/name, /*string*/ version, /*RC_TYPE*/ type, /*boolean*/ _isShared, /*string*/ relativePath, /*boolean*/ deferred, /*Object*/ statusHandler) { if (name == "") { return; //nothing to do really w/ an empty component } if (version == null || version == "") { version = C_LATEST_VERSION_IDENTIFIER; //empty version we can handle } var libraryKey = name + "_" + version; var resourceKey = (relativePath != null && relativePath.length > 0) ? libraryKey + "_" + relativePath : libraryKey; if (resourceCache[libraryKey] != null) { if (!versionsMixEnabled && librariesRegistry[name] != version) { throw new Error("Version " + librariesRegistry[name] + " of " + name + " is already loaded. Cannot load " + version + " at the same time!" ); } if (resourceCache[resourceKey] == null) { resourceCache[resourceKey] = new ResourceLocator(resourceCache[libraryKey].getBaseURL(), relativePath); } else { return; } } else { if (libraryKey != resourceKey) { throw new Error("A dependent resource cannot be loaded w/o loading its parent library"); } librariesRegistry[name] = version; resourceCache[libraryKey] = getResourceLocator(name, version, type, _isShared); } if (deferred) { if (isDocumentClosed) { throw new Error("Cannot defer after the document is closed"); } resourcesQueue.push( new Resource(type, resourceCache[resourceKey] ) ); } else { injectResourceIntoDOM( new Resource(type, resourceCache[resourceKey], statusHandler ) ); } }; function getResourceURL(/*string*/ resourcePath, /*Library*/ library) { if (library != null) { var libraryKey = library.getPackageName() + "_" + library.getVersion(); if (resourceCache[libraryKey] != null) { return new ResourceLocator(resourceCache[libraryKey].getBaseURL(), resourcePath).getURL(); } else { throw new Error("Load the library first then ask for a dependent resource!"); } } else { return isSecure ? SHARED_SECURE_URL : SHARED_URL + "/" + resourcePath; } }; /** * Injects the resource into DOM by generating the appropriate * markup. Currently SCRIPT and STYLE elements are supported. * * @param resource */ /*private*/ function injectResourceIntoDOM(/*Resource*/ resource) { (isDocumentClosed) ? injectResourceIntoDOM_createElement(resource) : injectResourceIntoDOM_documentWrite(resource); }; /*private*/function injectResourceIntoDOM_documentWrite(/*Resource*/ resource) { if (resource.type == RC_TYPE.SCRIPT) { document.write("