require('mootools'); Vn = module.exports = {}; Object.assign(Vn, { Locale : require('./locale') ,Enum : require('./enum') ,Type : require('./type') ,Object : require('./object') ,Mutators : require('./mutators') ,Browser : require('./browser') ,Cookie : require('./cookie') ,Date : require('./date') ,Value : require('./value') ,Url : require('./url') ,LotIface : require('./lot-iface') ,Lot : require('./lot') ,LotQuery : require('./lot-query') ,Hash : require('./hash') ,ParamIface : require('./param-iface') ,Param : require('./param') ,Spec : require('./spec') ,Model : require('./model') ,ModelIface : require('./model-iface') ,ModelProxy : require('./model-proxy') ,IteratorIface : require('./iterator-iface') ,Iterator : require('./iterator') ,Form : require('./form') ,Node : require('./node') ,NodeBuilder : require('./node-builder') ,Component : require('./component') ,Builder : require('./builder') ,JsonException : require('./json-exception') ,JsonConnection : require('./json-connection') ,Config: {} ,includes: {} ,cssIncludes: {} ,currentDeps: [] ,currentCallback: null ,head: document.getElementsByTagName('head')[0] ,isMobileCached: null ,getVersion() { if (this._version === undefined) { var re = /[; ]vnVersion=([^\\s;]*)/; var sMatch = (' '+ document.cookie).match(re); this._version = (sMatch) ? '?'+ unescape(sMatch[1]) : ''; } return this._version; } ,setVersion(version) { document.cookie = `vnVersion=${version}; SameSite=Lax;`; } /** * 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(fileName) { var cssData = this.cssIncludes[fileName]; if (!cssData) { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = fileName + this.getVersion(); 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(fileName) { var cssData = this.cssIncludes[fileName]; if (cssData && cssData.included) { cssData.link.disabled = true; cssData.included = false; } } ,_createIncludeData(path) { var includeData = { path, depCount: 0, success: false, loaded: false, callbacks: [], dependants: [], }; this.includes[path] = includeData; return includeData; } ,_resolveDeps(includeData) { includeData.success = true; var callbacks = includeData.callbacks; if (callbacks) for (var i = 0; i < callbacks.length; i++) callbacks[i](includeData.loaded); var dependants = includeData.dependants; if (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; delete includeData.dependants; delete includeData.depCount; } /** * 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(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.currentDeps; for (var i = 0; i < scripts.length; i++) { var path = scripts[i].src.substr(basePath.length); path = path.substr(0, path.indexOf('.js')) +'.js'; var includeData = this.includes[path]; if (includeData === undefined) { this.currentDeps = includes; var includeData = this._createIncludeData(path); this._onScriptLoad(includeData, true); } } includeData.callbacks.push(this._onMainDepsLoad.bind(this)); window.addEventListener('load', this._onWindowLoad.bind(this)); } ,_onMainDepsLoad() { this.mainDepsLoaded = true; this._callMain(); } ,_onWindowLoad() { this.windowReady = true; this._callMain(); } ,_callMain() { if (this.mainCallback && this.windowReady && this.mainDepsLoaded) this.mainCallback(); } /** * Includes a set of javascript files and sets it as dependecies of the * current script. * * @param {...} The list of files as function arguments */ ,include() { for (var i = 0; i < arguments.length; i++) { var includeData = this._realIncludeJs(arguments[i] +'.js'); if (!includeData.success) this.currentDeps.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() { for (var i = 0; i < arguments.length; i++) { var includeData = this._realLoadXml(arguments[i]); if (!includeData.success) this.currentDeps.push(includeData); } } /** * Sets the function that will be called when current script dependencies * are resolved. * * @param {Function} callback The callback function */ ,define(callback) { this.currentCallback = callback; } ,async _handleCallback(includeData) { if (includeData.success) return; return new Promise((resolve, reject) => { function callback(loaded) { if (!loaded) return reject(new Error(`Could not load resource: ${includeData.path}`)); resolve(); } includeData.callbacks.push(callback); }); } /** * 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 */ ,async includeJs(fileName, skipVersion) { var includeData = this._realIncludeJs(fileName, skipVersion); return this._handleCallback(includeData); } ,_realIncludeJs(fileName, skipVersion) { var includeData = this.includes[fileName]; if (includeData === undefined) { includeData = this._createIncludeData(fileName); var src = fileName; if (!skipVersion) src = src + this.getVersion(); var script = document.createElement('script'); script.type = 'text/javascript'; script.async = false; script.src = src; script.onload = () => this._onScriptLoad(includeData, true); script.onerror = () => this._onScriptLoad(includeData, false); script.onreadystatechange = () => this._onScriptStateChange(includeData, script); this.head.appendChild(script); } return includeData; } ,_onScriptStateChange(includeData, script) { if (script.readyState == 'complete') this._onScriptLoad(includeData, true); } ,_onScriptLoad(includeData, loaded) { includeData.loaded = loaded; if (loaded) { if (this.currentCallback) includeData.callbacks.unshift(this.currentCallback); var includes = this.currentDeps; 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.currentDeps = []; this.currentCallback = null; } /** * Request an XML file. * * @param {string} path The file path */ ,async loadXml(path) { var includeData = this._realLoadXml(path); return this._handleCallback(includeData); } ,_realLoadXml(path) { var includeData = this.includes[path]; if (includeData === undefined) { includeData = this._createIncludeData(path); var request = new XMLHttpRequest(); request.onreadystatechange = () => this._onXmlReady(includeData, request); request.open('get', path + this.getVersion(), true); request.send(); } return includeData; } ,_onXmlReady(includeData, request) { if (request.readyState != 4) return; includeData.loaded = request.status == 200; if (includeData.loaded) 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(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() { if (this.isMobileCached === null) { var regExp = /(Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone)/i; this.isMobileCached = navigator.userAgent.match(regExp); } return this.isMobileCached; } });