hedera-web/web/js/vn/vn.js

401 lines
8.5 KiB
JavaScript
Executable File

/**
* The main namespace.
**/
var Vn =
{
Config: {}
,includes: {}
,cssIncludes: {}
,xmlIncludes: {}
,tmpIncludes: []
,tmpDefine: null
,customTags: {}
,head: document.getElementsByTagName ('head')[0]
,isMobileCached: null
/**
* Includes a new CSS stylesheet in the current document, if the stylesheet
* is already included, does nothing.
*
* @param {string} fileName The stylesheet file name
**/
,includeCss: function (fileName)
{
var cssData = this.cssIncludes[fileName];
if (!cssData)
{
var link = document.createElement ('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = fileName +'?'+ Vn.Cookie.get ('hedera_version');
this.head.appendChild (link);
this.cssIncludes[fileName] =
{
included: true
,link: link
};
}
else if (!cssData.included)
{
cssData.link.disabled = false;
cssData.included = true;
}
}
/**
* Excludes a CSS stylesheet from the current document.
*
* @param {string} fileName The stylesheet file name
**/
,excludeCss: function (fileName)
{
var cssData = this.cssIncludes[fileName];
if (cssData && cssData.included)
{
cssData.link.disabled = true;
cssData.included = false;
}
}
/**
* Initializes the library and calls the passed function when all
* includes and its dependencies are resolved.
* Should be called on the last statically incuded script.
*
* @param {Function} callback The main function
**/
,main: function (callback)
{
if (this.mainCalled)
{
Vn.warning ("Vn: main method should be called only once");
return;
}
this.mainCalled = true;
this.mainCallback = callback;
var basePath = location.protocol +'//'+ location.host;
basePath += location.port ? ':'+ location.port : '';
basePath += location.pathname;
var scripts = this.head.getElementsByTagName ('script');
var includes = this.tmpIncludes;
for (var i = 0; i < scripts.length; i++)
{
var relPath = scripts[i].src.substr (basePath.length);
relPath = relPath.substr (0, relPath.indexOf ('.js'));
var includeData = this.includes[relPath];
if (includeData === undefined)
{
includeData = {
depCount: 0
,callbacks: []
,loaded: true
,dependants: []
,success: true
};
this.includes[relPath] = includeData;
}
if (i == scripts.length - 1)
includeData.callbacks.push (this._onMainDepsLoad.bind (this));
this.tmpIncludes = includes;
this._onScriptLoad (includeData, true);
}
window.addEventListener ('load', this._onWindowLoad.bind (this));
}
,_onMainDepsLoad: function ()
{
this.mainDepsLoaded = true;
this._callMain ();
}
,_onWindowLoad: function ()
{
this.windowReady = true;
this._callMain ();
}
,_callMain: function ()
{
if (this.mainCallback && this.windowReady && this.mainDepsLoaded)
this.mainCallback ();
}
,_handleCallback: function (includeData, callback)
{
if (!callback)
return;
if (includeData.loaded)
callback (includeData.success);
else
includeData.callbacks.push (callback);
}
/**
* Includes a set of javascript files and sets it as dependecies of the
* current script.
*
* @param {...} The list of files as function arguments
**/
,include: function ()
{
for (var i = 0; i < arguments.length; i++)
{
var includeData = this._realIncludeJs (arguments[i] +'.js');
if (!includeData.loaded)
this.tmpIncludes.push (includeData);
}
}
/**
* Downloads a set of resources and sets it as dependecies of the
* current script.
*
* @param {...} The list of files as function arguments
**/
,resource: function ()
{
for (var i = 0; i < arguments.length; i++)
{
var includeData = this._realLoadXml (arguments[i]);
if (!includeData.loaded)
this.tmpIncludes.push (includeData);
}
}
/**
* Sets the function that will be called when current script dependencies
* are resolved.
*
* @param {Function} callback The callback function
**/
,define: function (callback)
{
this.tmpDefine = callback;
}
/**
* Includes an entire Javascript library including it's localized file.
*
* @param {string} libName The folder of the library
* @param {Array<string>} files Array with every library file name
**/
,includeLib: function (libName, files)
{
Vn.Locale.loadScript ('js/'+ libName +'.js');
for (var i = 0; i < files.length; i++)
this.include ('js/'+ libName +'/'+ files[i]);
}
/**
* Includes a new Javascript in the current document, if the script
* is already included, does nothing and calls the callback.
*
* @param {string} fileName The script file name
* @param {Function} callback The function to call when script is
* downloaded and included
**/
,includeJs: function (fileName, callback, skipVersion)
{
var includeData = this._realIncludeJs (fileName, skipVersion);
this._handleCallback (includeData, callback);
}
,_realIncludeJs: function (fileName, skipVersion)
{
var includeData = this.includes[fileName];
if (includeData === undefined)
{
var src = fileName;
if (!skipVersion)
src = src +'?'+ Vn.Cookie.get ('hedera_version');
var script = document.createElement ('script');
script.type = 'text/javascript';
script.async = false;
script.src = src;
includeData = {
depCount: 0
,callbacks: []
,loaded: false
,dependants: []
,success: false
};
script.onload =
this._onScriptLoad.bind (this, includeData, true);
script.onerror =
this._onScriptLoad.bind (this, includeData, false);
script.onreadystatechange =
this._onScriptStateChange.bind (this, includeData, script);
this.includes[fileName] = includeData;
this.head.appendChild (script);
}
return includeData;
}
,_onScriptStateChange: function (includeData, script)
{
if (script.readyState == 'complete')
this._onScriptLoad (includeData, true);
}
,_onScriptLoad: function (includeData, success)
{
includeData.success = success;
if (success)
{
if (this.tmpDefine)
includeData.callbacks.push (this.tmpDefine);
var includes = this.tmpIncludes;
if (includes && includes.length > 0)
{
includeData.depCount = includes.length;
for (var i = 0; i < includes.length; i++)
includes[i].dependants.push (includeData);
}
else
this.resolveDeps (includeData);
}
else
this.resolveDeps (includeData);
this.tmpIncludes = [];
this.tmpDefine = null;
}
,resolveDeps: function (includeData)
{
includeData.loaded = true;
var callbacks = includeData.callbacks;
for (var i = 0; i < callbacks.length; i++)
callbacks[i] (includeData.success);
var dependants = includeData.dependants;
for (var i = 0; i < dependants.length; i++)
{
var dependant = dependants[i];
dependant.depCount--;
if (dependant.depCount == 0)
this.resolveDeps (dependant);
}
delete includeData.callbacks;
}
/**
* Request an XML file.
*
* @param {string} path The file path
* @param {Function} callback The function to call when file is downloaded
**/
,loadXml: function (path, callback)
{
var includeData = this._realLoadXml (path);
this._handleCallback (includeData, callback);
}
,_realLoadXml: function (path)
{
var includeData = this.includes[path];
if (includeData === undefined)
{
includeData = {
callbacks: []
,loaded: false
,dependants: []
,depCount: 0
,success: false
,xml: null
};
var request = new XMLHttpRequest ();
request.onreadystatechange =
this._onXmlReady.bind (this, includeData, request);
request.open ('get',
path +'?'+ Vn.Cookie.get ('hedera_version'), true);
request.send ();
this.includes[path] = includeData;
}
return includeData;
}
,_onXmlReady: function (includeData, request)
{
if (request.readyState != 4)
return;
includeData.success = request.status == 200;
if (includeData.success)
includeData.xml = request.responseXML;
this.resolveDeps (includeData);
}
/**
* Gets the DOM object from an included XML file.
*
* @param {string} path The file path
* @return {Object} The DOM object
**/
,getXml: function (path)
{
var includeData = this.includes[path];
if (!(includeData && includeData.success))
return null;
return includeData.xml;
}
/**
* Checks if user is using a mobile browser.
*
* return {boolean} %true if is mobile, %false otherwise.
**/
,isMobile: function ()
{
if (this.isMobileCached === null)
{
var regExp = /(Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone)/i;
this.isMobileCached = navigator.userAgent.match (regExp);
}
return this.isMobileCached;
}
};