From 936fa026a6e51a20a66982a48129234a8620f445 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Thu, 1 May 2014 11:21:55 -0400 Subject: [PATCH] ui: update ember, dist steps --- ui/Gemfile | 6 + ui/Gemfile.lock | 22 + ui/Makefile | 10 +- ui/README.md | 17 +- ui/index.html | 3 +- .../libs/{ember-1.5.0.js => ember-1.5.1.js} | 410 +++++++++++++----- ui/scripts/compile.rb | 32 ++ 7 files changed, 370 insertions(+), 130 deletions(-) create mode 100644 ui/Gemfile create mode 100644 ui/Gemfile.lock rename ui/javascripts/libs/{ember-1.5.0.js => ember-1.5.1.js} (99%) create mode 100644 ui/scripts/compile.rb diff --git a/ui/Gemfile b/ui/Gemfile new file mode 100644 index 0000000000..77b884c352 --- /dev/null +++ b/ui/Gemfile @@ -0,0 +1,6 @@ +# A sample Gemfile +source "https://rubygems.org" + +gem "uglifier" +gem "sass" +gem "therubyracer" diff --git a/ui/Gemfile.lock b/ui/Gemfile.lock new file mode 100644 index 0000000000..8ca7428084 --- /dev/null +++ b/ui/Gemfile.lock @@ -0,0 +1,22 @@ +GEM + remote: https://rubygems.org/ + specs: + execjs (2.0.2) + json (1.8.1) + libv8 (3.16.14.3) + ref (1.0.5) + sass (3.3.6) + therubyracer (0.12.1) + libv8 (~> 3.16.14.0) + ref + uglifier (2.5.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + +PLATFORMS + ruby + +DEPENDENCIES + sass + therubyracer + uglifier diff --git a/ui/Makefile b/ui/Makefile index 986be0b4f3..4956a7501c 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -4,7 +4,11 @@ server: watch: sass styles:static --watch -build: - sass styles/base.scss static/base.css +dist: + @echo "compile styles/*.scss" + @sass styles/base.scss static/base.css + @ruby scripts/compile.rb + cp -R ./static dist/static + cp index.html dist/ -.PHONY: server watch build +.PHONY: server watch dist diff --git a/ui/README.md b/ui/README.md index 795878b61f..e7f7b48eb9 100644 --- a/ui/README.md +++ b/ui/README.md @@ -25,14 +25,11 @@ performance and usability. Improvements and bug fixes are welcome and encouraged for the Web UI. -The UI is built with SASS CSS, so you'll need to compile that through -the associated makefile, as well as installing the `sass` gem. +You'll need sass to compile CSS stylesheets. Install that with +bundler: - gem install sass - -One-time stylesheet compilation: - - make build + cd ui/ + bundle Reloading compilation for development: @@ -47,3 +44,9 @@ An example of this command, from inside the `ui/` directory, would be: consul agent -bootstrap -server -data-dir /tmp/ -ui-dir . + +### Releasing + +These steps are slightly manual at the moment. + +1. Build with `make dist` diff --git a/ui/index.html b/ui/index.html index ccbfe504a9..cf99ab3c23 100644 --- a/ui/index.html +++ b/ui/index.html @@ -403,7 +403,7 @@ - + @@ -411,7 +411,6 @@ - diff --git a/ui/javascripts/libs/ember-1.5.0.js b/ui/javascripts/libs/ember-1.5.1.js similarity index 99% rename from ui/javascripts/libs/ember-1.5.0.js rename to ui/javascripts/libs/ember-1.5.1.js index fa4b380fc1..4ec7312559 100755 --- a/ui/javascripts/libs/ember-1.5.0.js +++ b/ui/javascripts/libs/ember-1.5.1.js @@ -5,7 +5,7 @@ * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.5.0 + * @version 1.5.1 */ @@ -227,7 +227,7 @@ if (!Ember.testing) { * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.5.0 + * @version 1.5.1 */ @@ -310,7 +310,7 @@ var define, requireModule, require, requirejs; @class Ember @static - @version 1.5.0 + @version 1.5.1 */ if ('undefined' === typeof Ember) { @@ -337,10 +337,10 @@ Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String - @default '1.5.0' + @default '1.5.1' @static */ -Ember.VERSION = '1.5.0'; +Ember.VERSION = '1.5.1'; /** Standard environmental variables. You can define these in a global `EmberENV` @@ -10704,7 +10704,7 @@ define("rsvp", })(); (function() { -define("container/container", +define("container/container", ["container/inheriting_dict","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -11516,7 +11516,7 @@ define("container/container", __exports__["default"] = Container; }); -define("container/inheriting_dict", +define("container/inheriting_dict", ["exports"], function(__exports__) { "use strict"; @@ -11630,7 +11630,7 @@ define("container/inheriting_dict", __exports__["default"] = InheritingDict; }); -define("container", +define("container", ["container/container","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -15872,10 +15872,11 @@ function ReduceComputedProperty(options) { this.cacheable(); this.recomputeOnce = function(propertyName) { - // TODO: Coalesce recomputation by . - recompute.call(this, propertyName); + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + Ember.run.once(this, recompute, propertyName); }; - var recompute = function(propertyName) { var dependentKeys = cp._dependentKeys, meta = cp._instanceMeta(this, propertyName), @@ -34955,6 +34956,15 @@ Ember.Router = Ember.Object.extend(Ember.Evented, { */ location: 'hash', + /** + Represents the URL of the root of the application, often '/'. This prefix is + assumed on all routes defined on this router. + + @property rootURL + @default '/' + */ + rootURL: '/', + init: function() { this.router = this.constructor.router || this.constructor.map(Ember.K); this._activeViews = {}; @@ -35134,6 +35144,10 @@ Ember.Router = Ember.Object.extend(Ember.Evented, { var location = get(this, 'location'), rootURL = get(this, 'rootURL'); + if (rootURL && !this.container.has('-location-setting:root-url')) { + this.container.register('-location-setting:root-url', rootURL, { instantiate: false }); + } + if ('string' === typeof location && this.container) { var resolvedLocation = this.container.lookup('location:' + location); @@ -35147,7 +35161,7 @@ Ember.Router = Ember.Object.extend(Ember.Evented, { } } - if (typeof rootURL === 'string') { + if (rootURL && typeof rootURL === 'string') { location.rootURL = rootURL; } @@ -39239,6 +39253,7 @@ Ember.Location = { }, implementations: {}, + _location: window.location, /** Returns the current `location.hash` by parsing location.href since browsers @@ -39249,8 +39264,10 @@ Ember.Location = { @private @method getHash */ - getHash: function () { - var href = window.location.href, + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href, hashIndex = href.indexOf('#'); if (hashIndex === -1) { @@ -39365,8 +39382,7 @@ Ember.NoneLocation = Ember.Object.extend({ @submodule ember-routing */ -var get = Ember.get, set = Ember.set, - getHash = Ember.Location.getHash; +var get = Ember.get, set = Ember.set; /** `Ember.HashLocation` implements the location API using the browser's @@ -39381,9 +39397,18 @@ Ember.HashLocation = Ember.Object.extend({ implementation: 'hash', init: function() { - set(this, 'location', get(this, 'location') || window.location); + set(this, 'location', get(this, '_location') || window.location); }, + /** + @private + + Returns normalized location.hash + + @method getHash + */ + getHash: Ember.Location._getHash, + /** Returns the current `location.hash`, minus the '#' at the front. @@ -39391,7 +39416,7 @@ Ember.HashLocation = Ember.Object.extend({ @method getURL */ getURL: function() { - return getHash().substr(1); + return this.getHash().substr(1); }, /** @@ -39524,7 +39549,7 @@ Ember.HistoryLocation = Ember.Object.extend({ rootURL: '/', /** - Returns the current `location.pathname` without `rootURL`. + Returns the current `location.pathname` without `rootURL` or `baseURL` @private @method getURL @@ -39555,7 +39580,7 @@ Ember.HistoryLocation = Ember.Object.extend({ var state = this.getState(); path = this.formatURL(path); - if (state && state.path !== path) { + if (!state || state.path !== path) { this.pushState(path); } }, @@ -39572,15 +39597,16 @@ Ember.HistoryLocation = Ember.Object.extend({ var state = this.getState(); path = this.formatURL(path); - if (state && state.path !== path) { + if (!state || state.path !== path) { this.replaceState(path); } }, /** - Get the current `history.state` - Polyfill checks for native browser support and falls back to retrieving - from a private _historyState variable + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. @private @method getState @@ -39700,11 +39726,11 @@ Ember.HistoryLocation = Ember.Object.extend({ @submodule ember-routing */ - var get = Ember.get, set = Ember.set; - var documentMode = document.documentMode, - history = window.history, - location = window.location, - getHash = Ember.Location.getHash; + var get = Ember.get, set = Ember.set, + HistoryLocation = Ember.HistoryLocation, + HashLocation = Ember.HashLocation, + NoneLocation = Ember.NoneLocation, + EmberLocation = Ember.Location; /** Ember.AutoLocation will select the best location option based off browser @@ -39723,6 +39749,19 @@ Ember.HistoryLocation = Ember.Object.extend({ var AutoLocation = Ember.AutoLocation = { /** + @private + + This property is used by router:main to know whether to cancel the routing + setup process, which is needed while we redirect the browser. + + @property cancelRouterSetup + @default false + */ + cancelRouterSetup: false, + + /** + @private + Will be pre-pended to path upon state change. @property rootURL @@ -39733,28 +39772,78 @@ Ember.HistoryLocation = Ember.Object.extend({ /** @private - Exposed for testing + Attached for mocking in tests + + @property _window + @default window + */ + _window: window, + + /** + @private + + Attached for mocking in tests @property location @default window.location */ - _location: location, + _location: window.location, + + /** + @private + + Attached for mocking in tests + + @property _history + @default window.history + */ + _history: window.history, + + /** + @private + + Attached for mocking in tests + + @property _HistoryLocation + @default Ember.HistoryLocation + */ + _HistoryLocation: HistoryLocation, + + /** + @private + + Attached for mocking in tests + + @property _HashLocation + @default Ember.HashLocation + */ + _HashLocation: HashLocation, + + /** + @private + + Attached for mocking in tests + + @property _NoneLocation + @default Ember.NoneLocation + */ + _NoneLocation: NoneLocation, /** @private Returns location.origin or builds it if device doesn't support it. - @method getOrigin + @method _getOrigin */ - getOrigin: function () { + _getOrigin: function () { var location = this._location, origin = location.origin; // Older browsers, especially IE, don't have origin if (!origin) { origin = location.protocol + '//' + location.hostname; - + if (location.port) { origin += ':' + location.port; } @@ -39769,14 +39858,14 @@ Ember.HistoryLocation = Ember.Object.extend({ We assume that if the history object has a pushState method, the host should support HistoryLocation. - @property supportsHistory + @method _getSupportsHistory */ - supportsHistory: (function () { + _getSupportsHistory: function () { // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js // The stock browser on Android 2.2 & 2.3 returns positive on history support // Unfortunately support is really buggy and there is no clean way to detect // these bugs, so we fall back to a user agent sniff :( - var userAgent = window.navigator.userAgent; + var userAgent = this._window.navigator.userAgent; // We only want Android 2, stock browser, and not Chrome which identifies // itself as 'Mobile Safari' as well @@ -39786,8 +39875,8 @@ Ember.HistoryLocation = Ember.Object.extend({ return false; } - return !!(history && 'pushState' in history); - })(), + return !!(this._history && 'pushState' in this._history); + }, /** @private @@ -39795,56 +39884,13 @@ Ember.HistoryLocation = Ember.Object.extend({ IE8 running in IE7 compatibility mode gives false positive, so we must also check documentMode. - @property supportsHashChange + @method _getSupportsHashChange */ - supportsHashChange: ('onhashchange' in window && (documentMode === undefined || documentMode > 7 )), + _getSupportsHashChange: function () { + var window = this._window, + documentMode = window.document.documentMode; - create: function (options) { - if (options && options.rootURL) { - this.rootURL = options.rootURL; - } - - var implementationClass, historyPath, hashPath, - cancelRouterSetup = false, - currentPath = this.getFullPath(); - - if (this.supportsHistory) { - historyPath = this.getHistoryPath(); - - // Since we support history paths, let's be sure we're using them else - // switch the location over to it. - if (currentPath === historyPath) { - implementationClass = Ember.HistoryLocation; - } else { - cancelRouterSetup = true; - this.replacePath(historyPath); - } - - } else if (this.supportsHashChange) { - hashPath = this.getHashPath(); - - // Be sure we're using a hashed path, otherwise let's switch over it to so - // we start off clean and consistent. - if (currentPath === hashPath) { - implementationClass = Ember.HashLocation; - } else { - cancelRouterSetup = true; - this.replacePath(hashPath); - } - } - - // If none has been set - if (!implementationClass) { - implementationClass = Ember.NoneLocation; - } - - var implementation = implementationClass.create.apply(implementationClass, arguments); - - if (cancelRouterSetup) { - set(implementation, 'cancelRouterSetup', true); - } - - return implementation; + return ('onhashchange' in window && (documentMode === undefined || documentMode > 7 )); }, /** @@ -39853,10 +39899,18 @@ Ember.HistoryLocation = Ember.Object.extend({ Redirects the browser using location.replace, prepending the locatin.origin to prevent phishing attempts - @method replacePath + @method _replacePath */ - replacePath: function (path) { - this._location.replace(this.getOrigin() + path); + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; }, /** @@ -39864,10 +39918,10 @@ Ember.HistoryLocation = Ember.Object.extend({ Returns the current `location.pathname`, normalized for IE inconsistencies. - @method getPath + @method _getPath */ - getPath: function () { - var pathname = location.pathname; + _getPath: function () { + var pathname = this._location.pathname; // Various versions of IE/Opera don't always return a leading slash if (pathname.charAt(0) !== '/') { pathname = '/' + pathname; @@ -39879,30 +39933,81 @@ Ember.HistoryLocation = Ember.Object.extend({ /** @private - Returns the full pathname including the hash string. + Returns normalized location.hash as an alias to Ember.Location._getHash - @method getFullPath + @method _getHash */ - getFullPath: function () { - return this.getPath() + getHash().substr(1); + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); }, /** @private Returns the current path as it should appear for HistoryLocation supported - browsers. This may very well differ from the real current path (e.g. if it + browsers. This may very well differ from the real current path (e.g. if it starts off as a hashed URL) - @method getHistoryPath + @method _getHistoryPath */ - getHistoryPath: function () { - var path = this.getPath(), - hashPath = getHash().substr(1), - url = path + hashPath; + _getHistoryPath: function () { + var rootURL = this._getRootURL(), + path = this._getPath(), + hash = this._getHash(), + query = this._getQuery(), + rootURLIndex = path.indexOf(rootURL), + routeHash, hashParts; - // Removes any stacked double stashes - return url.replace(/\/\//, '/'); + Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; }, /** @@ -39911,19 +40016,79 @@ Ember.HistoryLocation = Ember.Object.extend({ Returns the current path as it should appear for HashLocation supported browsers. This may very well differ from the real current path. - @method getHashPath + @method _getHashPath */ - getHashPath: function () { - var historyPath = this.getHistoryPath(), - exp = new RegExp('(' + this.rootURL + ')(.+)'), - url = historyPath.replace(exp, '$1#/$2'); + _getHashPath: function () { + var rootURL = this._getRootURL(), + path = rootURL, + historyPath = this._getHistoryPath(), + routePath = historyPath.substr(rootURL.length); - // Remove any stacked double stashes - url = url.replace(/\/\//, '/'); + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } - return url; + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"', options.rootURL.charAt(options.rootURL.length-1) === '/'); + this.rootURL = options.rootURL; + } + + var historyPath, hashPath, + cancelRouterSetup = false, + implementationClass = this._NoneLocation, + currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; } - }; })(); @@ -41235,6 +41400,7 @@ Ember.Application.reopenClass({ container.injection('controller', 'namespace', 'application:main'); container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); // DEBUGGING container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); @@ -42083,7 +42249,7 @@ Ember Extension Support })(); -define("container/container", +define("container/container", ["container/inheriting_dict","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -42501,7 +42667,7 @@ define("container/container", validateFullName(fullName); if (this.parent) { illegalChildOperation('typeInjection'); } - var fullNameType = fullName.split(':')[0]; + var fullNameType = fullName.split(':')[0]; if(fullNameType === type) { throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); } @@ -42565,6 +42731,9 @@ define("container/container", validateFullName(fullName); var normalizedName = this.normalize(fullName); + if (this.cache.has(normalizedName)) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } addInjection(this.injections, normalizedName, property, normalizedInjectionName); }, @@ -42667,6 +42836,9 @@ define("container/container", validateFullName(fullName); + if (this.factoryCache.has(normalizedName)) { + throw new Error("Attempted to register a factoryInjection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); }, @@ -42898,7 +43070,7 @@ define("container/container", } __exports__["default"] = Container; - });define("ember-runtime/ext/rsvp", + });define("ember-runtime/ext/rsvp", ["ember-metal/core","ember-metal/logger","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -42921,6 +43093,8 @@ define("container/container", } else { throw error; } + } else if (Ember.onerror) { + Ember.onerror(error); } else { Logger.error(error.stack); Ember.assert(error, false); @@ -42931,7 +43105,7 @@ define("container/container", RSVP.on('error', RSVP.onerrorDefault); __exports__["default"] = RSVP; - });define("ember-runtime/system/container", + });define("ember-runtime/system/container", ["ember-metal/property_set","exports"], function(__dependency1__, __exports__) { "use strict"; diff --git a/ui/scripts/compile.rb b/ui/scripts/compile.rb new file mode 100644 index 0000000000..f69937e6bf --- /dev/null +++ b/ui/scripts/compile.rb @@ -0,0 +1,32 @@ +require 'uglifier' + +File.open("static/application.min.js", "w") {|file| file.truncate(0) } + +libs = [ + "javascripts/libs/jquery-1.10.2.js", + "javascripts/libs/handlebars-1.1.2.js", + "javascripts/libs/ember-1.5.1.js", + "javascripts/libs/ember-validations.js", +] + +app = [ + "javascripts/app/router.js", + "javascripts/app/models.js", + "javascripts/app/routes.js", + "javascripts/app/controllers.js", + "javascripts/app/views.js", +] + +libs.each do |js_file| + File.open("static/application.min.js", "a") do |f| + puts "compile #{js_file}" + f << Uglifier.compile(File.read(js_file)) + end +end + +app.each do |js_file| + File.open("static/application.min.js", "a") do |f| + puts "compile #{js_file}" + f << Uglifier.compile(File.read(js_file)) + end +end