diff --git a/.sencha/app/Boot.js b/.sencha/app/Boot.js new file mode 100644 index 0000000..3d53b01 --- /dev/null +++ b/.sencha/app/Boot.js @@ -0,0 +1,1831 @@ +// @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 = {}), + + // + // All calls to _debug are commented out to speed up old browsers a bit; + // yes that makes a difference because the cost of concatenating strings + // and passing them into _debug() adds up pretty quickly. + _debug = function (message) { + //console.log(message); + }, + // + _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 + */ + // + debug: _debug, + // + + /** + * 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)]) { + // +// _debug("creating entry " + key + " in Boot.init"); + // + 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) { + // +// _debug("Boot.load called"); + // + 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) { + // +// _debug("current active request, suspending this request"); + // + // 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) { + // +// _debug("Boot.loadSync called"); + // + 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) { + // +// _debug("resuming suspended request"); + // + 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 { + // +// _debug("fetching " + url + " " + (async ? "async" : "sync")); + // + 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) { + // +// _debug("firing request 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; + } + + // +// _debug("creating entry for " + cfg.url); + // + + 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) { + // +// _debug("checking " + me.getLoadUrl() + " for prefix " + Boot.origin); + // + 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) { + // +// _debug("creating element for " + me.url); + // + 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 = + // + ("Failed loading synchronously via XHR: '" + url + + "'. It's likely that the file is either being loaded from a " + + "different domain or from the local file system where cross " + + "origin requests are not allowed for security reasons. Try " + + "asynchronous loading instead.") || + // + 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 = + // + ("Failed loading synchronously via XHR: '" + url + + "'. Please verify that the file exists. XHR status code: " + + status) || + // + 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) { + // +// _debug("injecting content for " + this.url); + // + 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 + + + cordova ${cordova.cli.options} platform list + + + + + + + + + + cordova ${cordova.cli.options} platform add ${cordova.platforms.missing} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/cordova.defaults.properties b/.sencha/app/cordova.defaults.properties new file mode 100644 index 0000000..7c4815e --- /dev/null +++ b/.sencha/app/cordova.defaults.properties @@ -0,0 +1,6 @@ +# +# Copyright (c) 2012-2014. Sencha Inc. +# + +# Legacy support here for old build workflow. +cordova.platforms=${app.cordova.config.platforms} \ No newline at end of file diff --git a/.sencha/app/defaults.properties b/.sencha/app/defaults.properties new file mode 100644 index 0000000..d54f6da --- /dev/null +++ b/.sencha/app/defaults.properties @@ -0,0 +1,707 @@ +# ============================================================================= +# This file defines properties used by build-impl.xml and the associated +# *-impl.xml files (sass-impl.xml, js-impl.xml, etc.), which are the core of +# the applications build process. +# +# This file represents the lowest priority file for defining these properties +# as well as the place to look for documentation and learning what properties +# exist. +# +# The full set of these files is as follows (in priority order): +# +# - One of these (based on build.environment): +# - production.properties +# - testing.properties +# - native.properties +# - package.properties +# +# - build.properties +# +# - One of these (based on app.framework): +# - ext.properties +# - touch.properties +# +# - One of these (based on build.environment): +# - production.defaults.properties +# - testing.defaults.properties +# - native.defaults.properties +# - package.defaults.properties +# +# - defaults.properties +# +# Properties are controlled by the first file in the above list to define the +# value. Values from all levels, however, can reference each other via the +# property expansion. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +# ***************************************************************************** +# Global Build Properties +# these are cross-concern properties used by many build phases +# ***************************************************************************** + +# the default build environment type (production, testing, native, package) +# NOTE: this is only a default and will typically be set before this file is +# loaded, typically by the 'sencha app build" command. +# See "sencha help app build" for details. +# +# The corresponding properties files: +# (production.properties, testing.properties, etc.) provide examples of +# overriding sets of properties depending on the selected environment +# NOTE: this replaces the deprecated args.environment +app.environment=production +build.environment=${app.environment} + +# the directory to place built application files +build.dir=${workspace.build.dir}/${build.environment}/${app.name} + +app.compressor.type=${app.compressor} + +app.output=${build.dir} +app.output.base=${app.output} + +app.output.page=index.html +app.output.page.path=${app.output.page} +app.output.page.enable=true + +app.output.resources=resources +app.output.resources.path=${app.output.resources} +app.output.resources.enable=true +app.output.resources.compress=${app.output.js.compress} + +app.output.css.dir=${app.output.resources.path} +app.output.css=${app.output.css.dir}/${app.name}-all.css +app.output.css.path=${app.output.css} +app.output.css.enable=true +app.output.css.compress=true +app.output.css.preprocess=true +app.output.css.split=4095 + +app.output.js=app.js +app.output.js.path=${app.output.js} +app.output.js.enable=true +app.output.js.compress=false +app.output.js.optimize=false +app.output.js.optimize.cssPrefix=${app.output.js.optimize} +app.output.js.optimize.xtemplate=false +app.output.js.optimize.propNames=${app.output.js.optimize} +app.output.js.optimize.defines=${app.output.js.optimize} +app.output.js.optimize.callParent=${app.output.js.optimize} +app.output.js.optimize.requires=${app.output.js.optimize} + +app.output.framework=framework.js +app.output.framework.path=${app.output.framework} +app.output.framework.enable=false + +app.output.microloader=microloader.js +app.output.microloader.path=${app.output.microloader} +app.output.microloader.enable=true +app.output.microloader.embed=true + +app.output.manifest=app.json +app.output.manifest.path=${app.output.manifest} +app.output.manifest.enable=true +app.output.manifest.embed=false + +app.output.slicer=${app.output.resources.path} +app.output.slicer.path=${app.output.slicer} +app.output.slicer.enable=true + +app.archivePath=archive +app.output.archive=${app.archivePath} +app.output.archive.path=${app.output.archive} + +app.cache.enable=${app.output.deltas.enable} + +app.output.cache=cache.appcache +app.output.cache.path=${app.output.cache} +app.output.cache.enable=true +app.output.appCache.enable=${app.output.cache.enable} +app.output.appCache.path=${app.output.cache.path} + +build.out.base.path=${app.output.base} +build.out.page.path=${build.out.base.path}/${app.output.page.path} +build.out.resources.path=${build.out.base.path}/${app.output.resources.path} +build.out.css.path=${build.out.base.path}/${app.output.css.path} +build.out.js.path=${build.out.base.path}/${app.output.js.path} +build.out.framework.path=${build.out.base.path}/${app.output.framework.path} +build.out.archive.path=${build.out.base.path}/${app.output.archive.path} +build.out.manifest.path=${build.out.base.path}/${app.output.manifest.path} +build.out.microloader.path=${build.out.base.path}/${app.output.microloader.path} +build.out.appCache.path=${build.out.base.path}/${app.output.appCache.path} + +# Moved to init-impl.xml to handle truthy special values +#build.out.deltas.path=${build.out.base.path}/${app.output.deltas.path} +build.out.slicer.path=${build.out.base.path}/${app.output.slicer.path} + +# place holder properties to allow the newer .path property to control the existing .dir property +build.out.resources.dir=${build.out.resources.path} +build.out.css.dir=${build.out.base.path}/${app.output.css.dir} + +build.out.metadata.path=${build.out.page.path} + +# a temporary output directory used for staging intermediate build artifacts +build.temp.dir=${workspace.build.dir}/temp/${build.environment}/${app.name} + +# the directory under the output folder for placing resources +build.resources.dir=${build.out.resources.path} + +app.manifest.bootstrap=bootstrap.json + +app.bootstrap=${app.dir} +app.bootstrap.base=${app.bootstrap} +app.bootstrap.page=${app.indexHtmlPath} +app.bootstrap.page.path=${app.bootstrap.page} +app.bootstrap.css=${app.bootstrap.css.name} +app.bootstrap.css.path=${app.bootstrap.css} +app.bootstrap.microloader=${app.bootstrap.js.name} +app.bootstrap.microloader.path=${app.bootstrap.microloader} +app.bootstrap.manifest=${app.manifest.bootstrap} +app.bootstrap.manifest.path=${app.bootstrap.manifest} + +build.bootstrap.base.path=${app.bootstrap.base} +build.bootstrap.page.path=${build.bootstrap.base.path}/${app.bootstrap.page.path} +build.bootstrap.css.path=${build.bootstrap.base.path}/${app.bootstrap.css.path} +build.bootstrap.microloader.path=${build.bootstrap.base.path}/${app.bootstrap.microloader.path} +build.bootstrap.manifest.path=${build.bootstrap.base.path}/${app.bootstrap.manifest.path} + +build.bootstrap.metadata.path=${build.bootstrap.page.path} + +# ***************************************************************************** +# JS +# these properties control various aspects of output js code construction +# ***************************************************************************** + +# the output js file that contains all needed js code + +# deprecated, now controlled by app.output.js / app.output.js.path in app.json +build.classes.file=${build.out.js.path} + +# the output js file for framework code, if the framework +# classes are not included in the default all-classes.js file +# deprecated, now controlled by app.output.framework / app.output.framework.path in app.json +build.framework.file=${build.out.framework.path} + +# Don't use these - they are deprecated +build.options.debug.enable=debug:true +build.options.debug.disable=debug:false +build.options.logger.enable=logger:yes +build.options.logger.disable=logger:no + +# This property enables/disables blocks in js output, see build.options +build.options.logger=no + +# This property enables/disables blocks in js output, see build.options +build.options.debug=false + +# This property can be used to pass custom build options in addition to any of the other +# build.options flags. When overlapping, these options take priority, see build.options +build.options.custom= + +# This value is specified by the framework +build.options.default= + +# This property contains the framework ("product") used for filtering of JavaScript using +# the preprocessor. This is set by either ext.properties or touch.properties. +# +#build.options.product=touch + +# This property contains the desired API level used for preprocessor filtering of JavaScript. +# This is set by either ext.properties or touch.properties. +# +#build.options.minVersion=2.1 + +# This property holds the set of js preprocessor options in the form: +# +# name1:value1,name2:value2,... +# +# (used by -init-compiler in init-impl.xml) +# +# This property is not likely to be set directly. Rather, you should set one of the +# contributing properties that are combined to form this one: +# +# build.options.debug +# build.options.logger +# build.options.custom +# +# The other properties that contribute to this are typically not needing to be set: +# +# build.options.product +# build.options.minVersion +# +build.options=logger:${build.options.logger},debug:${build.options.debug},product:${build.options.product},minVersion:${build.options.minVersion},${build.options.default},${build.options.custom} + +# This property can be modified to change general build options +# such as excluding files from the set. The format expects newlines +# for each argument, for example: +# +# build.operations=\ +# exclude\n \ +# -namespace=Ext\n +# +# NOTE: modifications to build.operations are intended to be +# placed in an override of the "-after-init" target, where it +# can be calculated based on other +# ant properties +# +# build.operations= + +# enables / disables the full class optimizer during js builds +# (used by the -compile-* targets in js-impl.xml) +build.optimize.defines=${app.output.js.optimize.defines} +build.optimize.callparent=${app.output.js.optimize.callParent} +build.optimize.cssPrefix=${app.output.js.optimize.cssPrefix} +build.optimize.xtemplate=${app.output.js.optimize.xtemplate} +build.optimize.propNames=${app.output.js.optimize.propNames} +build.optimize.include.metadata=${app.output.js.optimize.requires} +build.optimize.enable=\ + optimize\n \ + -property-name=${build.optimize.propNames}\n \ + -css-prefix=${build.optimize.cssPrefix}\n \ + -xtemplate=${build.optimize.xtemplate}\n \ + -define-rewrite=${build.optimize.defines}\n \ + -call-parent=${build.optimize.callparent}\n \ + -include-metadata=${build.optimize.include.metadata} + +build.optimize.disable= +build.optimize=${build.optimize.disable} + +# enables / disables removing text references from +# package js build files +build.remove.references=true + +# enables / disables removing "requires" and "uses" elements +# from class definitions +build.remove.requirement.nodes=true + +# enables / disables de-quoting certain string references to classes +# like mixin references +build.optimize.string.references=true + +# enables / disables yui compression +build.compression.yui=${app.output.js.compress} + +# enables / disables closure compression +build.compression.closure=0 + +# enables / disables uglify compression +build.compression.ugilfy=0 + +build.compile.temp.dir=${build.temp.dir}/sencha-compiler + +# controles whether to keep the temp compile dir after the build +build.compile.temp.dir.keep=true + +# ------------------------------------------ +# DOC ONLY - Do Not Set +# this variable will be set to the appropriate compressor +# option, and is calculated in init-impl.xml, but may be overridded in +# app.properties, .properties, or via command line +# +# build.compression= +# ------------------------------------------ + +# ***************************************************************************** +# Page +# these variables control aspects of building the output markup page +# ***************************************************************************** + +# controls whether the microloader content will be embedded in the output +# markup, or left as a separate resource +build.enable.embedded.microloader=${app.output.microloader.embed} + +# whether to include the page's manifest.json code with the +# microloader content. Production.properties files should set this to +# false to have manifest.json exist as a server resource. +build.enable.embedded.manifest=${app.output.manifest.embed} + +# enables / disables compression of resources referenced in app.json / package.json +# js and css entries +enable.resource.compression=${app.output.resources.compress} + +# defaults to index.html, but may be overridden in app.json +app.indexHtmlPath=index.html + +# the input page file for the application +app.page.name=${app.indexHtmlPath} +app.page.file=${app.dir}/${app.page.name} + +# the output page file +# deprecated, now controlled by app.output.page / app.output.page.path in app.json +build.page.name=${app.page.name} +build.page.dir=${build.out.base.path} +build.page.file=${build.out.page.path} + +# the directory where the microloader files may be found +app.microloader.dir=${app.config.dir}/microloader + +# the file names of the individual microloaders +app.microloader.development=development.js +app.microloader.testing=testing.js +app.microloader.production=production.js + +# the target microloader to use for builds +app.microloader.name=${app.microloader.development} +app.microloader=${app.microloader.dir}/${app.microloader.name} +app.microloader.path=${app.microloader} + +# specifies how to embed the microloader code into the output markup +# {0} is replaced with the content of the microloader file specified +# by app.microloader.path +build.microloader.code.tpl={0} + +# the template to use when generating a stand-alone json manifest file +build.microloader.json.tpl.standalone={0} + +# the template to use when embedding the manifest json directly next to the +# microloader in the output microloader content +build.microloader.json.tpl.embedded=Ext.blink({0}); + +# the template to use in the output microloader content when supplying +# the manifest json as a separate server-side resource ('production' builds) +build.microloader.json.tpl.external=Ext.blink('{'id:''${app.id}'''}'); + +# the template string to use when embedding the microloader content +# into the output markup +build.embedded.microloader.tpl= + +# the compressor to use when embedding the microloader into a page +# can be -closure or -yui, or leave empty to disable compression +build.embedded.microloader.compressor= + +# the path to the microloader content file, if external to the outpout markup +build.microloader.path=${build.out.microloader.path} + +# the inner markup to embed into the output markup when not including +# the microloader content directly into the output markup +build.embedded.microloader.src=${build.microloader.name} +build.external.microloader.markup= + +# a flag indicating which mode the microloader should run in (production, testing, etc.) +# currently unused : is a placeholder for future microloader interactions +build.microloader.mode=${build.environment} + +# the tag name to use when generating the compiler save set for +# the page's js code +build.tag.name=full-page + +# the name of the archive folder containing source versions for +# delta patch generation +# deprecated, now controlled by app.output.archive / app.output.archive.path in app.json +build.archive.name=archive + +# the output cache manifest file +build.manifest.name=${app.output.appCache.path} +build.manifest.path=${build.out.appCache.path} + +# the name of the manifest json file +build.json.name=${app.manifest.name} + +# the full path to the manifest json file +build.out.json.path=${build.out.manifest.path} + +# Defines the file that will contain Ext.setVersion calls for each used package. +build.out.package.versions=${build.compile.temp.dir}/cmd-packages.js + +# a temp directory for managing extracted resources during the page build +build.app.temp.dir=${build.compile.temp.dir}/app + +# controls the format of checksum headers injected into microloaded content +# either comment style, or code style for js and css files +delta.comment.checksums=false + +# ***************************************************************************** +# Refresh +# these properties are used for generating bootstrap js and css +# files to support dev-time interaction with the app +# ***************************************************************************** + +# the base path to use for generating / calculating bootstrap info +# this property is not longer defaulted here, but calculated in refresh-impl.xml +# based on new app.bootstrap properties +# app.bootstrap.base.path=${app.dir} + +# these control the name of the bootstrap js file +# note: there will be corresponding entries in either the index page +# or app.json that reference these names +# deprecated, use app.bootstrap.microloader +app.bootstrap.js.name=bootstrap.js +app.bootstrap.js=${build.bootstrap.microloader.path} + +# these control the name of the bootstrap css file (for ext 4.2+ apps) +# note: there will be corresponding entries in either the index page +# or app.json that reference these names +app.bootstrap.css.name=bootstrap.css + +# the microloader to use for bootstrapping operations +app.microloader.bootstrap=${app.microloader.dir}/${app.microloader.development} + +# the name of the bootstrap microloader manifest +build.json.bootstrap.name=${app.manifest.bootstrap} + +# the full path to the bootstrap microloader manifest +build.json.bootstrap.path=${build.bootstrap.manifest.path} + +# enables inclusion of override files in the generated bootstrap +bootstrap.include.overrides=true + +# enables inclusion of the Boot.js code in the generated bootstrap +bootstrap.include.boot=false + +# controls the template used to generate load calls for override files +bootstrap.override.tpl=Ext.Loader.loadScriptFile(''{0}'', Ext.emptyFn); + +build.boot.name=Boot.js +build.boot.file=${app.config.dir}/${build.boot.name} +build.slicer.microloader.name=Microloader.js +build.slicer.microloader.file=${app.config.dir}/${build.slicer.microloader.name} + +# the type of the override template ('tpl' or 'jsonp') +bootstrap.override.tpltype=tpl + +# ***************************************************************************** +# Sass / Css +# properties for controling features of sass generation and compilation +# ***************************************************************************** + +# controls the ruby command that is used to execute compasss +# a full path to ruby may be specified rather than allowing the system +# shell to resolve the command +build.ruby.path=ruby + +# -------------------- +# these control properties select the mode used to build the app's styling +# see sass-impl.xml for how then are used + +# enables theme builds for apps using ext 41 style themes +enable.ext41.themes=false + +# enables theme builds for apps using ext 42 style themes +enable.ext42.themes=false + +# enables theme builds for apps using touch style themes +enable.touch.themes=false +# -------------------- + +# selector count threshold to use when +# splitting a single css file into multiple +# css files (IE selector limit workaround) +# +# NOTE: applies only to ext js 4.2+ style theme management, currently +# see the above theme control variables for details +build.css.selector.limit=${app.output.css.split} + +# enables / disable css preprocessor (enable.ext42.themes only) +build.css.preprocess=${app.output.css.preprocess} + +# sets the css preprocessor options, in the form: +# name1:value1,name2:value2,... +build.css.preprocessor.opts= + +# enables / disable css compressor (enable.ext42.themes only) +build.css.compress=${app.output.css.compress} + +# controls the directory used to generate the output app scss file +# for apps that use theme packages +build.sass.dir=${build.temp.dir}/sass + +# Specify the name for the individual resource dirs in the app +# (enable.touch.themes only) +app.sass.name=sass + +# Specify the sass path in the app +# (enable.touch.themes only) +app.sass.dir=${app.dir}/resources/${app.sass.name} + +# name prefix to use for output css / sass files +app.out.base=${app.name}-all +app.out.base.debug=${app.out.base} + +# the output sass file to generate (used with enable.ext42.themes) +app.out.scss=${build.sass.dir}/${app.out.base.debug}.scss +# the output ruby compass config file to generate (used with enable.ext42.themes) +app.out.ruby=${build.sass.dir}/config.rb + +# output css file prefix +app.out.css.prefix=${app.out.base.debug} + +# output css file name +app.out.css.name=${app.out.css.prefix}.css + +# output css file path (relative to build directory root +app.out.css.rel=${app.output.resources.path}/${app.out.css.name} + +# output css file path (full path) +app.out.css=${build.out.css.path} + +# separate file name to use for generating a compressed copy +# of the output css file (this default will compress the file in-place) +app.out.css.compressed=${build.out.css.path} + +# the directory containing sass files for compass to compile +compass.sass.dir=${build.sass.dir} + +# the output directory where compass should place built css files +compass.css.dir=${build.out.css.dir} + +# the directory containing the ruby config file for compass +compass.config.file=${app.out.ruby} + +# enables / disables console highlighting for compass +compass.compile.boring=false + +# enables / disables forced rebuilds for compass +compass.compile.force=true + +# enables / disables stack traces in compass failure output +compass.compile.trace=true + +compass.cache.dir=${workspace.build.dir}/.sass-cache + +compass.working.dir=${build.sass.dir} + +# --------------------------------------------------- +# Legacy properties for ext41 theme directories +# Specify the resources path in the app +app.packages.dir=${app.dir}/packages + +# Specify the theme path in the app (this directory contains the themes) +app.theme.dir=${app.packages.dir} + +# the currently selected ext 41 theme name +theme.name=default +# --------------------------------------------------- + +# ***************************************************************************** +# Slice +# these properties control features of the theme slice build phase +# ***************************************************************************** + +# the resources directory of the application +# note: this property is currently only used for building ext 4.1 style themes +# (used by x-build-theme and x-copy-resources in slice-impl.xml) +app.resources.dir=${app.dir}/resources + +# the directory containing the slicer widget example page +app.example.dir=${app.dir}/sass/example + +# properties to control the recirect css file that is +# generated for the slicer example page +app.example.css.name=example.css +app.example.css.file=${app.example.dir}/${app.example.css.name} + +# the base path for generating the bootstrap code for the +# slicer page +bootstrap.base.path=${app.example.dir} + +# the full file name of the slicer page's bootstrap js file +bootstrap.example.js=${app.example.dir}/bootstrap.js + +# the full file name of the slicer page's bootstrap js file +bootstrap.example.json.name=bootstrap.json +bootstrap.example.json=${app.example.dir}/${bootstrap.example.json.name} + +# this is the directory used for intermediate build artifacts used +# by the slicer for generating theme images +app.example.build.dir=${build.temp.dir}/slicer-temp + +# the name of the intermediate screenshot file used for image slicing +build.capture.png=${app.example.build.dir}/theme-capture.png + +# the name of the intermediate widget manifest file used for image slicing +build.capture.json=${app.example.build.dir}/theme-capture.json + +# the location of the slicer widget page +app.example.theme.html.name=theme.html +app.example.fashion.html.name=fashion.html +app.example.theme.html=${app.example.dir}/${app.example.theme.html.name} +app.example.fashion.html=${app.example.dir}/${app.example.fashion.html.name} + +# a name prefix used for slicer page temporary artifacts +app.example.base=${app.name}-example + +# the special slicer page scss file name to generate +app.example.scss=${app.example.build.dir}/${app.example.base}.scss + +# the relative path from the slicer css file to the slicer html file +app.example.css.rel=${app.example.base}.css + +# the path to the css file that will be built for the slicer page +app.example.css=${app.example.build.dir}/${app.example.css.rel} + +# the ruby compass config file to generate for slicer page scss +app.example.out.ruby=${app.example.build.dir}/config.rb +app.example.compass.config=${app.example.out.ruby} + +# legacy ext 41 theme property indicating the name of the +# slicer example page contained in the theme directory +theme.page.name=theme.html + +# Options to pass to the "sencha fs slice" command. +build.slice.options= + +# ***************************************************************************** +# Packager +# these properties control features of the native packaging phase of the +# build process +# ***************************************************************************** + +# enables packaging the built application with the Sencha Desktop Packager +# NOTE: currently unsupported +enable.desktop.packager=false + +# skips packaging the built application with cordova/phonegap +skip.native-package=false + +# a property that controls whether a standalone manifest.json file will be +# generated for the native packaged application +enable.standalone.manifest=false + +# ***************************************************************************** +# Resolve +# these properties control aspects of the dynamic dependency resolver, which +# uses phantomjs to load the application and extract Ext.Loader class load +# history. +# ***************************************************************************** + +# enables / disables dynamic dependency resolution +skip.resolve=true + +# enables the local web server. this may be disabled to load the application's +# page from an existing web server. +skip.web-start=false + +# the port number to start the local web server on +build.web.port=1841 + +# the directory representing the root web folder +build.web.root=${workspace.dir} + +# the base url to access the local web server +build.resolve.url=http://localhost:${build.web.port} + +# a template string used to format the detected dynamic dependencies +build.resolve.tpl={0} + +# the mode to use when formatting the detected dynamic dependencies +build.resolve.mode=references + +# the output file for the detected dynamic dependencies +build.resolve.file=${build.temp.dir}/resolve.json + +# controls whether unmatched external references in the specified file will +# generate build warnings or build failures +build.resolve.allow.unmatched=true + +# ***************************************************************************** +# Watch +# these properties adjust the behavior of the app watch process. +# ***************************************************************************** + +# the default set of actions to run when triggering a rebuild +build.trigger.targets=refresh,resources,sass + +# the watcher targets to run that monitor for code changes +build.watcher.targets=-watch-compiler diff --git a/.sencha/app/development.defaults.properties b/.sencha/app/development.defaults.properties new file mode 100644 index 0000000..e07a438 --- /dev/null +++ b/.sencha/app/development.defaults.properties @@ -0,0 +1,30 @@ +# ============================================================================= +# This file defines default property values that apply to the "development" build +# environment. +# +# Please use testing.properties to customize these properties unless you want +# your customizations to be for all environments. In that case, you can instead +# override these properties in build.properties. +# +# The properties defined in this file take priority over defaults.properties +# but are lower priority than build.properties which in turn is lower priority +# than development.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +build.options.logger=yes + +build.options.debug=true + +build.css.compress=false + +build.include.all.scss=true + +# By default we don't need to build an "all.js" file, or a new markup page or +# slice images for IE8/9. These can be added to "development.properties" and +# set to 0 to enable them if needed. +skip.page=1 +skip.js=1 +skip.slice=1 diff --git a/.sencha/app/development.properties b/.sencha/app/development.properties new file mode 100644 index 0000000..d7a5e57 --- /dev/null +++ b/.sencha/app/development.properties @@ -0,0 +1,8 @@ +# ============================================================================= +# This file provides an override point for default variables defined in +# testing.defaults.properties. These properties are only imported when building +# for the "development" environment. +# +# Properties defined in this file take priority over build.properties but are +# only loaded for "development" builds. +# ============================================================================= diff --git a/.sencha/app/ext.properties b/.sencha/app/ext.properties new file mode 100644 index 0000000..c6ab83a --- /dev/null +++ b/.sencha/app/ext.properties @@ -0,0 +1,45 @@ +# ============================================================================= +# This file defines default property values that apply to all builds based on +# Ext JS 5.x framework. +# +# Please use build.properties to customize these properties. +# +# To override a property based on build.environment instead add properties to +# one of these higher priority files: +# +# - production.properties +# - testing.properties +# - native.properties +# - package.properties +# +# The properties defined in this file take priority over defaults.properties +# and *.defaults.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +enable.ext42.themes=true + +enable.sencha-core.filter=true + +build.options.product=ext + +build.options.minVersion=5 + +bootstrap.include.boot=true +bootstrap.override.tpl=Ext.Loader.loadScriptsSync +bootstrap.override.tpltype=jsonp + +app.microloader.name=Microloader.js +app.microloader.dir=${app.config.dir} +app.microloader.bootstrap=${app.microloader.dir}/${app.microloader.name} +app.microloader.path=${app.microloader.dir}/${app.microloader.name} + +build.microloader.json.tpl.embedded=var Ext = Ext || '{' '}'; Ext.manifest = Ext.manifest || {0}; +build.microloader.manifest.name=${app.manifest.name} +build.microloader.json.tpl.external=var Ext = Ext || '{' '}'; Ext.manifest = Ext.manifest || "${build.microloader.manifest.name}"; + +build.skip.versions.file=true +build.enable.appmanifest=true +compass.compile.force=false diff --git a/.sencha/app/find-cmd-impl.xml b/.sencha/app/find-cmd-impl.xml new file mode 100644 index 0000000..55d6826 --- /dev/null +++ b/.sencha/app/find-cmd-impl.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + source ~/.bash_profile; sencha which -p cmd.dir -o '$cmddir$' + + + + + + \ No newline at end of file diff --git a/.sencha/app/init-impl.xml b/.sencha/app/init-impl.xml new file mode 100644 index 0000000..a642c5f --- /dev/null +++ b/.sencha/app/init-impl.xml @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Application available at http://localhost:${build.web.port} + + + diff --git a/.sencha/app/js-impl.xml b/.sencha/app/js-impl.xml new file mode 100644 index 0000000..17dd9a7 --- /dev/null +++ b/.sencha/app/js-impl.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/native.defaults.properties b/.sencha/app/native.defaults.properties new file mode 100644 index 0000000..9b64ecd --- /dev/null +++ b/.sencha/app/native.defaults.properties @@ -0,0 +1,28 @@ +# ============================================================================= +# This file defines default property values that apply to the "native" build +# environment. +# +# Please use native.properties to customize these properties unless you want +# your customizations to be for all environments. In that case, you can instead +# override these properties in build.properties. +# +# The properties defined in this file take priority over defaults.properties +# but are lower priority than build.properties which in turn is lower priority +# than native.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +build.options.logger=no + +build.options.debug=false + +# enable yui compression +build.compression.yui=1 + +enable.standalone.manifest=true + +app.microloader.name=testing.js + +skip.native-package=false diff --git a/.sencha/app/native.properties b/.sencha/app/native.properties new file mode 100644 index 0000000..277ff19 --- /dev/null +++ b/.sencha/app/native.properties @@ -0,0 +1,8 @@ +# ============================================================================= +# This file provides an override point for default variables defined in +# native.defaults.properties. These properties are only imported when building +# for the "native" environment. +# +# Properties defined in this file take priority over build.properties but are +# only loaded for "native" builds. +# ============================================================================= diff --git a/.sencha/app/package.defaults.properties b/.sencha/app/package.defaults.properties new file mode 100644 index 0000000..e98b994 --- /dev/null +++ b/.sencha/app/package.defaults.properties @@ -0,0 +1,27 @@ +# ============================================================================= +# This file defines default property values that apply to the "package" build +# environment. +# +# Please use package.properties to customize these properties unless you want +# your customizations to be for all environments. In that case, you can instead +# override these properties in build.properties. +# +# The properties defined in this file take priority over defaults.properties +# but are lower priority than build.properties which in turn is lower priority +# than package.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# +# NOTE: This use of "package" applies to native packaged application, not a +# Package in the general since of code libraries. +# ============================================================================= + +build.options.logger=no + +build.options.debug=false + +# enable yui compression +build.compression.yui=1 + +app.microloader.name=testing.js diff --git a/.sencha/app/package.properties b/.sencha/app/package.properties new file mode 100644 index 0000000..3c59c31 --- /dev/null +++ b/.sencha/app/package.properties @@ -0,0 +1,11 @@ +# ============================================================================= +# This file provides an override point for default variables defined in +# package.defaults.properties. These properties are only imported when building +# for the "package" environment. +# +# Properties defined in this file take priority over build.properties but are +# only loaded for "package" builds. +# +# NOTE: This use of "package" applies to native packaged application, not a +# Package in the general since of code libraries. +# ============================================================================= diff --git a/.sencha/app/packager-impl.xml b/.sencha/app/packager-impl.xml new file mode 100644 index 0000000..ba5813a --- /dev/null +++ b/.sencha/app/packager-impl.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/page-impl.xml b/.sencha/app/page-impl.xml new file mode 100644 index 0000000..efe67e8 --- /dev/null +++ b/.sencha/app/page-impl.xml @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/phonegap-impl.xml b/.sencha/app/phonegap-impl.xml new file mode 100644 index 0000000..1ec137c --- /dev/null +++ b/.sencha/app/phonegap-impl.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + phonegap ${phonegap.cli.options} create "${app.phonegap.config.path}" ${app.phonegap.config.id} ${app.phonegap.config.name} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Phonegap Build login credentials were was not found. If you have not logged in prior to running this command. + Please either login via "phonegap remote login" or edit your [APP_ROOT]/local.properties and set "phonegap.username" and "phonegap.password" appropriately + + + + + + phonegap ${phonegap.cli.options} remote login --username="${phonegap.build.remote.username}" --password="${phonegap.build.remote.password}" + + + + + + + phonegap ${phonegap.cli.options} remote build ${phonegap.platform} + + + + + + + phonegap ${phonegap.cli.options} remote run ${phonegap.platform} + + + + + + + phonegap ${phonegap.cli.options} remote run ${phonegap.platform} --emulator + + + + + + + + phonegap ${phonegap.cli.options} local build ${phonegap.platform} + + + + + + + phonegap ${phonegap.cli.options} local run ${phonegap.platform} + + + + + + + phonegap ${phonegap.cli.options} local run ${phonegap.platform} --emulator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/phonegap.defaults.properties b/.sencha/app/phonegap.defaults.properties new file mode 100644 index 0000000..4fee1c8 --- /dev/null +++ b/.sencha/app/phonegap.defaults.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2012-2014. Sencha Inc. +# + +# Original PhoneGap Packager used the following properties +# here we map in the app space properties to allow for app.json +# setting of these instead of properties files +phonegap.platform=${app.phonegap.config.platform} +phonegap.build.remote=${app.phonegap.config.remote} + +# These are simply shorthanded as the user must specify them in +# a local.properties file anyway. +# No need for the user to type all this out. +phonegap.build.remote.username=${phonegap.username} +phonegap.build.remote.password=${phonegap.password} \ No newline at end of file diff --git a/.sencha/app/plugin.xml b/.sencha/app/plugin.xml new file mode 100644 index 0000000..d57eba8 --- /dev/null +++ b/.sencha/app/plugin.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/.sencha/app/production.defaults.properties b/.sencha/app/production.defaults.properties new file mode 100644 index 0000000..1b03df7 --- /dev/null +++ b/.sencha/app/production.defaults.properties @@ -0,0 +1,27 @@ +# ============================================================================= +# This file defines default property values that apply to the "production" build +# environment. +# +# Please use production.properties to customize these properties unless you want +# your customizations to be for all environments. In that case, you can instead +# override these properties in build.properties. +# +# The properties defined in this file take priority over defaults.properties +# but are lower priority than build.properties which in turn is lower priority +# than production.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +build.options.logger=no + +build.options.debug=false + +# enable the full class system optimizer +app.output.js.optimize=true +build.optimize=${build.optimize.enable} + +enable.resource.compression=true + +build.embedded.microloader.compressor=-closure diff --git a/.sencha/app/production.properties b/.sencha/app/production.properties new file mode 100644 index 0000000..8f03e38 --- /dev/null +++ b/.sencha/app/production.properties @@ -0,0 +1,8 @@ +# ============================================================================= +# This file provides an override point for default variables defined in +# production.defaults.properties. These properties are only imported when building +# for the "production" environment. +# +# Properties defined in this file take priority over build.properties but are +# only loaded for "production" builds. +# ============================================================================= diff --git a/.sencha/app/refresh-impl.xml b/.sencha/app/refresh-impl.xml new file mode 100644 index 0000000..53fdd6f --- /dev/null +++ b/.sencha/app/refresh-impl.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +var Ext = Ext || {}; +Ext.manifest = Ext.manifest || "${build.json.bootstrap.rel.path}"; + + + + + + + + + + + + + + + +/** + * This file is generated by Sencha Cmd and should NOT be edited. It is a + * combination of content from app.json, and all required package's package.json + * files. Customizations should be placed in app.json. + */ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/resolve-impl.xml b/.sencha/app/resolve-impl.xml new file mode 100644 index 0000000..51981f3 --- /dev/null +++ b/.sencha/app/resolve-impl.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.sencha/app/resources-impl.xml b/.sencha/app/resources-impl.xml new file mode 100644 index 0000000..7889940 --- /dev/null +++ b/.sencha/app/resources-impl.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/.sencha/app/sass-impl.xml b/.sencha/app/sass-impl.xml new file mode 100644 index 0000000..1981e99 --- /dev/null +++ b/.sencha/app/sass-impl.xml @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + include + -all + + + + + restore + page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Preprocessing @{cssfile} to ${css.output.name} + + + + + + + Compressing @{cssfile} to ${css.output.name} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fashion + -config=${build.out.json.path} + -compress=${build.css.compress} + -split=${build.css.selector.limit} + -saveFile=${app.dir}/${app.sass.generated.var} + ${app.out.scss} + ${app.out.css} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Compiling sass directory : @{theme}/sass + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.sencha/app/sencha.cfg b/.sencha/app/sencha.cfg new file mode 100644 index 0000000..656d2fa --- /dev/null +++ b/.sencha/app/sencha.cfg @@ -0,0 +1,11 @@ +# this property specifies a comma separated list of paths containing +# resources to copy to the build directory +app.resource.paths= + +#============================================================================== +# Custom Properties - Place customizations below this line to avoid merge +# conflicts with newer versions + +app.framework.version=6.2.0.981 + +app.cmd.version=6.2.2.36 diff --git a/.sencha/app/slice-impl.xml b/.sencha/app/slice-impl.xml new file mode 100644 index 0000000..3382421 --- /dev/null +++ b/.sencha/app/slice-impl.xml @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fashion + -compress=${build.css.compress} + -split=${build.css.selector.limit} + ${app.example.build.dir} + ${app.example.build.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + exclude + -tag=framework,package-sencha-core,package-core,package-${toolkit.name} + + + + + + + + + + + + + + + + Capture theme image to ${build.capture.png} + + + + + + + + + + + + + Capture theme image to ${build.capture.png} + + + + + + + Slicing theme images to ${build.resources.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Copying base framework images from ${framework.theme.dir} to ${tmp.img.dir} + + + + + + + + Building sass for theme ${theme.name} + + + + + + Slicing images for theme ${theme.name} to ${tmp.img.dir} + + + + + + + + Copying user defined images from @{theme}/images to ${tmp.img.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + Processing theme directories from ${app.theme.dir} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.sencha/app/testing.defaults.properties b/.sencha/app/testing.defaults.properties new file mode 100644 index 0000000..d665447 --- /dev/null +++ b/.sencha/app/testing.defaults.properties @@ -0,0 +1,21 @@ +# ============================================================================= +# This file defines default property values that apply to the "testing" build +# environment. +# +# Please use testing.properties to customize these properties unless you want +# your customizations to be for all environments. In that case, you can instead +# override these properties in build.properties. +# +# The properties defined in this file take priority over defaults.properties +# but are lower priority than build.properties which in turn is lower priority +# than testing.properties. +# +# IMPORTANT - This file should not be modified by an app as it is overwritten +# during each app upgrade. +# ============================================================================= + +build.options.logger=yes + +build.options.debug=true + +build.css.compress=false diff --git a/.sencha/app/testing.properties b/.sencha/app/testing.properties new file mode 100644 index 0000000..39b1727 --- /dev/null +++ b/.sencha/app/testing.properties @@ -0,0 +1,8 @@ +# ============================================================================= +# This file provides an override point for default variables defined in +# testing.defaults.properties. These properties are only imported when building +# for the "testing" environment. +# +# Properties defined in this file take priority over build.properties but are +# only loaded for "testing" builds. +# ============================================================================= diff --git a/.sencha/app/watch-impl.xml b/.sencha/app/watch-impl.xml new file mode 100644 index 0000000..381b09d --- /dev/null +++ b/.sencha/app/watch-impl.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f68555c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,63 @@ +# conjoon +# (c) 2007-2017 conjoon.org +# licensing@conjoon.org +# +# conjoon / conjoon +# +# This is the very basic travis configuration for the conjoon application +# of the conjoon Open Source Project. +# It simply creates a workspace, adds this application and tries to build it +# while making sure that required packages are merged into the workspace. +language: node_js +env: + - CN_MAIN="conjoon" CN_SENCHA_EXT_VERSION="6.2.0" CN_SENCHA_CMD_VERSION="6.2.2.36" CN_WORKSPACE="/tmp/conjoon" + +install: + - gem install jsduck + +before_script: + - "wget http://cdn.sencha.com/ext/gpl/ext-$CN_SENCHA_EXT_VERSION-gpl.zip" + - "unzip -q ext-$CN_SENCHA_EXT_VERSION-gpl.zip" + - "ln -sv `pwd`/ext-$CN_SENCHA_EXT_VERSION $TRAVIS_BUILD_DIR/../ext" + + - "wget http://cdn.sencha.com/cmd/$CN_SENCHA_CMD_VERSION/no-jre/SenchaCmd-$CN_SENCHA_CMD_VERSION-linux-amd64.sh.zip" + - "unzip -q SenchaCmd-$CN_SENCHA_CMD_VERSION-linux-amd64.sh.zip" + - "chmod +x SenchaCmd-$CN_SENCHA_CMD_VERSION-linux-amd64.sh" + - "./SenchaCmd-$CN_SENCHA_CMD_VERSION-linux-amd64.sh -q" + + - "export PATH=~/bin/Sencha/Cmd/$CN_SENCHA_CMD_VERSION/:$PATH" + + - "mkdir $CN_WORKSPACE" + - "sencha -sdk $TRAVIS_BUILD_DIR/../ext generate workspace $CN_WORKSPACE" + - "mkdir -p $CN_WORKSPACE/packages/local/" + - "mkdir -p $CN_WORKSPACE/$CN_MAIN" + - "cp $TRAVIS_BUILD_DIR/. $CN_WORKSPACE/$CN_MAIN -R" + +# add requirements before building +## theme-cn_default + - "cd /tmp && wget -O theme-cn_default.zip https://github.com/conjoon/theme-cn_default/archive/master.zip" + - "unzip theme-cn_default.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/theme-cn_default-master $CN_WORKSPACE/packages/local/theme-cn_default" +## lib-cn_core + - "cd /tmp && wget -O lib-cn_core.zip https://github.com/conjoon/lib-cn_core/archive/master.zip" + - "unzip lib-cn_core.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/lib-cn_core-master $CN_WORKSPACE/packages/local/lib-cn_core" +## lib-cn_comp + - "cd /tmp && wget -O lib-cn_comp.zip https://github.com/conjoon/lib-cn_comp/archive/master.zip" + - "unzip lib-cn_comp.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/lib-cn_comp-master $CN_WORKSPACE/packages/local/lib-cn_comp" +## app-cn_user + - "cd /tmp && wget -O app-cn_user.zip https://github.com/conjoon/app-cn_user/archive/master.zip" + - "unzip app-cn_user.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/app-cn_user-master $CN_WORKSPACE/packages/local/app-cn_user" +## app-cn_treenavviewport + - "cd /tmp && wget -O app-cn_treenavviewport.zip https://github.com/conjoon/app-cn_treenavviewport/archive/master.zip" + - "unzip app-cn_treenavviewport.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/app-cn_treenavviewport-master $CN_WORKSPACE/packages/local/app-cn_treenavviewport" +## app-cn_mail + - "cd /tmp && wget -O app-cn_mail.zip https://github.com/conjoon/app-cn_mail/archive/master.zip" + - "unzip app-cn_mail.zip -d $CN_WORKSPACE/packages/local/" + - "mv $CN_WORKSPACE/packages/local/app-cn_mail-master $CN_WORKSPACE/packages/local/app-cn_mail" + +script: + - "cd $CN_WORKSPACE/$CN_MAIN && sencha app build classic" \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..7959fec --- /dev/null +++ b/Readme.md @@ -0,0 +1 @@ +# conjoon [![Build Status](https://travis-ci.org/conjoon/conjoon.svg?branch=master)](https://travis-ci.org/conjoon/conjoon) \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..b9a4e2d --- /dev/null +++ b/app.js @@ -0,0 +1,12 @@ +/** + * This file is generated and updated by Sencha Cmd. You can edit this file as + * needed for your application, but these edits will have to be merged by + * Sencha Cmd when upgrading. + */ +Ext.application({ + + name: 'conjoon', + + extend: 'conjoon.Application' + +}); diff --git a/app.json b/app.json new file mode 100644 index 0000000..4d48e9d --- /dev/null +++ b/app.json @@ -0,0 +1,560 @@ +{ + /** + * The application's namespace. + */ + "name": "conjoon", + + /** + * The version of the application. + */ + "version": "0.0.1", + + /** + * The relative path to the application's markup file (html, jsp, asp, etc.). + */ + "indexHtmlPath": "index.html", + + /** + * Comma-separated string with the paths of directories or files to search. Any classes + * declared in these locations will be available in your class "requires" or in calls + * to "Ext.require". The "app.dir" variable below is expanded to the path where the + * application resides (the same folder in which this file is located). + */ + "classpath": [ + "app", + "${toolkit.name}/src" + ], + + /** + * Comma-separated string with the paths of directories or files to search. Any classes + * declared in these locations will be automatically required and included in the build. + * If any file defines an Ext JS override (using Ext.define with an "override" property), + * that override will in fact only be included in the build if the target class specified + * in the "override" property is also included. + */ + "overrides": [ + "overrides", + "${toolkit.name}/overrides" + ], + + /** + * The Sencha Framework for this application: "ext" or "touch". + */ + "framework": "ext", + + /** + * The list of required packages (with optional versions; default is "latest"). + * + * For example, + * + * "requires": [ + * "charts" + * ] + */ + "requires": [ + "font-awesome", + "theme-cn_default", + "lib-cn_core", + "lib-cn_comp", + "app-cn_user", + "app-cn_treenavviewport", + "app-cn_mail" + ], + + /** + * Fashion build configuration properties. + */ + "fashion": { + "inliner": { + /** + * Disable resource inliner. Production builds enable this by default. + */ + "enable": false + } + }, + + /** + * Sass configuration properties. + */ + "sass": { + /** + * The root namespace to use when mapping *.scss files to classes in the + * sass/src and sass/var directories. For example, "conjoon.view.Foo" would + * map to "sass/src/view/Foo.scss". If we changed this to "conjoon.view" then + * it would map to "sass/src/Foo.scss". To style classes outside the app's + * root namespace, change this to "". Doing so would change the mapping of + * "conjoon.view.Foo" to "sass/src/conjoon/view/Foo.scss". + */ + "namespace": "conjoon", + + /** + * Generated sass source settings + * + * "generated": { + * // The file used to save sass variables edited via Sencha Inspector and Sencha Themer. + * // This file will automatically be applied to the end of the scss build. + * "var": "sass/save.scss", + * + * // The directory used to save generated sass sources. + * // This directory will automatically be applied to the end of the scss build. + * "src": "sass/save" + * } + * + */ + + + /** + * Comma-separated list of files or folders containing extra Sass. These + * files are automatically included in the Sass compilation. By default this + * is just "etc/all.scss" to allow import directives to control the order + * other files are included. + * + * All "etc" files are included at the top of the Sass compilation in their + * dependency order: + * + * +-------+---------+ + * | | base | + * | theme +---------+ + * | | derived | + * +-------+---------+ + * | packages | (in package dependency order) + * +-----------------+ + * | application | + * +-----------------+ + */ + "etc": [ + "sass/etc/all.scss", + "${toolkit.name}/sass/etc/all.scss" + ], + + /** + * Comma-separated list of folders containing Sass variable definitions + * files. These file can also define Sass mixins for use by components. + * + * All "var" files are included after "etc" files in the Sass compilation in + * dependency order: + * + * +-------+---------+ + * | | base | + * | theme +---------+ + * | | derived | + * +-------+---------+ + * | packages | (in package dependency order) + * +-----------------+ + * | application | + * +-----------------+ + * + * The "sass/var/all.scss" file is always included at the start of the var + * block before any files associated with JavaScript classes. + */ + "var": [ + "sass/var/all.scss", + "sass/var", + "${toolkit.name}/sass/var" + ], + + /** + * Comma-separated list of folders containing Sass rule files. + * + * All "src" files are included after "var" files in the Sass compilation in + * dependency order (the same order as "etc"): + * + * +-------+---------+ + * | | base | + * | theme +---------+ + * | | derived | + * +-------+---------+ + * | packages | (in package dependency order) + * +-----------------+ + * | application | + * +-----------------+ + */ + "src": [ + "sass/src", + "${toolkit.name}/sass/src" + ] + }, + + /** + * List of all JavaScript assets in the right execution order. + * + * Each item is an object with the following format: + * + * { + * // Path to file. If the file is local this must be a relative path from + * // this app.json file. + * // + * "path": "path/to/script.js", // REQUIRED + * + * // Set to true on one file to indicate that it should become the container + * // for the concatenated classes. + * // + * "bundle": false, // OPTIONAL + * + * // Set to true to include this file in the concatenated classes. + * // + * "includeInBundle": false, // OPTIONAL + * + * // Specify as true if this file is remote and should not be copied into the + * // build folder. Defaults to false for a local file which will be copied. + * // + * "remote": false, // OPTIONAL + * + * // If not specified, this file will only be loaded once, and cached inside + * // localStorage until this value is changed. You can specify: + * // + * // - "delta" to enable over-the-air delta update for this file + * // - "full" means full update will be made when this file changes + * // + * "update": "", // OPTIONAL + * + * // A value of true indicates that is a development mode only dependency. + * // These files will not be copied into the build directory or referenced + * // in the generate app.json manifest for the micro loader. + * // + * "bootstrap": false // OPTIONAL + * } + * + */ + "js": [ + { + "path": "app.js", + "bundle": true + }, + // load the Sims only in development mode. + { + "path" : "../packages/local/app-cn_mail/src/data/mail/PackageSim.js", + "bootstrap" : true + } + ], + + + /** + * Settings specific to classic toolkit builds. + */ + "classic": { + "js": [ + // Remove this entry to individually load sources from the framework. + { + /** + * @bug + * @see https://www.sencha.com/forum/showthread.php?325776-Upgrading-from-6-0-2-to-6-2-0-has-made-all-our-grids-right-align + */ + //"path": "${framework.dir}/build/ext-all-rtl-debug.js" + "path": "${framework.dir}/build/ext-all-debug.js" + + } + ] + }, + + + /** + * List of all CSS assets in the right inclusion order. + * + * Each item is an object with the following format: + * + * { + * // Path to file. If the file is local this must be a relative path from + * // this app.json file. + * // + * "path": "path/to/stylesheet.css", // REQUIRED + * + * // Specify as true if this file is remote and should not be copied into the + * // build folder. Defaults to false for a local file which will be copied. + * // + * "remote": false, // OPTIONAL + * + * // If not specified, this file will only be loaded once, and cached inside + * // localStorage until this value is changed. You can specify: + * // + * // - "delta" to enable over-the-air delta update for this file + * // - "full" means full update will be made when this file changes + * // + * "update": "" // OPTIONAL + * } + */ + "css": [ + { + // this entry uses an ant variable that is the calculated + // value of the generated output css file for the app, + // defined in .sencha/app/defaults.properties + "path": "${build.out.css.path}", + "bundle": true, + "exclude": ["fashion"] + } + ], + + /** + * This option is used to configure the dynamic loader. At present these options + * are supported. + * + */ + "loader": { + // This property controls how the loader manages caching for requests: + // + // - true: allows requests to receive cached responses + // - false: disable cached responses by adding a random "cache buster" + // - other: a string (such as the build.timestamp shown here) to allow + // requests to be cached for this build. + // + "cache": false, + + // When "cache" is not true, this value is the request parameter used + // to control caching. + // + "cacheParam": "_dc" + }, + + /** + * Settings specific to production builds. + */ + "production": { + "output": { + "appCache": { + "enable": true, + "path": "cache.appcache" + } + }, + "loader": { + "cache": "${build.timestamp}" + }, + "cache": { + "enable": true + }, + "compressor": { + "type": "yui" + } + }, + + /** + * Settings specific to testing builds. + */ + "testing": { + }, + + /** + * Settings specific to development builds. + */ + "development": { + "watch": { + "delay": 250 + } + }, + + /** + * Controls the output structure of development-mode (bootstrap) artifacts. May + * be specified by a string: + * + * "bootstrap": "${app.dir}" + * + * This will adjust the base path for all bootstrap objects, or expanded into object + * form: + * + * "bootstrap": { + * "base": "${app.dir}, + * "manifest": "bootstrap.json", + * "microloader": "bootstrap.js", + * "css": "bootstrap.css" + * } + * + * You can optionally exclude entries from the manifest. For example, to exclude + * the "loadOrder" (to help development load approximate a build) you can add: + * + * "bootstrap": { + * "manifest": { + * "path": "bootstrap.json", + * "exclude": "loadOrder" + * } + * } + * + */ + "bootstrap": { + "base": "${app.dir}", + + "manifest": "${build.id}.json", + + "microloader": "bootstrap.js", + "css": "bootstrap.css" + }, + + /** + * Controls the output directory for build resources. May be set with + * either a string: + * + * "${workspace.build.dir}/${build.environment}/${app.name}" + * + * or an object containing values for various types of build artifacts: + * + * { + * "base": "${workspace.build.dir}/${build.environment}/${app.name}", + * "page": { + * "path": "../index.html", + * "enable": false + * }, + * "css": "${app.output.resources}/${app.name}-all.css", + * "js": "app.js", + * "microloader": { + * "path": "microloader.js", + * "embed": true, + * "enable": true + * }, + * "manifest": { + * "path": "app.json", + * "embed": false, + * "enable": "${app.output.microloader.enable}" + * }, + * "resources": "resources", + * "slicer": { + * "path": "${app.output.resources}/images", + * "enable": false + * }, + * // Setting the "enable" property of this object to a Truthy value will cause a Application Cache + * // manifest file to be generated based on this files appCache object. This file will then be injected + * // into the index.html file of the built application + * "appCache":{ + * "enable": false" + * } + * } + * + */ + + "output": { + "base": "${workspace.build.dir}/${build.environment}/${app.name}", + "page": "index.html", + "manifest": "${build.id}.json", + "js": "${build.id}/app.js", + "appCache": { + "enable": false + }, + "resources": { + "path": "${build.id}/resources", + "shared": "resources" + } + }, + + + /** + * Controls for localStorage caching + * "cache": { + * // This property controls whether localStorage caching of this manifest file is on or off. + * // if disabled no deltas will be generated during a build and full updates will be disabled + * "enable": false, + * + * // This property allows for global toggle of deltas. + * // If set to a string the value will be used as the path to where deltas will be generated relative to you build. + * // If set to a Truthy Value the default path ok "deltas" will be used + * // If set to a Falsey value or if this property is not present deltas will be disabled and not generated. + * + * "deltas": "deltas" + * } + */ + + "cache": { + "enable": false, + "deltas": "${build.id}/deltas" + }, + + + /** + * Used to automatically generate cache.manifest (HTML 5 application cache manifest) + * file when you build. + */ + "appCache": { + /** + * List of items in the CACHE MANIFEST section + */ + "cache": [ + "index.html" + ], + /** + * List of items in the NETWORK section + */ + "network": [ + "*" + ], + /** + * List of items in the FALLBACK section + */ + "fallback": [] + }, + + /** + * Extra resources to be copied into the resource folder as specified in the "resources" + * property of the "output" object. Folders specified in this list will be deeply copied. + */ + "resources": [ + { + "path": "resources", + "output": "shared" + }, + { + "path": "${toolkit.name}/resources" + }, + { + "path": "${build.id}/resources" + } + ], + + /** + * Directory path to store all previous production builds. Note that the content + * generated inside this directory must be kept intact for proper generation of + * deltas between updates. + */ + + "archivePath": "archive/${build.id}", + + + + + /** + * Build Profiles. This object's properties are each a "build profile". You can + * add as many as you need to produce optimized builds for devices, themes, locales + * or other criteria. Your "Ext.beforeLoad" hook (see index.html) is responsible for + * selecting the desired build profile by setting "Ext.manifest" to one of these + * names. + * + * "builds": { + * "classic": { + * "toolkit": "classic", + * "theme": "theme-neptune" + * }, + * + * "modern": { + * "toolkit": "modern", + * "theme": "theme-neptune" + * } + * } + * + */ + + "builds": { + + "classic": { + "toolkit": "classic", + + "theme": "theme-cn_default", + + "sass": { + "generated": { + "var": "classic/sass/save.scss", + "src": "classic/sass/save" + } + } + } + }, + + + /** + * File / directory name patttern to ignore when copying to the builds. Must be a + * valid regular expression. + */ + "ignore": [ + "(^|/)CVS(/?$|/.*?$)" + ], + + /** + * Uniquely generated id for this application, used as prefix for localStorage keys. + * Normally you should never change this value. + */ + "id": "b5cc4b54-e659-4e3f-8ed3-91655f273db6" +} diff --git a/app/Application.js b/app/Application.js new file mode 100644 index 0000000..37c14a4 --- /dev/null +++ b/app/Application.js @@ -0,0 +1,48 @@ +/** + * conjoon + * (c) 2007-2017 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2017 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * The main application class. An instance of this class is created by app.js when it + * calls Ext.application(). This is the ideal place to handle application launch and + * initialization details. + */ +Ext.define('conjoon.Application', { + + extend: 'conjoon.cn_comp.app.Application', + + requires : [ + 'conjoon.view.main.Viewport' + ], + + controllers : [ + 'conjoon.cn_user.controller.PackageController', + 'conjoon.cn_mail.controller.PackageController' + ], + + name : 'conjoon', + + defaultToken : 'home', + + applicationViewClassName : 'conjoon.view.main.Viewport' + + +}); diff --git a/app/Readme.md b/app/Readme.md new file mode 100644 index 0000000..4942954 --- /dev/null +++ b/app/Readme.md @@ -0,0 +1,30 @@ +# ./controller + +This folder contains the application's global controllers. ViewControllers are located +alongside their respective view class in `"./view"`. These controllers are used for routing +and other activities that span all views. + +# ./model + +This folder contains the application's (data) Model classes. + +# ./view + +This folder contains the views as well as ViewModels and ViewControllers depending on the +application's architecture. Pure MVC applications may not have ViewModels, for example. For +MVCVM applications or MVC applications that use ViewControllers, the following directory +structure is recommended: + + ./view/ + foo/ # Some meaningful grouping of one or more views + Foo.js # The view class + FooController.js # The controller for Foo (a ViewController) + FooModel.js # The ViewModel for Foo + +This structure helps keep these closely related classes together and easily identifiable in +most tabbed IDE's or text editors. + +# ./store + +This folder contains any number of store instances or types that can then be reused in the +application. diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..2c9c13d --- /dev/null +++ b/build.xml @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/classic/src/view/main/Viewport.js b/classic/src/view/main/Viewport.js new file mode 100644 index 0000000..714e202 --- /dev/null +++ b/classic/src/view/main/Viewport.js @@ -0,0 +1,37 @@ +/** + * conjoon + * (c) 2007-2017 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2017 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Custom viewport to make sure the {@link conjoon.view.main.controller.ViewportController} + * is used with this view. + */ +Ext.define('conjoon.view.main.Viewport', { + + extend: 'conjoon.cn_treenavviewport.view.NavigationViewport', + + requires : [ + 'conjoon.view.main.controller.ViewportController' + ], + + controller : 'cn_app-mainviewport-ctrl' + +}); \ No newline at end of file diff --git a/classic/src/view/main/controller/ViewportController.js b/classic/src/view/main/controller/ViewportController.js new file mode 100644 index 0000000..14452aa --- /dev/null +++ b/classic/src/view/main/controller/ViewportController.js @@ -0,0 +1,81 @@ +/** + * conjoon + * (c) 2007-2017 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2017 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * This is the extended controller for the main viewport of conjoon. + * It derives from {@link conjoon.cn_treenavviewport.view.controller.NavigationViewportController} + * to add custom layout options to the navigation tree. + */ +Ext.define('conjoon.view.main.controller.ViewportController', { + + extend: 'conjoon.cn_treenavviewport.view.controller.NavigationViewportController', + + alias: 'controller.cn_app-mainviewport-ctrl', + + /** + * Callback for the {@link conjoon.cn_treenavviewport.view.NavigationToolbar}'s + * hideNavigation Button. + * + * @param {Ext.Button} btn + * + * see {@link #hideNavigation} + */ + onHideNavigationClick : function(btn) { + + var me = this, + view = me.getView(), + navTree = view.lookup('cn_treenavviewport_ref_conwrap') + .lookup('cn_treenavviewport_ref_navtree'); + + me.hideNavigation(!navTree.getMicro()); + }, + + + /** + * Hides the NavigationTree by only setting it to Micro Mode. + * + * @param {Boolean} hide True to hide the NavigationTree, otherwise false. + */ + hideNavigation : function(hide) { + + var me = this, + view = me.getView(), + contentWrap = view.lookup('cn_treenavviewport_ref_conwrap'), + navTree = contentWrap.lookup('cn_treenavviewport_ref_navtree'), + appLogo = view.lookup('cn_treenavviewport_ref_tbar') + .lookup('cn_treenavviewport_ref_applogo'), + newWidth = hide ? 64 : 250; + + appLogo.animate({ + dynamic : true, + to : { + width : newWidth + } + }); + + navTree.setWidth(newWidth); + navTree.setMicro(hide); + + contentWrap.updateLayout({isRoot: true}); + } + +}); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..484867b --- /dev/null +++ b/index.html @@ -0,0 +1,55 @@ + + + + + + + + conjoon + + + + + + + + + + + diff --git a/jsduck.json b/jsduck.json new file mode 100644 index 0000000..faeed03 --- /dev/null +++ b/jsduck.json @@ -0,0 +1,8 @@ +{ + "--ignore-global": true, + "--output": "docs/api", + "--ignore-html": "locale", + "--": [ + "src", "classic" +] +} \ No newline at end of file diff --git a/resources/Readme.md b/resources/Readme.md new file mode 100644 index 0000000..7ed062b --- /dev/null +++ b/resources/Readme.md @@ -0,0 +1,7 @@ +# conjoon/resources + +#### html/blank.html +This is a blank page which is mainly used by conjoon.cn_comp.form.AutoCompleteForm +to provide a valid post target to make sure auto completion works after +submitting the form. +For more information, see the documentation of [conjoon.cn_comp.form.AutoCompleteForm](https://github.com/conjoon/lib-cn_comp/blob/master/classic/src/form/AutoCompleteForm.js). diff --git a/resources/html/blank.html b/resources/html/blank.html new file mode 100644 index 0000000..25d941d --- /dev/null +++ b/resources/html/blank.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/sass/Readme.md b/sass/Readme.md new file mode 100644 index 0000000..be77ae2 --- /dev/null +++ b/sass/Readme.md @@ -0,0 +1,46 @@ +# ./sass + +This folder contains the styling for the application's views. + +## Styling + +Sencha Cmd supports styling using Sass and integrates the styling from the theme +and required packages (specified in `"app.json"`) with application-defined views. + +### ./sass/etc + +This folder contains misc. support code for Sass builds (global functions, etc.). + +### ./sass/src + +This folder contains Sass files defining CSS rules corresponding to classes +included in the application's JavaScript code build. By default, files in this +folder are mapped to the application's root namespace, 'conjoon'. This is set in +`"app.json"`: + + "sass": { + "namespace": "conjoon" + } + +### ./sass/var + +This folder contains Sass files defining Sass variables corresponding to classes +included in the application's JavaScript code build. By default, files in this +folder are mapped to the application's root namespace, 'conjoon' in the same way +as `"conjoon/sass/src"`. + +## Slicing + +Internet Explorer 8 and 9 do not support linear gradients and IE8 does not support +border-radius. To compensate for this, Sencha Cmd provides "image slicing" using an +internal WebKit based renderer. To enable this, there is a special web page that +renders all components and states so they can be captured and turned into image +sprites. + +### ./sass/example + +This folder contains the web page used to present all components and states so they +can be captured as an image and used to produce images for IE8 and 9. + +This web page is also helpful when loaded in Chrome to view all components in their +styled form. diff --git a/sass/config.rb b/sass/config.rb new file mode 100644 index 0000000..2c32c0a --- /dev/null +++ b/sass/config.rb @@ -0,0 +1,2 @@ +cur_dir = File.dirname(__FILE__) +output_style = :nested diff --git a/sass/etc/all.scss b/sass/etc/all.scss new file mode 100644 index 0000000..c3e4222 --- /dev/null +++ b/sass/etc/all.scss @@ -0,0 +1,3 @@ +/* + * This is is imported by virtue of "sass.etc" in "app.json". + */ diff --git a/sass/example/bootstrap.css b/sass/example/bootstrap.css new file mode 100644 index 0000000..b29582f --- /dev/null +++ b/sass/example/bootstrap.css @@ -0,0 +1,7 @@ +/** + * This file is generated by Sencha Cmd and should NOT be edited. It will + * redirect to the most recently built example css file for the application to + * support capture of theme background, frame, and corner images for non-CSS3 + * browsers. + */ +@import '../../bootstrap.css'; \ No newline at end of file diff --git a/sass/example/bootstrap.js b/sass/example/bootstrap.js new file mode 100644 index 0000000..9d9e1b6 --- /dev/null +++ b/sass/example/bootstrap.js @@ -0,0 +1,2679 @@ +// @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 = {}), + + // All calls to _debug are commented out to speed up old browsers a bit; + // yes that makes a difference because the cost of concatenating strings + // and passing them into _debug() adds up pretty quickly. + _debug = function (message) { + //console.log(message); + }, + _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 + */ + debug: _debug, + + /** + * 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)]) { +// _debug("creating entry " + key + " in Boot.init"); + 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) { +// _debug("Boot.load called"); + 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) { +// _debug("current active request, suspending this request"); + // 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) { +// _debug("Boot.loadSync called"); + 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) { +// _debug("resuming suspended request"); + 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 { +// _debug("fetching " + url + " " + (async ? "async" : "sync")); + 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) { +// _debug("firing request 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; + } + +// _debug("creating entry for " + cfg.url); + + 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) { +// _debug("checking " + me.getLoadUrl() + " for prefix " + Boot.origin); + 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) { +// _debug("creating element for " + me.url); + 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 = + ("Failed loading synchronously via XHR: '" + url + + "'. It's likely that the file is either being loaded from a " + + "different domain or from the local file system where cross " + + "origin requests are not allowed for security reasons. Try " + + "asynchronous loading instead.") || + 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 = + ("Failed loading synchronously via XHR: '" + url + + "'. Please verify that the file exists. XHR status code: " + + status) || + 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) { +// _debug("injecting content for " + this.url); + 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 + + + + + + + diff --git a/sass/example/render.js b/sass/example/render.js new file mode 100644 index 0000000..4d888d7 --- /dev/null +++ b/sass/example/render.js @@ -0,0 +1,450 @@ +/* + * This file is generated by Sencha Cmd and should NOT be edited. It will be replaced + * during an upgrade. + */ + +// This flag is checked by many Components to avoid compatibility warnings when +// the code is running under the slicer +Ext.slicer = true; + +Ext.require([ + 'Ext.layout.Context' +]); + +Ext.theme = Ext.apply(Ext.theme || {}, { + /** + * The array of all component manifests. These objects have the following set of + * properties recognized by the slicer: + * @private + */ + _manifest: [], + + /** + * The collection of shortcuts for a given alias (e.g., 'widget.panel'). This is an + * object keyed by alias whose values are arrays of shortcut definitions. + * @private + */ + _shortcuts: {}, + + doRequire : function(xtype) { + if(xtype.indexOf("widget.") != 0) { + xtype = "widget." + xtype; + } + Ext.require([xtype]); + }, + + /** + * Adds one ore more component entries to the theme manifest. These entries will be + * instantiated by the `Ext.theme.render` method when the page is ready. + * + * Usage: + * + * Ext.theme.addManifest({ + * xtype: 'widget.menu', + * folder: 'menu', + * delegate: '.x-menu-item-link', + * filename: 'menu-item-active', + * config: { + * floating: false, + * width: 200, + * items: [{ + * text: 'test', + * cls: 'x-menu-item-active' + * }] + * } + * },{ + * //... + * }); + * + * @param manifest {Object} An object with type of component, slicing information and + * component configuration. If this parameter is an array, each element is treated as + * a manifest entry. Otherwise, each argument passed is treated as a manifest entry. + * + * @param manifest.xtype {String} The xtype ('grid') or alias ('widget.grid'). This + * is used to specify the type of component to create as well as a potential key to + * any `shortcuts` defined for the xtype. + * + * @param manifest.config {Object} The component configuration object. The properties + * of this depend on the `xtype` of the component. + * + * @param [manifest.delegate] {String} The DOM query to use to select the element to + * slice. The default is to slice the primary element of the component. + * + * @param [manifest.parentCls] An optional CSS class to add to the parent of the + * component. + * + * @param [manifest.setup] {Function} An optional function to be called to initialize + * the component. + * @param manifest.setup.component {Ext.Component} The component instance + * @param manifest.setup.container {Element} The component's container. + * + * @param [manifest.folder] {String} The folder in to which to produce image slices. + * Only applies to Ext JS 4.1 (removed in 4.2). + * + * @param [manifest.filename] {String} The base filename for slices. + * Only applies to Ext JS 4.1 (removed in 4.2). + * + * @param [manifest.reverse] {Boolean} True to position the slices for linear gradient + * background at then opposite "end" (right or bottom) and apply the stretch to the + * area before it (left or top). Only applies to Ext JS 4.1 (removed in 4.2). + */ + addManifest: function (manifest) { + var all = Ext.theme._manifest; + var add = Ext.isArray(manifest) ? manifest : arguments; + + if(manifest.xtype) { + Ext.theme.doRequire(manifest.xtype); + } + + for (var i = 0, n = add.length; i < n; ++i) { + if(add[i].xtype) { + Ext.theme.doRequire(add[i].xtype); + } + all.push(add[i]); + } + }, + + /** + * Adds one or more shortcuts to the rendering process. A `shortcut` is an object that + * looks the same as a `manifest` entry. These are combined by copying the properties + * from the shortcut over those of the manifest entry. In basic terms: + * + * var config = Ext.apply(Ext.apply({}, manfiest.config), shortcut.config); + * var entry = Ext.apply(Ext.apply({}, manfiest), shortcut); + * entry.config = config; + * + * This is not exactly the process, but the idea is the same. The difference is that + * the `ui` of the manifest entry is used to replace any `"{ui}"` substrings found in + * any string properties of the shortcut or its `config` object. + * + * Usage: + * + * Ext.theme.addShortcuts({ + * 'widget.foo': [{ + * config: { + * } + * },{ + * config: { + * } + * }], + * + * 'widget.bar': [ ... ] + * }); + */ + addShortcuts: function (shortcuts) { + var all = Ext.theme._shortcuts; + + for (var key in shortcuts) { + + var add = shortcuts[key]; + var xtype = Ext.theme.addWidget(key); + var existing = all[xtype]; + + Ext.theme.doRequire(xtype); + for(var i=0; i < add.length; i++) { + var config = add[i]; + if(config.xtype) { + Ext.theme.doRequire(config.xtype); + } + } + + if (!existing) { + all[xtype] = existing = []; + } + + existing.push.apply(existing, add); + } + }, + + /** + * This method ensures that a given string has the specified prefix (e.g., "widget."). + * @private + */ + addPrefix: function (prefix, s) { + if (!s || (s.length > prefix.length && s.substring(0,prefix.length) === prefix)) { + return s; + } + return prefix + s; + }, + + /** + * This method returns the given string with "widget." added to the front if that is + * not already present. + * @private + */ + addWidget: function (str) { + return Ext.theme.addPrefix('widget.', str); + }, + + /** + * This method accepts an manifest entry and a shortcut entry and returns the merged + * version. + * @private + */ + applyShortcut: function (manifestEntry, shortcut) { + var ui = manifestEntry.ui; + var config = Ext.theme.copyProps({}, manifestEntry.config); + var entry = Ext.theme.copyProps({}, manifestEntry); + + if (ui && !config.ui) { + config.ui = ui; + } + if (shortcut) { + var tpl = { ui: ui }; + Ext.theme.copyProps(entry, shortcut, tpl); + Ext.theme.copyProps(config, shortcut.config, tpl); + } + + entry.xtype = Ext.theme.addWidget(entry.xtype); + entry.config = config; // both guys have "config" so smash merged one on now... + return entry; + }, + + /** + * This method copies property from a `src` object to a `dest` object and reaplces + * `"{foo}"` fragments of any string properties as defined in the `tpl` object. + * + * var obj = Ext.theme.copyProps({}, { + * foo: 'Hello-{ui}' + * }, { + * ui: 'World' + * }); + * + * console.log('obj.foo: ' + obj.foo); // logs "Hello-World" + * + * @return {Object} The `dest` object or a new object (if `dest` was null). + * @private + */ + copyProps: function (dest, src, tpl) { + var out = dest || {}; + var replacements = []; + var token; + + if (src) { + if (tpl) { + for (token in tpl) { + replacements.push({ + re: new RegExp('\\{' + token + '\\}', 'g'), + value: tpl[token] + }); + } + } + + for (var key in src) { + var val = src[key]; + if (tpl && typeof val === 'string') { + for (var i = 0; i < replacements.length; ++ i) { + val = val.replace(replacements[i].re, replacements[i].value); + } + } + out[key] = val; + } + } + + return out; + }, + + /** + * Renders a component given its manifest and shortcut entries. + * @private + */ + renderWidget: function (manifestEntry, shortcut) { + var entry = Ext.theme.applyShortcut(manifestEntry, shortcut); + var config = entry.config; + var widget = Ext.create(entry.xtype, config); + var ct = Ext.fly(document.body).createChild({ cls: 'widget-container' }); + + Ext.theme.currentWidget = widget; + + if (widget.floating === true) { + widget.floating = { shadow: false }; + } + if (widget.floating) { + widget.focusOnToFront = false; + } + + if (entry.setup) { + entry.setup.call(widget, widget, ct); + } else { + widget.render(ct); + if (widget.floating) { + widget.showAt(0, 0); + ct.setHeight(widget.getHeight()); + } + } + + var el = widget.el; + if (entry.delegate) { + el = el.down(entry.delegate); + } + + el.addCls('x-slicer-target'); // this is what generateSlicerManifest looks for + + if (entry.over) { + widget.addOverCls(); + } + if (config.parentCls) { + el.parent().addCls(config.parentCls); + } + + if (Ext.theme.legacy) { + // The 4.1 approach has some interesting extra pieces + // + var data = {}; + if (entry.reverse) { + data.reverse = true; + } + if (entry.filename) { + data.filename = entry.filename; + } + if (entry.folder) { + data.folder = entry.folder; + } + if (entry.offsets) { + data.offsets = entry.offsets; + } + + Ext.theme.setData(el.dom, data); + } + + Ext.theme.currentWidget = null; + }, + + /** + * Renders all of the components that have been added to the manifest. + * @private + */ + render: function () { + console.log("rendering widgets...") + var manifest = Ext.theme._manifest; + var shortcuts = Ext.theme._shortcuts; + + for (var k = 0, n = manifest ? manifest.length : 0; k < n; ++k) { + var manifestEntry = manifest[k]; + var xtype = Ext.theme.addWidget(manifestEntry.xtype); + var widgetShortcuts = xtype ? shortcuts[xtype] : null; + + if (xtype && manifestEntry.ui && widgetShortcuts) { + for (var i = 0; i < widgetShortcuts.length; i++) { + Ext.theme.renderWidget(manifestEntry, widgetShortcuts[i]); + } + } else { + Ext.theme.renderWidget(manifestEntry); + } + } + }, + + /** + * Renders all components (see `render`) and notifies the Slicer that things are ready. + * @private + */ + run: function () { + var extjsVer = Ext.versions.extjs; + var globalData = {}; + + if (Ext.layout.Context) { + Ext.override(Ext.layout.Context, { + run: function () { + var ok = this.callParent(), + widget = Ext.theme.currentWidget; + if (!ok && widget) { + Ext.Error.raise("Layout run failed: " + widget.id); + } + return ok; + } + }); + } + + console.log("loading widget definitions..."); + + // Previous to Ext JS 4.2, themes and their manifests where defined differently. + // So pass this along if we are hosting a pre-4.2 theme. + // + if (extjsVer && extjsVer.isLessThan(new Ext.Version("4.2"))) { + globalData.format = "1.0"; // tell the Slicer tool + Ext.theme.legacy = true; // not for our own data collection + + // Check for the Cmd3.0/ExtJS4.1 variables: + // + if (Ext.manifest && Ext.manifest.widgets) { + Ext.theme.addManifest(Ext.manifest.widgets); + } + if (Ext.shortcuts) { + Ext.theme.addShortcuts(Ext.shortcuts); + } + if (Ext.userManifest && Ext.userManifest.widgets) { + Ext.theme.addManifest(Ext.userManifest.widgets); + } + } + + Ext.theme.setData(document.body, globalData); + Ext.theme.render(); + Ext.theme.generateSlicerManifest(); + }, + + generateSlicerManifest: function() { + var now = new Date().getTime(), + me = Ext.theme, + // This function is defined by slicer.js (the framework-independent piece) + gsm = window && window['generateSlicerManifest'], + delta; + + me.generateStart = me.generateStart || now; + delta = now - me.generateStart; + + if(gsm) { + gsm(); + } else if(delta < (10 * 1000)){ + // allow the outer script wrapper a chance to inject the capture function + // but stop trying after 10 seconds + Ext.defer(Ext.theme.generateSlicerManifest, 100); + } + }, + + /** + * Sets the `data-slicer` attribute to the JSON-encoded value of the provided data. + * @private + */ + setData: function (el, data) { + if (data) { + var json = Ext.encode(data); + if (json !== '{}') { + el.setAttribute('data-slicer', json); + } + } + }, + + /** + * This used to be `loadExtStylesheet`. + * @private + */ + loadCss: function (src, callback) { + var xhr = new XMLHttpRequest(); + + xhr.open('GET', src); + + xhr.onload = function() { + var css = xhr.responseText, + head = document.getElementsByTagName('head')[0], + style = document.createElement('style'); + + // There's bugginess in the next gradient syntax in WebKit r84622 + // This might be fixed in a later WebKit, but for now we're going to + // strip it out here since compass generates it. + // + // TODO: Upgrade to later WebKit revision + css = css.replace(/background(-image)?: ?-webkit-linear-gradient(?:.*?);/g, ''); + + style.type = 'text/css'; + style.innerText = css; + + head.appendChild(style); + callback(); + }; + + xhr.send(null); + } +}); + +console.log("registering ready listener..."); +Ext.onReady(Ext.theme.run, Ext.theme); diff --git a/sass/example/theme.html b/sass/example/theme.html new file mode 100644 index 0000000..697664e --- /dev/null +++ b/sass/example/theme.html @@ -0,0 +1,37 @@ + + + + + Ext JS Theme Harness + + + + + + + + + + diff --git a/sass/var/all.scss b/sass/var/all.scss new file mode 100644 index 0000000..9e095bc --- /dev/null +++ b/sass/var/all.scss @@ -0,0 +1,5 @@ +/* + * This is is imported by virtue of "sass.var" in "app.json". + */ + +$enable-font-awesome: dynamic(true); diff --git a/tests/Readme.md b/tests/Readme.md new file mode 100644 index 0000000..95bb835 --- /dev/null +++ b/tests/Readme.md @@ -0,0 +1,16 @@ +# conjoon - Tests - Read Me + +conjoon uses [Siesta](http://bryntum.com) for Unit/UI testing. + +Make sure you set the paths to the resources properly in the files index.html.template and +tests.config.js.template, then rename them: + +``` +index.html.template -> index.html +tests.config.js.template -> tests.config.js +``` + +The tests require lib-cn_comp, lib-cn_core, app-cn_mail, app-cn_user and +app-cn_treenavviewport. Make sure you adjust the paths to this library in the +index.js if both packages are not part of a regular local package directory +layout in a sencha workspace. \ No newline at end of file diff --git a/tests/app/ApplicationTest.js b/tests/app/ApplicationTest.js new file mode 100644 index 0000000..8b95897 --- /dev/null +++ b/tests/app/ApplicationTest.js @@ -0,0 +1,48 @@ +/** + * conjoon + * (c) 2007-2017 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2017 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +describe('conjoon.ApplicationTest', function(t) { + + var application; + + + t.afterEach(function() { + if (application) { + application.destroy(); + application = null; + } + }); + + t.it("Should test the Application", function(t) { + + application = Ext.create('conjoon.Application'); + + t.expect(application instanceof conjoon.cn_comp.app.Application).toBe(true); + + t.expect(application.getName()).toBe('conjoon'); + t.expect(application.getDefaultToken()).toBe('home'); + t.expect(application.applicationViewClassName).toBe('conjoon.view.main.Viewport'); + + t.expect(application.controllers.items.length).toBe(2); + }); + +}); diff --git a/tests/classic/src/view/main/ViewportTest.js b/tests/classic/src/view/main/ViewportTest.js new file mode 100644 index 0000000..6a6dc55 --- /dev/null +++ b/tests/classic/src/view/main/ViewportTest.js @@ -0,0 +1,56 @@ +/** + * conjoon + * (c) 2007-2016 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2016 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +describe('conjoon.view.main.ViewportTest', function(t) { + + var viewport; + + + t.afterEach(function() { + if (viewport) { + viewport.destroy(); + viewport = null; + } + }); + + t.it("Should be using the custom controller", function(t) { + viewport = Ext.create('conjoon.view.main.Viewport'); + + t.expect( + viewport.getController() instanceof conjoon.view.main.controller.ViewportController + ).toBe(true); + }); + + + t.it("Should be possible to resize the navigation to micromode", function(t) { + viewport = Ext.create('conjoon.view.main.Viewport'); + + + t.expect(viewport.down('cn_treenavviewport-navtree').getWidth()).toBe(250); + viewport.hideNavigation(true); + t.expect(viewport.down('cn_treenavviewport-navtree').getWidth()).toBe(64); + viewport.hideNavigation(false); + t.expect(viewport.down('cn_treenavviewport-navtree').getWidth()).toBe(250); + }); + + +}); diff --git a/tests/classic/src/view/main/controller/ViewportControllerTest.js b/tests/classic/src/view/main/controller/ViewportControllerTest.js new file mode 100644 index 0000000..72de895 --- /dev/null +++ b/tests/classic/src/view/main/controller/ViewportControllerTest.js @@ -0,0 +1,43 @@ +/** + * conjoon + * (c) 2007-2016 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2016 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +describe('conjoon.view.main.ViewportControllerTest', function(t) { + + var viewportCtrl; + + t.afterEach(function() { + if (viewportCtrl) { + viewportCtrl.destroy(); + viewportCtrl = null; + } + }); + + t.it("Should create the ViewportController", function(t) { + viewportCtrl = Ext.create('conjoon.view.main.controller.ViewportController'); + t.expect( + viewportCtrl instanceof conjoon.cn_treenavviewport.view.controller.NavigationViewportController + ).toBe(true); + + t.expect(viewportCtrl.alias).toContain('controller.cn_app-mainviewport-ctrl'); + }); + +}); diff --git a/tests/classic/src/view/mock/ApplicationMock.js b/tests/classic/src/view/mock/ApplicationMock.js new file mode 100644 index 0000000..37a057a --- /dev/null +++ b/tests/classic/src/view/mock/ApplicationMock.js @@ -0,0 +1,40 @@ +/** + * conjoon + * (c) 2007-2016 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2016 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +Ext.define('conjoon.test.view.mock.ApplicationMock', { + + extend : 'conjoon.cn_comp.app.Application', + + name : 'test', + + requires : [ + 'conjoon.view.main.Viewport' + ], + + controllers : [ + 'conjoon.test.view.mock.PackageControllerMock' + ], + + applicationViewClassName : 'conjoon.view.main.Viewport' + + +}); diff --git a/tests/classic/src/view/mock/PackageControllerMock.js b/tests/classic/src/view/mock/PackageControllerMock.js new file mode 100644 index 0000000..2ca060d --- /dev/null +++ b/tests/classic/src/view/mock/PackageControllerMock.js @@ -0,0 +1,30 @@ +/** + * conjoon + * (c) 2007-2016 conjoon.org + * licensing@conjoon.org + * + * conjoon + * Copyright (C) 2016 Thorsten Suckow-Homberg/conjoon.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +Ext.define('conjoon.test.view.mock.PackageControllerMock', { + + extend : 'conjoon.cn_core.app.PackageController' + + + +}); diff --git a/tests/index.html.template b/tests/index.html.template new file mode 100644 index 0000000..cb6a317 --- /dev/null +++ b/tests/index.html.template @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..4d11dca --- /dev/null +++ b/tests/index.js @@ -0,0 +1,66 @@ +var harness = new Siesta.Harness.Browser.ExtJS(); + +harness.configure({ + title : 'My Tests', + disableCaching : true, + loaderPath : { + + + 'conjoon.Application' : '../app/Application.js', + + 'conjoon.view' : '../classic/src/view', + + 'conjoon.test.view.mock' : './classic/src/view/mock', + + /** + * Universal + */ + 'conjoon.cn_treenavviewport' : '../../packages/local/app-cn_treenavviewport/src', + + /** + * Classic + */ + 'conjoon.cn_treenavviewport.view' : '../../packages/local/app-cn_treenavviewport/classic/src/view', + 'conjoon.cn_mail.view' : '../../packages/local/app-cn_mail/classic/src/view', + + /** + * Requirements + */ + 'conjoon.cn_core' : '../../packages/local/lib-cn_core/src', + 'conjoon.cn_comp.container' : '../../packages/local/lib-cn_comp/classic/src/container', + 'conjoon.cn_comp.app' : '../../packages/local/lib-cn_comp/src/app', + 'conjoon.cn_comp.list' : '../../packages/local/lib-cn_comp/classic/src/list', + 'conjoon.cn_comp.window' : '../../packages/local/lib-cn_comp/classic/src/window' + }, + preload : [ + conjoon.tests.config.paths.extjs.css.url, + conjoon.tests.config.paths.extjs.js.url + ] +}); + +harness.start({ + group : 'universal', + items : [{ + group : 'app', + pageUrl : '../index.html?unittest', + items : [ + 'app/ApplicationTest.js' + ] + }] + },{ + group : 'classic', + items : [{ + group : 'view', + items : [{ + group : 'main', + items : [ + 'classic/src/view/main/ViewportTest.js', + { + group : 'controller', + items : [ + 'classic/src/view/main/controller/ViewportControllerTest.js', + ]} + ] + }] + }] +}); diff --git a/tests/tests.config.js.template b/tests/tests.config.js.template new file mode 100644 index 0000000..dffb080 --- /dev/null +++ b/tests/tests.config.js.template @@ -0,0 +1,17 @@ +var conjoon = conjoon || {}; +conjoon.tests = conjoon.tests || {}; +conjoon.tests.config = conjoon.tests.config || {}; + + +conjoon.tests.config.paths = { + extjs : { + js : { + url : "[PATH_TO_EXT_ALL.JS]" /*Your path to your ExtJS distribution (e.g. ext-all-debug.js) */ + }, + css : { + url : "[PATH_TO_EXT_THEME.JS]" /*Your path to an ExtJS theme, preferably Triton Theme */ + } + } +} + +