From 160a1dd7665a148606326944b2a498a28d493faf Mon Sep 17 00:00:00 2001 From: Robert Axelsen Date: Tue, 8 Nov 2016 09:34:37 +0100 Subject: [PATCH] TT#5020 Implement ngcp-csc account module mockup Implement ngcp-csc account module mockup, linked with corresponsing logged in ACL account. Also remove some console.logs, delete unneeded bootstrap.js and bootstrap.css files, and replace main model username object with formula object to correctly display username in header also immediately after log in. Cleanups and small refactoring in new patchset. Change-Id: I91d4b7bfbaf7d27908640b9f730024f63b729695 --- app/locales.js | 99 +- app/store/NavigationTree.js | 2 +- bootstrap.css | 9 - bootstrap.js | 2601 ----------------- .../sass/src/view/pages/account/Account.scss | 4 + classic/src/view/main/MainModel.js | 9 +- classic/src/view/pages/account/Account.js | 50 + .../view/pages/account/AccountController.js | 38 + classic/src/view/pages/account/AccountForm.js | 58 + .../src/view/pages/account/AccountModel.js | 17 + .../callbarring/CallBarringController.js | 3 - 11 files changed, 262 insertions(+), 2628 deletions(-) delete mode 100644 bootstrap.css delete mode 100644 bootstrap.js create mode 100644 classic/sass/src/view/pages/account/Account.scss create mode 100644 classic/src/view/pages/account/Account.js create mode 100644 classic/src/view/pages/account/AccountController.js create mode 100644 classic/src/view/pages/account/AccountForm.js create mode 100644 classic/src/view/pages/account/AccountModel.js diff --git a/app/locales.js b/app/locales.js index 84089498..c3c873bd 100644 --- a/app/locales.js +++ b/app/locales.js @@ -192,7 +192,6 @@ Ext.define('Ngcp.csc.locales', { sp: 'all calls' } }, - callbarring: { title: { en: 'Call barring for incoming and outgoing calls.', @@ -314,14 +313,92 @@ Ext.define('Ngcp.csc.locales', { sp: 'Please use digits only and include the area code of the number. You may use the wildcard characters "?" for one and "*" for an indefinite number of arbitrary digits.' }, new_entry_anonymous: { - en: 'To block anonymous calls you may just submit the empty string.', - it: 'To block anonymous calls you may just submit the empty string.', - de: 'To block anonymous calls you may just submit the empty string.', - fr: 'To block anonymous calls you may just submit the empty string.', - sp: 'To block anonymous calls you may just submit the empty string.' + en: 'To block anonymous calls you may just submit the empty string.', + it: 'To block anonymous calls you may just submit the empty string.', + de: 'To block anonymous calls you may just submit the empty string.', + fr: 'To block anonymous calls you may just submit the empty string.', + sp: 'To block anonymous calls you may just submit the empty string.' + } + }, + account: { + title: { + en: 'Your personal settings.', + it: 'Your personal settings.', + de: 'Your personal settings.', + fr: 'Your personal settings.', + sp: 'Your personal settings.' + }, + subtitle: { + en: 'PASSWORD', + it: 'PASSWORD', + de: 'PASSWORD', + fr: 'PASSWORD', + sp: 'PASSWORD' + }, + password_instructions: { + en: 'You may change the password for your self-administration login here.', + it: 'You may change the password for your self-administration login here.', + de: 'You may change the password for your self-administration login here.', + fr: 'You may change the password for your self-administration login here.', + sp: 'You may change the password for your self-administration login here.' + }, + change_password: { + en: 'change password', + it: 'change password', + de: 'change password', + fr: 'change password', + sp: 'change password' + }, + reset_form: { + en: 'reset form', + it: 'reset form', + de: 'reset form', + fr: 'reset form', + sp: 'reset form' + }, + password_short: { + en: 'The password is too short, please use 6 characters at least.', + it: 'The password is too short, please use 6 characters at least.', + de: 'The password is too short, please use 6 characters at least.', + fr: 'The password is too short, please use 6 characters at least.', + sp: 'The password is too short, please use 6 characters at least.' + }, + wrong_password: { + en: 'Wrong password, please verify your input.', + it: 'Wrong password, please verify your input.', + de: 'Wrong password, please verify your input.', + fr: 'Wrong password, please verify your input.', + sp: 'Wrong password, please verify your input.' + }, + password_match: { + en: 'Passwords do not match, please try again.', + it: 'Passwords do not match, please try again.', + de: 'Passwords do not match, please try again.', + fr: 'Passwords do not match, please try again.', + sp: 'Passwords do not match, please try again.' + }, + change_success: { + en: 'The password has been changed successfully.', + it: 'The password has been changed successfully.', + de: 'The password has been changed successfully.', + fr: 'The password has been changed successfully.', + sp: 'The password has been changed successfully.' + }, + enter_current: { + en: 'Please enter your current password.', + it: 'Please enter your current password.', + de: 'Please enter your current password.', + fr: 'Please enter your current password.', + sp: 'Please enter your current password.' + }, + username: { + en: 'username', + it: 'username', + de: 'username', + fr: 'username', + sp: 'username' } }, - filters: { search: { en: 'SEARCH', @@ -462,7 +539,6 @@ Ext.define('Ngcp.csc.locales', { sp: 'save settings' } } - }, chat: { title: { @@ -486,8 +562,8 @@ Ext.define('Ngcp.csc.locales', { fr: 'Chat group name', sp: 'Chat group name' }, - msg_box:{ - empty_text:{ + msg_box: { + empty_text: { en: 'Type a message', it: 'Type a message', de: 'Type a message', @@ -502,7 +578,7 @@ Ext.define('Ngcp.csc.locales', { fr: 'You can start a private conversation with {0} here.', sp: 'You can start a private conversation with {0} here.' }, - alerts:{ + alerts: { user_ddrop: { en: 'Only users can be dropped', it: 'Only users can be dropped', @@ -655,7 +731,6 @@ Ext.define('Ngcp.csc.locales', { fr: 'Videocall', sp: 'Videocall' } - } } }) diff --git a/app/store/NavigationTree.js b/app/store/NavigationTree.js index d072b080..9665caeb 100644 --- a/app/store/NavigationTree.js +++ b/app/store/NavigationTree.js @@ -68,7 +68,7 @@ Ext.define('NgcpCsc.store.NavigationTree', { }, { text: 'Account', iconCls: 'x-fa fa-user', - viewType: 'pageblank', + viewType: 'account', routeId: 'account', acl: ['administrator', 'restricted', 'host'], leaf: true diff --git a/bootstrap.css b/bootstrap.css deleted file mode 100644 index 5163fc58..00000000 --- a/bootstrap.css +++ /dev/null @@ -1,9 +0,0 @@ - - -/* - * This file is generated by Sencha Cmd and should NOT be edited. It redirects - * to the most recently built CSS file for the application to allow index.html - * in the development directory to load properly (i.e., "dev mode"). - */ -@import 'build/production/NgcpCsc/resources/NgcpCsc-all.css'; - diff --git a/bootstrap.js b/bootstrap.js deleted file mode 100644 index 65f30071..00000000 --- a/bootstrap.js +++ /dev/null @@ -1,2601 +0,0 @@ -var Ext = Ext || {}; -Ext.manifest = Ext.manifest || "classic.json"; -// @tag core -// @define Ext.Boot - -var Ext = Ext || {}; - -// -/** - * @class Ext.Boot - * @singleton - * @private - */ -Ext.Boot = Ext.Boot || (function (emptyFn) { - - var doc = document, - _emptyArray = [], - _config = { - /** - * @cfg {Boolean} [disableCaching=true] - * If `true` current timestamp is added to script URL's to prevent caching. - * In debug builds, adding a "cache" or "disableCacheBuster" query parameter - * to the page's URL will set this to `false`. - */ - disableCaching: (/[?&](?:cache|disableCacheBuster)\b/i.test(location.search) || - !(/http[s]?\:/i.test(location.href)) || - /(^|[ ;])ext-cache=1/.test(doc.cookie)) ? false : - true, - - /** - * @cfg {String} [disableCachingParam="_dc"] - * The query parameter name for the cache buster's timestamp. - */ - disableCachingParam: '_dc', - - /** - * @cfg {Boolean} loadDelay - * Millisecond delay between asynchronous script injection (prevents stack - * overflow on some user agents) 'false' disables delay but potentially - * increases stack load. - */ - loadDelay: false, - - /** - * @cfg {Boolean} preserveScripts - * `false` to remove asynchronously loaded scripts, `true` to retain script - * element for browser debugger compatibility and improved load performance. - */ - preserveScripts: true, - - /** - * @cfg {String} [charset=UTF-8] - * Optional charset to specify encoding of dynamic content. - */ - charset: 'UTF-8' - }, - - _assetConfig= {}, - - cssRe = /\.css(?:\?|$)/i, - resolverEl = doc.createElement('a'), - isBrowser = typeof window !== 'undefined', - _environment = { - browser: isBrowser, - node: !isBrowser && (typeof require === 'function'), - phantom: (window && (window._phantom || window.callPhantom)) || /PhantomJS/.test(window.navigator.userAgent) - }, - _tags = (Ext.platformTags = {}), - - _apply = function (object, config, defaults) { - if (defaults) { - _apply(object, defaults); - } - if (object && config && typeof config === 'object') { - for (var i in config) { - object[i] = config[i]; - } - } - return object; - }, - _merge = function() { - var lowerCase = false, - obj = Array.prototype.shift.call(arguments), - index, i, len, value; - - if (typeof arguments[arguments.length - 1] === 'boolean') { - lowerCase = Array.prototype.pop.call(arguments); - } - - len = arguments.length; - for (index = 0; index < len; index++) { - value = arguments[index]; - if (typeof value === 'object') { - for (i in value) { - obj[lowerCase ? i.toLowerCase() : i] = value[i]; - } - } - } - - return obj; - }, - _getKeys = (typeof Object.keys == 'function') ? - function(object){ - if (!object) { - return []; - } - return Object.keys(object); - } : - function(object) { - var keys = [], - property; - - for (property in object) { - if (object.hasOwnProperty(property)) { - keys.push(property); - } - } - - return keys; - }, - /* - * The Boot loader class manages Request objects that contain one or - * more individual urls that need to be loaded. Requests can be performed - * synchronously or asynchronously, but will always evaluate urls in the - * order specified on the request object. - */ - Boot = { - loading: 0, - loaded: 0, - apply: _apply, - env: _environment, - config: _config, - - /** - * @cfg {Object} assetConfig - * A map (url->assetConfig) that contains information about assets loaded by the Microlaoder. - */ - assetConfig: _assetConfig, - - // Keyed by absolute URL this object holds "true" if that URL is already loaded - // or an array of callbacks to call once it loads. - scripts: { - /* - Entry objects - - 'http://foo.com/bar/baz/Thing.js': { - done: true, - el: scriptEl || linkEl, - preserve: true, - requests: [ request1, ... ] - } - */ - }, - - /** - * contains the current script name being loaded - * (loadSync or sequential load only) - */ - currentFile: null, - suspendedQueue: [], - currentRequest: null, - - // when loadSync is called, need to cause subsequent load requests to also be loadSync, - // eg, when Ext.require(...) is called - syncMode: false, - - /* - * simple helper method for debugging - */ - - /** - * enables / disables loading scripts via script / link elements rather - * than using ajax / eval - */ - useElements: true, - - listeners: [], - - Request: Request, - - Entry: Entry, - - allowMultipleBrowsers: false, - - browserNames: { - ie: 'IE', - firefox: 'Firefox', - safari: 'Safari', - chrome: 'Chrome', - opera: 'Opera', - dolfin: 'Dolfin', - edge: 'Edge', - webosbrowser: 'webOSBrowser', - chromeMobile: 'ChromeMobile', - chromeiOS: 'ChromeiOS', - silk: 'Silk', - other: 'Other' - }, - - osNames: { - ios: 'iOS', - android: 'Android', - windowsPhone: 'WindowsPhone', - webos: 'webOS', - blackberry: 'BlackBerry', - rimTablet: 'RIMTablet', - mac: 'MacOS', - win: 'Windows', - tizen: 'Tizen', - linux: 'Linux', - bada: 'Bada', - chromeOS: 'ChromeOS', - other: 'Other' - }, - - browserPrefixes: { - ie: 'MSIE ', - edge: 'Edge/', - firefox: 'Firefox/', - chrome: 'Chrome/', - safari: 'Version/', - opera: 'OPR/', - dolfin: 'Dolfin/', - webosbrowser: 'wOSBrowser/', - chromeMobile: 'CrMo/', - chromeiOS: 'CriOS/', - silk: 'Silk/' - }, - - // When a UA reports multiple browsers this list is used to prioritize the 'real' browser - // lower index number will win - browserPriority: [ - 'edge', - 'opera', - 'dolfin', - 'webosbrowser', - 'silk', - 'chromeiOS', - 'chromeMobile', - 'ie', - 'firefox', - 'safari', - 'chrome' - ], - - osPrefixes: { - tizen: '(Tizen )', - ios: 'i(?:Pad|Phone|Pod)(?:.*)CPU(?: iPhone)? OS ', - android: '(Android |HTC_|Silk/)', // Some HTC devices ship with an OSX userAgent by default, - // so we need to add a direct check for HTC_ - windowsPhone: 'Windows Phone ', - blackberry: '(?:BlackBerry|BB)(?:.*)Version\/', - rimTablet: 'RIM Tablet OS ', - webos: '(?:webOS|hpwOS)\/', - bada: 'Bada\/', - chromeOS: 'CrOS ' - }, - - fallbackOSPrefixes: { - windows: 'win', - mac: 'mac', - linux: 'linux' - }, - - devicePrefixes: { - iPhone: 'iPhone', - iPod: 'iPod', - iPad: 'iPad' - }, - - maxIEVersion: 12, - - - /** - * The default function that detects various platforms and sets tags - * in the platform map accordingly. Examples are iOS, android, tablet, etc. - * @param tags the set of tags to populate - */ - detectPlatformTags: function () { - var me = this, - ua = navigator.userAgent, - isMobile = /Mobile(\/|\s)/.test(ua), - element = document.createElement('div'), - isEventSupported = function (name, tag) { - if (tag === undefined) { - tag = window; - } - - var eventName = 'on' + name.toLowerCase(), - isSupported = (eventName in element); - - if (!isSupported) { - if (element.setAttribute && element.removeAttribute) { - element.setAttribute(eventName, ''); - isSupported = typeof element[eventName] === 'function'; - - if (typeof element[eventName] !== 'undefined') { - element[eventName] = undefined; - } - - element.removeAttribute(eventName); - } - } - - return isSupported; - }, - - // Browser Detection - getBrowsers = function () { - var browsers = {}, - maxIEVersion, prefix, - value, key, index, len, match, version, matched; - - // MS Edge browser (and possibly others) can report multiple browsers in the UserAgent - // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240" - // we use this to prioritize the actual browser in this situation - len = me.browserPriority.length; - for (index = 0; index < len; index++) { - key = me.browserPriority[index]; - if (!matched) { - value = me.browserPrefixes[key]; - match = ua.match(new RegExp('(' + value + ')([\\w\\._]+)')); - version = match && match.length > 1 ? parseInt(match[2]) : 0; - if (version) { - matched = true; - } - } else { - version = 0; - } - browsers[key] = version; - } - - //Deal with IE document mode - if (browsers.ie) { - var mode = document.documentMode; - - if (mode >= 8) { - browsers.ie = mode; - } - } - - // Fancy IE greater than and less then quick tags - version = browsers.ie || false; - maxIEVersion = Math.max(version, me.maxIEVersion); - - for (index = 8; index <= maxIEVersion; ++index) { - prefix = 'ie' + index; - browsers[prefix + 'm'] = version ? version <= index : 0; - browsers[prefix] = version ? version === index : 0; - browsers[prefix + 'p'] = version ? version >= index : 0; - } - - return browsers; - }, - - //OS Detection - getOperatingSystems = function () { - var systems = {}, - value, key, keys, index, len, match, matched, version, activeCount; - - keys = _getKeys(me.osPrefixes); - len = keys.length; - for (index = 0, activeCount = 0; index < len; index++) { - key = keys[index]; - value = me.osPrefixes[key]; - match = ua.match(new RegExp('(' + value + ')([^\\s;]+)')); - matched = match ? match[1] : null; - - // This is here because some HTC android devices show an OSX Snow Leopard userAgent by default. - // And the Kindle Fire doesn't have any indicator of Android as the OS in its User Agent - if (matched && (matched === 'HTC_' || matched === 'Silk/')) { - version = 2.3; - } else { - version = match && match.length > 1 ? parseFloat(match[match.length - 1]) : 0; - } - - if (version) { - activeCount++; - } - systems[key] = version; - } - - keys = _getKeys(me.fallbackOSPrefixes); - - // If no OS could be found we resort to the fallbacks, otherwise we just - // falsify the fallbacks - len = keys.length; - for (index = 0; index < len; index++) { - key = keys[index]; - - // No OS was detected from osPrefixes - if (activeCount === 0) { - value = me.fallbackOSPrefixes[key]; - match = ua.toLowerCase().match(new RegExp(value)); - systems[key] = match ? true : 0; - } else { - systems[key] = 0; - } - } - - return systems; - }, - - // Device Detection - getDevices = function () { - var devices = {}, - value, key, keys, index, len, match; - - keys = _getKeys(me.devicePrefixes); - len = keys.length; - for (index = 0; index < len; index++) { - key = keys[index]; - value = me.devicePrefixes[key]; - match = ua.match(new RegExp(value)); - devices[key] = match ? true : 0; - } - - return devices; - }, - browsers = getBrowsers(), - systems = getOperatingSystems(), - devices = getDevices(), - platformParams = Boot.loadPlatformsParam(); - - // We apply platformParams from the query here first to allow for forced user valued - // to be used in calculation of generated tags - _merge(_tags, browsers, systems, devices, platformParams, true); - - _tags.phone = !!((_tags.iphone || _tags.ipod) || - (!_tags.silk && (_tags.android && (_tags.android < 3 || isMobile))) || - (_tags.blackberry && isMobile) || - (_tags.windowsphone)); - - _tags.tablet = !!(!_tags.phone && ( - _tags.ipad || - _tags.android || - _tags.silk || - _tags.rimtablet || - (_tags.ie10 && /; Touch/.test(ua)) - )); - - _tags.touch = - // if the browser has touch events we can be reasonably sure the device has - // a touch screen - isEventSupported('touchend') || - // browsers that use pointer event have maxTouchPoints > 0 if the - // device supports touch input - // http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints - navigator.maxTouchPoints || - // IE10 uses a vendor-prefixed maxTouchPoints property - navigator.msMaxTouchPoints; - - _tags.desktop = !_tags.phone && !_tags.tablet; - _tags.cordova = _tags.phonegap = !!(window.PhoneGap || window.Cordova || window.cordova); - _tags.webview = /(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)(?!.*FBAN)/i.test(ua); - _tags.androidstock = (_tags.android <= 4.3) && (_tags.safari || _tags.silk); - - // Re-apply any query params here to allow for user override of generated tags (desktop, touch, tablet, etc) - _merge(_tags, platformParams, true); - }, - - /** - * Extracts user supplied platform tags from the "platformTags" query parameter - * of the form: - * - * ?platformTags=name:state,name:state,... - * - * (each tag defaults to true when state is unspecified) - * - * Example: - * - * ?platformTags=isTablet,isPhone:false,isDesktop:0,iOS:1,Safari:true, ... - * - * @returns {Object} the platform tags supplied by the query string - */ - loadPlatformsParam: function () { - // Check if the ?platform parameter is set in the URL - var paramsString = window.location.search.substr(1), - paramsArray = paramsString.split("&"), - params = {}, i, - platforms = {}, - tmpArray, tmplen, platform, name, enabled; - - for (i = 0; i < paramsArray.length; i++) { - tmpArray = paramsArray[i].split("="); - params[tmpArray[0]] = tmpArray[1]; - } - - if (params.platformTags) { - tmpArray = params.platformTags.split(","); - for (tmplen = tmpArray.length, i = 0; i < tmplen; i++) { - platform = tmpArray[i].split(":"); - name = platform[0]; - enabled=true; - if (platform.length > 1) { - enabled = platform[1]; - if (enabled === 'false' || enabled === '0') { - enabled = false; - } - } - platforms[name] = enabled; - } - } - return platforms; - }, - - filterPlatform: function (platform, excludes) { - platform = _emptyArray.concat(platform || _emptyArray); - excludes = _emptyArray.concat(excludes || _emptyArray); - - var plen = platform.length, - elen = excludes.length, - include = (!plen && elen), // default true if only excludes specified - i, tag; - - for (i = 0; i < plen && !include; i++) { - tag = platform[i]; - include = !!_tags[tag]; - } - - for (i = 0; i < elen && include; i++) { - tag = excludes[i]; - include = !_tags[tag]; - } - - return include; - }, - - init: function () { - var scriptEls = doc.getElementsByTagName('script'), - script = scriptEls[0], - len = scriptEls.length, - re = /\/ext(\-[a-z\-]+)?\.js$/, - entry, src, state, baseUrl, key, n, origin; - - // No check for script definedness because there always should be at least one - Boot.hasReadyState = ("readyState" in script); - Boot.hasAsync = ("async" in script); - Boot.hasDefer = ("defer" in script); - Boot.hasOnLoad = ("onload" in script); - - // Feature detecting IE - Boot.isIE8 = Boot.hasReadyState && !Boot.hasAsync && Boot.hasDefer && !Boot.hasOnLoad; - Boot.isIE9 = Boot.hasReadyState && !Boot.hasAsync && Boot.hasDefer && Boot.hasOnLoad; - Boot.isIE10p = Boot.hasReadyState && Boot.hasAsync && Boot.hasDefer && Boot.hasOnLoad; - - Boot.isIE10 = (new Function('/*@cc_on return @_jscript_version @*/')()) === 10; - Boot.isIE10m = Boot.isIE10 || Boot.isIE9 || Boot.isIE8; - - // IE11 does not support conditional compilation so we detect it by exclusion - Boot.isIE11 = Boot.isIE10p && !Boot.isIE10; - - // Since we are loading after other scripts, and we needed to gather them - // anyway, we track them in _scripts so we don't have to ask for them all - // repeatedly. - for (n = 0; n < len; n++) { - src = (script = scriptEls[n]).src; - if (!src) { - continue; - } - state = script.readyState || null; - - // If we find a script file called "ext-*.js", then the base path is that file's base path. - if (!baseUrl && re.test(src)) { - baseUrl = src; - } - - if (!Boot.scripts[key = Boot.canonicalUrl(src)]) { - entry = new Entry({ - key: key, - url: src, - done: state === null || // non-IE - state === 'loaded' || state === 'complete', // IE only - el: script, - prop: 'src' - }); - } - } - - if (!baseUrl) { - script = scriptEls[scriptEls.length - 1]; - baseUrl = script.src; - } - - Boot.baseUrl = baseUrl.substring(0, baseUrl.lastIndexOf('/') + 1); - origin = window.location.origin || - window.location.protocol + - "//" + - window.location.hostname + - (window.location.port ? ':' + window.location.port: ''); - Boot.origin = origin; - - Boot.detectPlatformTags(); - Ext.filterPlatform = Boot.filterPlatform; - }, - - /** - * This method returns a canonical URL for the given URL. - * - * For example, the following all produce the same canonical URL (which is the - * last one): - * - * http://foo.com/bar/baz/zoo/derp/../../goo/Thing.js?_dc=12345 - * http://foo.com/bar/baz/zoo/derp/../../goo/Thing.js - * http://foo.com/bar/baz/zoo/derp/../jazz/../../goo/Thing.js - * http://foo.com/bar/baz/zoo/../goo/Thing.js - * http://foo.com/bar/baz/goo/Thing.js - * - * @private - */ - canonicalUrl: function (url) { - // *WARNING WARNING WARNING* - // This method yields the most correct result we can get but it is EXPENSIVE! - // In ALL browsers! When called multiple times in a sequence, as if when - // we resolve dependencies for entries, it will cause garbage collection events - // and overall painful slowness. This is why we try to avoid it as much as we can. - // - // @TODO - see if we need this fallback logic - // http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue - resolverEl.href = url; - - var ret = resolverEl.href, - dc = _config.disableCachingParam, - pos = dc ? ret.indexOf(dc + '=') : -1, - c, end; - - // If we have a _dc query parameter we need to remove it from the canonical - // URL. - if (pos > 0 && ((c = ret.charAt(pos - 1)) === '?' || c === '&')) { - end = ret.indexOf('&', pos); - end = (end < 0) ? '' : ret.substring(end); - if (end && c === '?') { - ++pos; // keep the '?' - end = end.substring(1); // remove the '&' - } - ret = ret.substring(0, pos - 1) + end; - } - - return ret; - }, - - /** - * Get the config value corresponding to the specified name. If no name is given, will return the config object - * @param {String} name The config property name - * @return {Object} - */ - getConfig: function (name) { - return name ? Boot.config[name] : Boot.config; - }, - - /** - * Set the configuration. - * @param {Object} config The config object to override the default values. - * @return {Ext.Boot} this - */ - setConfig: function (name, value) { - if (typeof name === 'string') { - Boot.config[name] = value; - } else { - for (var s in name) { - Boot.setConfig(s, name[s]); - } - } - return Boot; - }, - - getHead: function () { - return Boot.docHead || - (Boot.docHead = doc.head || - doc.getElementsByTagName('head')[0]); - }, - - create: function (url, key, cfg) { - var config = cfg || {}; - config.url = url; - config.key = key; - return Boot.scripts[key] = new Entry(config); - }, - - getEntry: function (url, cfg, canonicalPath) { - var key, entry; - - // Canonicalizing URLs via anchor element href yields the most correct result - // but is *extremely* resource heavy so we need to avoid it whenever possible - key = canonicalPath ? url : Boot.canonicalUrl(url); - entry = Boot.scripts[key]; - - if (!entry) { - entry = Boot.create(url, key, cfg); - - if (canonicalPath) { - entry.canonicalPath = true; - } - } - - return entry; - }, - - registerContent: function (url, type, content) { - var cfg = { - content: content, - loaded: true, - css: type === 'css' - }; - - return Boot.getEntry(url, cfg); - }, - - processRequest: function(request, sync) { - request.loadEntries(sync); - }, - - load: function (request) { - var request = new Request(request); - - if (request.sync || Boot.syncMode) { - return Boot.loadSync(request); - } - - // If there is a request in progress, we must - // queue this new request to be fired when the current request completes. - if (Boot.currentRequest) { - // trigger assignment of entries now to ensure that overlapping - // entries with currently running requests will synchronize state - // with this pending one as they complete - request.getEntries(); - Boot.suspendedQueue.push(request); - } else { - Boot.currentRequest = request; - Boot.processRequest(request, false); - } - return Boot; - }, - - loadSync: function (request) { - var request = new Request(request); - - Boot.syncMode++; - Boot.processRequest(request, true); - Boot.syncMode--; - return Boot; - }, - - loadBasePrefix: function(request) { - request = new Request(request); - request.prependBaseUrl = true; - return Boot.load(request); - }, - - loadSyncBasePrefix: function(request) { - request = new Request(request); - request.prependBaseUrl = true; - return Boot.loadSync(request); - }, - - requestComplete: function(request) { - var next; - - if (Boot.currentRequest === request) { - Boot.currentRequest = null; - while(Boot.suspendedQueue.length > 0) { - next = Boot.suspendedQueue.shift(); - if(!next.done) { - Boot.load(next); - break; - } - } - } - if (!Boot.currentRequest && Boot.suspendedQueue.length == 0) { - Boot.fireListeners(); - } - }, - - isLoading: function () { - return !Boot.currentRequest && Boot.suspendedQueue.length == 0; - }, - - fireListeners: function () { - var listener; - while (Boot.isLoading() && (listener = Boot.listeners.shift())) { - listener(); - } - }, - - onBootReady: function (listener) { - if (!Boot.isLoading()) { - listener(); - } else { - Boot.listeners.push(listener); - } - }, - - /** - * this is a helper function used by Ext.Loader to flush out - * 'uses' arrays for classes in some Ext versions - */ - getPathsFromIndexes: function (indexMap, loadOrder) { - // In older versions indexMap was an object instead of a sparse array - if (!('length' in indexMap)) { - var indexArray = [], - index; - - for (index in indexMap) { - if (!isNaN(+index)) { - indexArray[+index] = indexMap[index]; - } - } - - indexMap = indexArray; - } - - return Request.prototype.getPathsFromIndexes(indexMap, loadOrder); - }, - - createLoadOrderMap: function(loadOrder) { - return Request.prototype.createLoadOrderMap(loadOrder); - }, - - fetch: function(url, complete, scope, async) { - async = (async === undefined) ? !!complete : async; - - var xhr = new XMLHttpRequest(), - result, status, content, exception = false, - readyStateChange = function () { - if (xhr && xhr.readyState == 4) { - status = (xhr.status === 1223) ? 204 : - (xhr.status === 0 && ((self.location || {}).protocol === 'file:' || - (self.location || {}).protocol === 'ionp:')) ? 200 : xhr.status; - content = xhr.responseText; - result = { - content: content, - status: status, - exception: exception - }; - if (complete) { - complete.call(scope, result); - } - xhr.onreadystatechange = emptyFn; - xhr = null; - } - }; - - if (async) { - xhr.onreadystatechange = readyStateChange; - } - - try { - xhr.open('GET', url, async); - xhr.send(null); - } catch (err) { - exception = err; - readyStateChange(); - return result; - } - - if (!async) { - readyStateChange(); - } - - return result; - }, - - notifyAll: function(entry) { - entry.notifyRequests(); - } - }; - - function Request(cfg) { - //The request class encapsulates a series of Entry objects - //and provides notification around the completion of all Entries - //in this request. - - if(cfg.$isRequest) { - return cfg; - } - - var cfg = cfg.url ? cfg : {url: cfg}, - url = cfg.url, - urls = url.charAt ? [ url ] : url, - charset = cfg.charset || Boot.config.charset; - - _apply(this, cfg); - - delete this.url; - this.urls = urls; - this.charset = charset; - }; - - Request.prototype = { - $isRequest: true, - - createLoadOrderMap: function (loadOrder) { - var len = loadOrder.length, - loadOrderMap = {}, - i, element; - - for (i = 0; i < len; i++) { - element = loadOrder[i]; - loadOrderMap[element.path] = element; - } - - return loadOrderMap; - }, - - getLoadIndexes: function (item, indexMap, loadOrder, includeUses, skipLoaded) { - var resolved = [], - queue = [item], - itemIndex = item.idx, - queue, entry, dependencies, depIndex, i, len; - - if (indexMap[itemIndex]) { - // prevent cycles - return resolved; - } - - // Both indexMap and resolved are sparse arrays keyed by indexes. - // This gives us a naturally sorted sequence of indexes later on - // when we need to convert them to paths. - // indexMap is the map of all indexes we have visited at least once - // per the current expandUrls() invocation, and resolved is the map - // of all dependencies for the current item that are not included - // in indexMap. - indexMap[itemIndex] = resolved[itemIndex] = true; - - while (item = queue.shift()) { - // Canonicalizing URLs is expensive, we try to avoid it - if (item.canonicalPath) { - entry = Boot.getEntry(item.path, null, true); - } - else { - entry = Boot.getEntry(this.prepareUrl(item.path)); - } - - if (!(skipLoaded && entry.done)) { - if (includeUses && item.uses && item.uses.length) { - dependencies = item.requires.concat(item.uses); - } - else { - dependencies = item.requires; - } - - for (i = 0, len = dependencies.length; i < len; i++) { - depIndex = dependencies[i]; - - if (!indexMap[depIndex]) { - indexMap[depIndex] = resolved[depIndex] = true; - queue.push(loadOrder[depIndex]); - } - } - } - } - - return resolved; - }, - - getPathsFromIndexes: function (indexes, loadOrder) { - var paths = [], - index, len; - - // indexes is a sparse array with values being true for defined indexes - for (index = 0, len = indexes.length; index < len; index++) { - if (indexes[index]) { - paths.push(loadOrder[index].path); - } - } - - return paths; - }, - - expandUrl: function (url, loadOrder, loadOrderMap, indexMap, includeUses, skipLoaded) { - var item, resolved; - - if (loadOrder) { - item = loadOrderMap[url]; - - if (item) { - resolved = this.getLoadIndexes(item, indexMap, loadOrder, includeUses, skipLoaded); - - if (resolved.length) { - return this.getPathsFromIndexes(resolved, loadOrder); - } - } - } - - return [url]; - }, - - expandUrls: function (urls, includeUses) { - var me = this, - loadOrder = me.loadOrder, - expanded = [], - expandMap = {}, - indexMap = [], - loadOrderMap, tmpExpanded, i, len, t, tlen, tUrl; - - if (typeof urls === "string") { - urls = [urls]; - } - - if (loadOrder) { - loadOrderMap = me.loadOrderMap; - - if (!loadOrderMap) { - loadOrderMap = me.loadOrderMap = me.createLoadOrderMap(loadOrder); - } - } - - for (i = 0, len = urls.length; i < len; i++) { - // We don't want to skip loaded entries (last argument === false). - // There are some overrides that get loaded before their respective classes, - // and when the class dependencies are processed we don't want to skip over - // the overrides' dependencies just because they were loaded first. - tmpExpanded = this.expandUrl(urls[i], loadOrder, loadOrderMap, indexMap, includeUses, false); - - for (t = 0, tlen = tmpExpanded.length; t < tlen; t++) { - tUrl = tmpExpanded[t]; - - if (!expandMap[tUrl]) { - expandMap[tUrl] = true; - expanded.push(tUrl); - } - } - } - - if (expanded.length === 0) { - expanded = urls; - } - - return expanded; - }, - - expandLoadOrder: function () { - var me = this, - urls = me.urls, - expanded; - - if (!me.expanded) { - expanded = this.expandUrls(urls, true); - me.expanded = true; - } else { - expanded = urls; - } - - me.urls = expanded; - - // if we added some urls to the request to honor the indicated - // load order, the request needs to be sequential - if (urls.length != expanded.length) { - me.sequential = true; - } - - return me; - }, - - getUrls: function () { - this.expandLoadOrder(); - return this.urls; - }, - - prepareUrl: function(url) { - if(this.prependBaseUrl) { - return Boot.baseUrl + url; - } - return url; - }, - - getEntries: function () { - var me = this, - entries = me.entries, - loadOrderMap, item, i, entry, urls, url; - - if (!entries) { - entries = []; - urls = me.getUrls(); - - // If we have loadOrder array then the map will be expanded by now - if (me.loadOrder) { - loadOrderMap = me.loadOrderMap; - } - - for (i = 0; i < urls.length; i++) { - url = me.prepareUrl(urls[i]); - - if (loadOrderMap) { - item = loadOrderMap[url]; - } - - entry = Boot.getEntry(url, { - buster: me.buster, - charset: me.charset - }, item && item.canonicalPath); - - entry.requests.push(me); - entries.push(entry); - } - - me.entries = entries; - } - - return entries; - }, - - loadEntries: function(sync) { - var me = this, - entries = me.getEntries(), - len = entries.length, - start = me.loadStart || 0, - continueLoad, entries, entry, i; - - if(sync !== undefined) { - me.sync = sync; - } - - me.loaded = me.loaded || 0; - me.loading = me.loading || len; - - for(i = start; i < len; i++) { - entry = entries[i]; - if(!entry.loaded) { - continueLoad = entries[i].load(me.sync); - } else { - continueLoad = true; - } - if(!continueLoad) { - me.loadStart = i; - entry.onDone(function(){ - me.loadEntries(sync); - }); - break; - } - } - me.processLoadedEntries(); - }, - - processLoadedEntries: function () { - var me = this, - entries = me.getEntries(), - len = entries.length, - start = me.startIndex || 0, - i, entry; - - if (!me.done) { - for (i = start; i < len; i++) { - entry = entries[i]; - - if (!entry.loaded) { - me.startIndex = i; - return; - } - - if (!entry.evaluated) { - entry.evaluate(); - } - - if (entry.error) { - me.error = true; - } - } - me.notify(); - } - }, - - notify: function () { - var me = this; - if (!me.done) { - var error = me.error, - fn = me[error ? 'failure' : 'success'], - delay = ('delay' in me) - ? me.delay - : (error ? 1 : Boot.config.chainDelay), - scope = me.scope || me; - me.done = true; - if (fn) { - if (delay === 0 || delay > 0) { - // Free the stack (and defer the next script) - setTimeout(function () { - fn.call(scope, me); - }, delay); - } else { - fn.call(scope, me); - } - } - me.fireListeners(); - Boot.requestComplete(me); - } - }, - - onDone: function(listener) { - var me = this, - listeners = me.listeners || (me.listeners = []); - if(me.done) { - listener(me); - } else { - listeners.push(listener); - } - }, - - fireListeners: function() { - var listeners = this.listeners, - listener; - if(listeners) { - while((listener = listeners.shift())) { - listener(this); - } - } - } - }; - - function Entry(cfg) { - //The Entry class is a token to manage the load and evaluation - //state of a particular url. It is used to notify all Requests - //interested in this url that the content is available. - - if(cfg.$isEntry) { - return cfg; - } - - - var charset = cfg.charset || Boot.config.charset, - manifest = Ext.manifest, - loader = manifest && manifest.loader, - cache = (cfg.cache !== undefined) ? cfg.cache : (loader && loader.cache), - buster, busterParam; - - if (Boot.config.disableCaching) { - if (cache === undefined) { - cache = !Boot.config.disableCaching; - } - - if (cache === false) { - buster = +new Date(); - } else if (cache !== true) { - buster = cache; - } - - if (buster) { - busterParam = (loader && loader.cacheParam) || Boot.config.disableCachingParam; - buster = busterParam + "=" + buster; - } - } - - _apply(this, cfg); - - this.charset = charset; - this.buster = buster; - this.requests = []; - }; - - Entry.prototype = { - $isEntry: true, - done: false, - evaluated: false, - loaded: false, - - isCrossDomain: function() { - var me = this; - if(me.crossDomain === undefined) { - me.crossDomain = (me.getLoadUrl().indexOf(Boot.origin) !== 0); - } - return me.crossDomain; - }, - - isCss: function () { - var me = this; - if (me.css === undefined) { - if (me.url) { - var assetConfig = Boot.assetConfig[me.url]; - me.css = assetConfig ? assetConfig.type === "css" : cssRe.test(me.url); - } else { - me.css = false; - } - } - return this.css; - }, - - getElement: function (tag) { - var me = this, - el = me.el; - if (!el) { - if (me.isCss()) { - tag = tag || "link"; - el = doc.createElement(tag); - if(tag == "link") { - el.rel = 'stylesheet'; - me.prop = 'href'; - } else { - me.prop="textContent"; - } - el.type = "text/css"; - } else { - tag = tag || "script"; - el = doc.createElement(tag); - el.type = 'text/javascript'; - me.prop = 'src'; - - if (me.charset) { - el.charset = me.charset; - } - - if (Boot.hasAsync) { - el.async = false; - } - } - me.el = el; - } - return el; - }, - - getLoadUrl: function () { - var me = this, - url; - - url = me.canonicalPath ? me.url : Boot.canonicalUrl(me.url); - - if (!me.loadUrl) { - me.loadUrl = !!me.buster - ? (url + (url.indexOf('?') === -1 ? '?' : '&') + me.buster) - : url; - } - return me.loadUrl; - }, - - fetch: function (req) { - var url = this.getLoadUrl(), - async = !!req.async, - complete = req.complete; - - Boot.fetch(url, complete, this, async); - }, - - onContentLoaded: function (response) { - var me = this, - status = response.status, - content = response.content, - exception = response.exception, - url = this.getLoadUrl(); - me.loaded = true; - if ((exception || status === 0) && !_environment.phantom) { - me.error = - true; - me.evaluated = true; - } - else if ((status >= 200 && status < 300) || status === 304 - || _environment.phantom - || (status === 0 && content.length > 0) - ) { - me.content = content; - } - else { - me.error = - true; - me.evaluated = true; - } - }, - - createLoadElement: function(callback) { - var me = this, - el = me.getElement(); - - me.preserve = true; - - el.onerror = function() { - me.error = true; - - if (callback) { - callback(); - callback = null; - } - }; - - if (Boot.isIE10m) { - el.onreadystatechange = function() { - if (this.readyState === 'loaded' || this.readyState === 'complete') { - if (callback) { - callback(); - callback = this.onreadystatechange = this.onerror = null; - } - } - }; - } - else { - el.onload = function() { - callback(); - callback = this.onload = this.onerror = null; - }; - } - - // IE starts loading here - el[me.prop] = me.getLoadUrl(); - }, - - onLoadElementReady: function() { - Boot.getHead().appendChild(this.getElement()); - this.evaluated = true; - }, - - inject: function (content, asset) { - var me = this, - head = Boot.getHead(), - url = me.url, - key = me.key, - base, el, ieMode, basePath; - - if (me.isCss()) { - me.preserve = true; - basePath = key.substring(0, key.lastIndexOf("/") + 1); - base = doc.createElement('base'); - base.href = basePath; - if(head.firstChild) { - head.insertBefore(base, head.firstChild); - } else { - head.appendChild(base); - } - // reset the href attribute to cuase IE to pick up the change - base.href = base.href; - - if (url) { - content += "\n/*# sourceURL=" + key + " */"; - } - - // create element after setting base - el = me.getElement("style"); - - ieMode = ('styleSheet' in el); - - head.appendChild(base); - if(ieMode) { - head.appendChild(el); - el.styleSheet.cssText = content; - } else { - el.textContent = content; - head.appendChild(el); - } - head.removeChild(base); - - } else { - // Debugger friendly, file names are still shown even though they're - // eval'ed code. Breakpoints work on both Firebug and Chrome's Web - // Inspector. - if (url) { - content += "\n//# sourceURL=" + key; - } - Ext.globalEval(content); - } - return me; - }, - - loadCrossDomain: function() { - var me = this, - complete = function(){ - me.el.onerror = me.el.onload = emptyFn; - me.el = null; - me.loaded = me.evaluated = me.done = true; - me.notifyRequests(); - }; - me.createLoadElement(function(){ - complete(); - }); - me.evaluateLoadElement(); - // at this point, we need sequential evaluation, - // which means we can't advance the load until - // this entry has fully completed - return false; - }, - - loadElement: function() { - var me = this, - complete = function(){ - me.el.onerror = me.el.onload = emptyFn; - me.el = null; - me.loaded = me.evaluated = me.done = true; - me.notifyRequests(); - }; - me.createLoadElement(function(){ - complete(); - }); - me.evaluateLoadElement(); - return true; - }, - - loadSync: function() { - var me = this; - me.fetch({ - async: false, - complete: function (response) { - me.onContentLoaded(response); - } - }); - me.evaluate(); - me.notifyRequests(); - }, - - load: function (sync) { - var me = this; - if (!me.loaded) { - if(me.loading) { - // if we're calling back through load and we're loading but haven't - // yet loaded, then we should be in a sequential, cross domain - // load scenario which means we can't continue the load on the - // request until this entry has fully evaluated, which will mean - // loaded = evaluated = done = true in one step. For css files, this - // will happen immediately upon element creation / insertion, - // but