diff --git a/.openshift/quickstart.json b/.openshift/quickstart.json index 6e4784f86..e76dabda8 100644 --- a/.openshift/quickstart.json +++ b/.openshift/quickstart.json @@ -1,7 +1,7 @@ { "name":"Ghost", "website":"http://tryghost.org/", -"version":"0.5.6", +"version":"0.5.7", "initial_git_url":"https://github.com/fuzzmz/openshift-ghost-quickstart.git", "cartridges":["nodejs-0.10"], "env_variables":[{"name":"value"},{"name":"value"}], diff --git a/Gruntfile.js b/Gruntfile.js index 1c81bb8e3..786209d91 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -317,7 +317,7 @@ var _ = require('lodash'), }, testem: { - command: path.resolve(cwd + '/node_modules/.bin/testem ci'), + command: path.resolve(cwd + '/node_modules/.bin/testem ci -f core/test/client/testem.json'), options: { stdout: true, stdin: false diff --git a/bower.json b/bower.json index a8a3202dc..4805b9819 100644 --- a/bower.json +++ b/bower.json @@ -8,7 +8,7 @@ "ember-data": "1.0.0-beta.11", "ember-load-initializers": "git://github.com/stefanpenner/ember-load-initializers.git#0.0.1", "ember-resolver": "git://github.com/stefanpenner/ember-jj-abrams-resolver.git#181251821cf513bb58d3e192faa13245a816f75e", - "ember-simple-auth": "0.6.6", + "ember-simple-auth": "0.7.2", "fastclick": "1.0.0", "handlebars": "1.3.0", "ic-ajax": "1.0.1", diff --git a/core/built/scripts/ghost-dev.js b/core/built/scripts/ghost-dev.js index b8ad1858f..3c3ce48ce 100644 --- a/core/built/scripts/ghost-dev.js +++ b/core/built/scripts/ghost-dev.js @@ -477,6 +477,7 @@ define("ghost/assets/lib/uploader", // This is the start point if no image exists $dropzone.find('img.js-upload-target').css({display: 'none'}); + $dropzone.find('div.description').show(); $dropzone.removeClass('pre-image-uploader image-uploader-url').addClass('image-uploader'); this.removeExtras(); this.buildExtras(); @@ -500,6 +501,7 @@ define("ghost/assets/lib/uploader", $dropzone.find('.js-cancel').on('click', function () { $dropzone.find('.js-url').remove(); $dropzone.find('.js-fileupload').removeClass('right'); + $dropzone.trigger('imagecleared'); self.removeExtras(); self.initWithDropzone(); }); @@ -541,10 +543,12 @@ define("ghost/assets/lib/uploader", // This is the start point if an image already exists $dropzone.removeClass('image-uploader image-uploader-url').addClass('pre-image-uploader'); $dropzone.find('div.description').hide(); + $dropzone.find('img.js-upload-target').show(); $dropzone.append($cancel); $dropzone.find('.js-cancel').on('click', function () { $dropzone.find('img.js-upload-target').attr({src: ''}); $dropzone.find('div.description').show(); + $dropzone.trigger('imagecleared'); $dropzone.delay(2500).animate({opacity: 100}, 1000, function () { self.init(); }); @@ -604,7 +608,11 @@ define("ghost/components/gh-activating-list-item", var ActivatingListItem = Ember.Component.extend({ tagName: 'li', classNameBindings: ['active'], - active: false + active: false, + + unfocusLink: function () { + this.$('a').blur(); + }.on('click') }); __exports__["default"] = ActivatingListItem; @@ -1553,7 +1561,7 @@ define("ghost/components/gh-uploader", } }); - $this.find('.js-cancel').on('click', function () { + $this.on('imagecleared', function () { self.sendAction('canceled'); }); }.on('didInsertElement'), @@ -1718,44 +1726,6 @@ define("ghost/controllers/forgotten", __exports__["default"] = ForgottenController; }); -define("ghost/controllers/modals/auth-failed-unsaved", - ["exports"], - function(__exports__) { - "use strict"; - var AuthFailedUnsavedController = Ember.Controller.extend({ - editorController: Ember.computed.alias('model'), - - actions: { - confirmAccept: function () { - var editorController = this.get('editorController'); - - if (editorController) { - editorController.get('model').rollback(); - } - - window.onbeforeunload = null; - - window.location = this.get('ghostPaths').adminRoot + '/signin/'; - }, - - confirmReject: function () { - } - }, - - confirm: { - accept: { - text: 'Leave', - buttonClass: 'btn btn-red' - }, - reject: { - text: 'Stay', - buttonClass: 'btn btn-default btn-minor' - } - } - }); - - __exports__["default"] = AuthFailedUnsavedController; - }); define("ghost/controllers/modals/copy-html", ["exports"], function(__exports__) { @@ -1781,6 +1751,8 @@ define("ghost/controllers/modals/delete-all", type: 'DELETE' }).then(function () { self.notifications.showSuccess('All content deleted from database.'); + self.store.unloadAll('post'); + self.store.unloadAll('tag'); }).catch(function (response) { self.notifications.showErrors(response); }); @@ -1850,7 +1822,27 @@ define("ghost/controllers/modals/delete-user", ["exports"], function(__exports__) { "use strict"; - var DeleteUserController = Ember.Controller.extend({ + var DeleteUserController = Ember.ObjectController.extend({ + userPostCount: Ember.computed('id', function () { + var promise, + query = { + author: this.get('slug'), + status: 'all' + }; + + promise = this.store.find('post', query).then(function (results) { + return results.meta.pagination.total; + }); + + return Ember.Object.extend(Ember.PromiseProxyMixin, { + count: Ember.computed.alias('content'), + + inflection: Ember.computed('count', function () { + return this.get('count') > 1 ? 'posts' : 'post'; + }) + }).create({promise: promise}); + }), + actions: { confirmAccept: function () { var self = this, @@ -2035,6 +2027,41 @@ define("ghost/controllers/modals/leave-editor", __exports__["default"] = LeaveEditorController; }); +define("ghost/controllers/modals/signin", + ["ghost/controllers/signin","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var SigninController = __dependency1__["default"]; + + __exports__["default"] = SigninController.extend({ + needs: 'application', + + identification: Ember.computed('session.user.email', function () { + return this.get('session.user.email'); + }), + + actions: { + authenticate: function () { + var appController = this.get('controllers.application'), + self = this; + + appController.set('skipAuthSuccessHandler', true); + + this._super().then(function () { + self.send('closeModal'); + self.notifications.showSuccess('Login successful.'); + self.set('password', ''); + }).finally(function () { + appController.set('skipAuthSuccessHandler', undefined); + }); + }, + + confirmAccept: function () { + this.send('validateAndAuthenticate'); + } + } + }); + }); define("ghost/controllers/modals/transfer-owner", ["exports"], function(__exports__) { @@ -3210,6 +3237,7 @@ define("ghost/controllers/settings/labs", formData = new FormData(); this.set('uploadButtonText', 'Importing'); + this.set('importErrors', ''); this.notifications.closePassive(); formData.append('importfile', file); @@ -3277,10 +3305,14 @@ define("ghost/controllers/settings/tags", var TagsController = Ember.ArrayController.extend(PaginationMixin, { tags: Ember.computed.alias('model'), + needs: 'application', + activeTag: null, activeTagNameScratch: boundOneWay('activeTag.name'), activeTagSlugScratch: boundOneWay('activeTag.slug'), activeTagDescriptionScratch: boundOneWay('activeTag.description'), + activeTagMetaTitleScratch: boundOneWay('activeTag.meta_title'), + activeTagMetaDescriptionScratch: boundOneWay('activeTag.meta_description'), init: function (options) { options = options || {}; @@ -3288,18 +3320,90 @@ define("ghost/controllers/settings/tags", this._super(options); }, - saveActiveTag: function () { + isViewingSubview: Ember.computed('controllers.application.showSettingsMenu', function (key, value) { + // Not viewing a subview if we can't even see the PSM + if (!this.get('controllers.application.showSettingsMenu')) { + return false; + } + if (arguments.length > 1) { + return value; + } + + return false; + }), + + showErrors: function (errors) { + errors = Ember.isArray(errors) ? errors : [errors]; + this.notifications.showErrors(errors); + }, + + saveActiveTagProperty: function (propKey, newValue) { var activeTag = this.get('activeTag'), - name = activeTag.get('name'), + currentValue = activeTag.get(propKey), self = this; - activeTag.save().then(function () { - self.notifications.showSuccess('Saved ' + name); - }).catch(function (error) { - self.notifications.showAPIError(error); + newValue = newValue.trim(); + + // Quit if there was no change + if (newValue === currentValue) { + return; + } + + activeTag.set(propKey, newValue); + + this.notifications.closePassive(); + + activeTag.save().catch(function (errors) { + self.showErrors(errors); }); }, + seoTitle: Ember.computed('scratch', 'activeTagNameScratch', 'activeTagMetaTitleScratch', function () { + var metaTitle = this.get('activeTagMetaTitleScratch') || ''; + + metaTitle = metaTitle.length > 0 ? metaTitle : this.get('activeTagNameScratch'); + + if (metaTitle && metaTitle.length > 70) { + metaTitle = metaTitle.substring(0, 70).trim(); + metaTitle = Ember.Handlebars.Utils.escapeExpression(metaTitle); + metaTitle = new Ember.Handlebars.SafeString(metaTitle + '…'); + } + + return metaTitle; + }), + + seoURL: Ember.computed('activeTagSlugScratch', function () { + var blogUrl = this.get('config').blogUrl, + seoSlug = this.get('activeTagSlugScratch') ? this.get('activeTagSlugScratch') : '', + seoURL = blogUrl + '/tag/' + seoSlug; + + // only append a slash to the URL if the slug exists + if (seoSlug) { + seoURL += '/'; + } + + if (seoURL.length > 70) { + seoURL = seoURL.substring(0, 70).trim(); + seoURL = new Ember.Handlebars.SafeString(seoURL + '…'); + } + + return seoURL; + }), + + seoDescription: Ember.computed('scratch', 'activeTagDescriptionScratch', 'activeTagMetaDescriptionScratch', function () { + var metaDescription = this.get('activeTagMetaDescriptionScratch') || ''; + + metaDescription = metaDescription.length > 0 ? metaDescription : this.get('activeTagDescriptionScratch'); + + if (metaDescription && metaDescription.length > 156) { + metaDescription = metaDescription.substring(0, 156).trim(); + metaDescription = Ember.Handlebars.Utils.escapeExpression(metaDescription); + metaDescription = new Ember.Handlebars.SafeString(metaDescription + '…'); + } + + return metaDescription; + }), + actions: { newTag: function () { this.set('activeTag', this.store.createRecord('tag')); @@ -3325,47 +3429,39 @@ define("ghost/controllers/settings/tags", }, saveActiveTagName: function (name) { - var activeTag = this.get('activeTag'), - currentName = activeTag.get('name'); + this.saveActiveTagProperty('name', name); + }, - name = name.trim(); - if (!name || name === currentName) { - return; - } + saveActiveTagSlug: function (slug) { + this.saveActiveTagProperty('slug', slug); + }, - // setting all of the properties as they are not saved until name is present - activeTag.setProperties({ - name: name, - slug: this.get('activeTagSlugScratch').trim(), - description: this.get('activeTagDescriptionScratch').trim() - }); - this.saveActiveTag(); + saveActiveTagDescription: function (description) { + this.saveActiveTagProperty('description', description); }, - saveActiveTagSlug: function (slug) { - var name = this.get('activeTag.name'), - currentSlug = this.get('activeTag.slug') || ''; + saveActiveTagMetaTitle: function (metaTitle) { + this.saveActiveTagProperty('meta_title', metaTitle); + }, - slug = slug.trim(); - if (!name || !slug || slug === currentSlug) { - return; - } + saveActiveTagMetaDescription: function (metaDescription) { + this.saveActiveTagProperty('meta_description', metaDescription); + }, - this.set('activeTag.slug', slug); - this.saveActiveTag(); + showSubview: function () { + this.set('isViewingSubview', true); }, - saveActiveTagDescription: function (description) { - var name = this.get('activeTag.name'), - currentDescription = this.get('activeTag.description') || ''; + closeSubview: function () { + this.set('isViewingSubview', false); + }, - description = description.trim(); - if (!name || description === currentDescription) { - return; - } + setCoverImage: function (image) { + this.saveActiveTagProperty('image', image); + }, - this.set('activeTag.description', description); - this.saveActiveTag(); + clearCoverImage: function () { + this.saveActiveTagProperty('image', ''); } } }); @@ -4069,8 +4165,15 @@ define("ghost/initializers/authentication", window.ENV['simple-auth'] = { authenticationRoute: 'signin', - routeAfterAuthentication: 'content', - authorizer: 'simple-auth-authorizer:oauth2-bearer' + routeAfterAuthentication: 'posts', + authorizer: 'simple-auth-authorizer:oauth2-bearer', + localStorageKey: 'ghost' + (Ghost.subdir.indexOf('/') === 0 ? '-' + Ghost.subdir.substr(1) : '') + ':session' + }; + + window.ENV['simple-auth-oauth2'] = { + serverTokenEndpoint: Ghost.apiRoot + '/authentication/token', + serverTokenRevocationEndpoint: Ghost.apiRoot + '/authentication/revoke', + refreshAccessTokens: true }; SimpleAuth.Session.reopen({ @@ -4080,18 +4183,11 @@ define("ghost/initializers/authentication", }); SimpleAuth.Authenticators.OAuth2.reopen({ - serverTokenEndpoint: Ghost.apiRoot + '/authentication/token', - serverTokenRevocationEndpoint: Ghost.apiRoot + '/authentication/revoke', - refreshAccessTokens: true, makeRequest: function (url, data) { data.client_id = 'ghost-admin'; return this._super(url, data); } }); - - SimpleAuth.Stores.LocalStorage.reopen({ - key: 'ghost' + (Ghost.subdir.indexOf('/') === 0 ? '-' + Ghost.subdir.substr(1) : '') + ':session' - }); } }; @@ -4526,8 +4622,12 @@ define("ghost/mixins/editor-base-controller", }, showSaveNotification: function (prevStatus, status, delay) { - var message = this.messageMap.success.post[prevStatus][status]; + var message = this.messageMap.success.post[prevStatus][status], + path = this.get('ghostPaths.url').join(this.get('config.blogUrl'), this.get('url')); + if (status === 'published') { + message += ' View Post'; + } this.notifications.showSuccess(message, {delayed: delay}); }, @@ -4577,7 +4677,7 @@ define("ghost/mixins/editor-base-controller", this.set('status', status); // Set a default title - if (!this.get('titleScratch')) { + if (!this.get('titleScratch').trim()) { this.set('titleScratch', '(Untitled)'); } @@ -5559,11 +5659,6 @@ define("ghost/mixins/shortcuts-route", activate: function () { this._super(); - - if (!this.shortcuts) { - return; - } - this.registerShortcuts(); }, @@ -5640,8 +5735,8 @@ define("ghost/mixins/text-input", __exports__["default"] = BlurField; }); define("ghost/mixins/validation-engine", - ["ghost/utils/ajax","ghost/utils/validator-extensions","ghost/validators/post","ghost/validators/setup","ghost/validators/signup","ghost/validators/signin","ghost/validators/forgotten","ghost/validators/setting","ghost/validators/reset","ghost/validators/user","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + ["ghost/utils/ajax","ghost/utils/validator-extensions","ghost/validators/post","ghost/validators/setup","ghost/validators/signup","ghost/validators/signin","ghost/validators/forgotten","ghost/validators/setting","ghost/validators/reset","ghost/validators/user","ghost/validators/tag-settings","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { "use strict"; var getRequestErrorMessage = __dependency1__.getRequestErrorMessage; @@ -5654,6 +5749,7 @@ define("ghost/mixins/validation-engine", var SettingValidator = __dependency8__["default"]; var ResetValidator = __dependency9__["default"]; var UserValidator = __dependency10__["default"]; + var TagSettingsValidator = __dependency11__["default"]; // our extensions to the validator library ValidatorExtensions.init(); @@ -5716,7 +5812,8 @@ define("ghost/mixins/validation-engine", forgotten: ForgotValidator, setting: SettingValidator, reset: ResetValidator, - user: UserValidator + user: UserValidator, + tag: TagSettingsValidator }, /** @@ -5846,6 +5943,7 @@ define("ghost/models/post", published_at: DS.attr('moment-date'), published_by: DS.belongsTo('user', {async: true}), tags: DS.hasMany('tag', {embedded: 'always'}), + url: DS.attr('string'), // Computed post properties @@ -5950,19 +6048,23 @@ define("ghost/models/slug-generator", __exports__["default"] = SlugGenerator; }); define("ghost/models/tag", - ["ghost/mixins/nprogress-save","exports"], - function(__dependency1__, __exports__) { + ["ghost/mixins/validation-engine","ghost/mixins/nprogress-save","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var NProgressSaveMixin = __dependency1__["default"]; + var ValidationEngine = __dependency1__["default"]; + var NProgressSaveMixin = __dependency2__["default"]; + + var Tag = DS.Model.extend(NProgressSaveMixin, ValidationEngine, { + validationType: 'tag', - var Tag = DS.Model.extend(NProgressSaveMixin, { uuid: DS.attr('string'), name: DS.attr('string'), slug: DS.attr('string'), description: DS.attr('string'), parent_id: DS.attr('number'), meta_title: DS.attr('string'), - meta_description: DS.attr('string') + meta_description: DS.attr('string'), + image: DS.attr('string') }); __exports__["default"] = Tag; @@ -6025,6 +6127,7 @@ define("ghost/models/user", type: 'PUT', data: { password: [{ + user_id: this.get('id'), oldPassword: this.get('password'), newPassword: this.get('newPassword'), ne2Password: this.get('ne2Password') @@ -6137,13 +6240,22 @@ define("ghost/router", __exports__["default"] = Router; }); define("ghost/routes/application", - ["ghost/mixins/shortcuts-route","exports"], - function(__dependency1__, __exports__) { + ["ghost/mixins/shortcuts-route","ghost/utils/ctrl-or-cmd","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; /* global key */ var ShortcutsRoute = __dependency1__["default"]; + var ctrlOrCmd = __dependency2__["default"]; - var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, ShortcutsRoute, { + var ApplicationRoute, + shortcuts = {}; + + shortcuts.esc = {action: 'closePopups', scope: 'all'}; + shortcuts.enter = {action: 'confirmModal', scope: 'modal'}; + shortcuts[ctrlOrCmd + '+s'] = {action: 'save', scope: 'all'}; + + ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, ShortcutsRoute, { + shortcuts: shortcuts, afterModel: function (model, transition) { if (this.get('session').isAuthenticated) { @@ -6151,32 +6263,11 @@ define("ghost/routes/application", } }, - shortcuts: { - esc: {action: 'closePopups', scope: 'all'}, - enter: {action: 'confirmModal', scope: 'modal'} - }, - title: function (tokens) { return tokens.join(' - ') + ' - ' + this.get('config.blogTitle'); }, actions: { - authorizationFailed: function () { - var currentRoute = this.get('controller').get('currentRouteName'), - editorController; - - if (currentRoute.split('.')[0] === 'editor') { - editorController = this.controllerFor(currentRoute); - - if (editorController.get('isDirty')) { - this.send('openModal', 'auth-failed-unsaved', editorController); - return; - } - } - - this._super(); - }, - toggleGlobalMobileNav: function () { this.toggleProperty('controller.showGlobalMobileNav'); }, @@ -6184,9 +6275,11 @@ define("ghost/routes/application", openSettingsMenu: function () { this.set('controller.showSettingsMenu', true); }, + closeSettingsMenu: function () { this.set('controller.showSettingsMenu', false); }, + toggleSettingsMenu: function () { this.toggleProperty('controller.showSettingsMenu'); }, @@ -6215,7 +6308,13 @@ define("ghost/routes/application", }, sessionAuthenticationSucceeded: function () { - var self = this; + var appController = this.controllerFor('application'), + self = this; + + if (appController && appController.get('skipAuthSuccessHandler')) { + return; + } + this.store.find('user', 'me').then(function (user) { self.send('signedIn', user); var attemptedTransition = self.get('session').get('attemptedTransition'); @@ -6297,7 +6396,10 @@ define("ghost/routes/application", errorObj.el.addClass('input-error'); } }); - } + }, + + // noop default for unhandled save (used from shortcuts) + save: Ember.K } }); @@ -6389,6 +6491,12 @@ define("ghost/routes/editor/edit", return self.replaceWith('posts.index'); } }); + }, + + actions: { + authorizationFailed: function () { + this.send('openModal', 'signin'); + } } }); @@ -6870,22 +6978,15 @@ define("ghost/routes/settings/apps", __exports__["default"] = AppsRoute; }); define("ghost/routes/settings/code-injection", - ["ghost/routes/authenticated","ghost/mixins/loading-indicator","ghost/mixins/current-user-settings","ghost/mixins/style-body","ghost/mixins/shortcuts-route","ghost/utils/ctrl-or-cmd","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + ["ghost/routes/authenticated","ghost/mixins/loading-indicator","ghost/mixins/current-user-settings","ghost/mixins/style-body","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var AuthenticatedRoute = __dependency1__["default"]; var loadingIndicator = __dependency2__["default"]; var CurrentUserSettings = __dependency3__["default"]; var styleBody = __dependency4__["default"]; - var ShortcutsRoute = __dependency5__["default"]; - var ctrlOrCmd = __dependency6__["default"]; - - var shortcuts = {}, - SettingsCodeInjectionRoute; - shortcuts[ctrlOrCmd + '+s'] = {action: 'save'}; - - SettingsCodeInjectionRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, ShortcutsRoute, { + var SettingsCodeInjectionRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, { classNames: ['settings-view-code'], beforeModel: function () { @@ -6900,8 +7001,6 @@ define("ghost/routes/settings/code-injection", }); }, - shortcuts: shortcuts, - actions: { save: function () { this.get('controller').send('save'); @@ -6912,22 +7011,15 @@ define("ghost/routes/settings/code-injection", __exports__["default"] = SettingsCodeInjectionRoute; }); define("ghost/routes/settings/general", - ["ghost/routes/authenticated","ghost/mixins/loading-indicator","ghost/mixins/current-user-settings","ghost/mixins/style-body","ghost/mixins/shortcuts-route","ghost/utils/ctrl-or-cmd","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + ["ghost/routes/authenticated","ghost/mixins/loading-indicator","ghost/mixins/current-user-settings","ghost/mixins/style-body","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var AuthenticatedRoute = __dependency1__["default"]; var loadingIndicator = __dependency2__["default"]; var CurrentUserSettings = __dependency3__["default"]; var styleBody = __dependency4__["default"]; - var ShortcutsRoute = __dependency5__["default"]; - var ctrlOrCmd = __dependency6__["default"]; - - var shortcuts = {}, - SettingsGeneralRoute; - shortcuts[ctrlOrCmd + '+s'] = {action: 'save'}; - - SettingsGeneralRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, ShortcutsRoute, { + var SettingsGeneralRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, { titleToken: 'General', classNames: ['settings-view-general'], @@ -6944,8 +7036,6 @@ define("ghost/routes/settings/general", }); }, - shortcuts: shortcuts, - actions: { save: function () { this.get('controller').send('save'); @@ -7137,20 +7227,13 @@ define("ghost/routes/settings/users/index", __exports__["default"] = UsersIndexRoute; }); define("ghost/routes/settings/users/user", - ["ghost/routes/authenticated","ghost/mixins/style-body","ghost/mixins/shortcuts-route","ghost/utils/ctrl-or-cmd","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + ["ghost/routes/authenticated","ghost/mixins/style-body","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; var AuthenticatedRoute = __dependency1__["default"]; var styleBody = __dependency2__["default"]; - var ShortcutsRoute = __dependency3__["default"]; - var ctrlOrCmd = __dependency4__["default"]; - - var shortcuts = {}, - SettingsUserRoute; - shortcuts[ctrlOrCmd + '+s'] = {action: 'save'}; - - SettingsUserRoute = AuthenticatedRoute.extend(styleBody, ShortcutsRoute, { + var SettingsUserRoute = AuthenticatedRoute.extend(styleBody, { titleToken: 'User', classNames: ['settings-view-user'], @@ -7197,8 +7280,6 @@ define("ghost/routes/settings/users/user", this._super(); }, - shortcuts: shortcuts, - actions: { save: function () { this.get('controller').send('save'); @@ -7324,7 +7405,7 @@ define("ghost/routes/signup", tokenText, email, model = {}, - re = /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/; + re = /^(?:[A-Za-z0-9_\-]{4})*(?:[A-Za-z0-9_\-]{2}|[A-Za-z0-9_\-]{3})?$/; return new Ember.RSVP.Promise(function (resolve) { if (!re.test(params.token)) { @@ -7451,10 +7532,14 @@ define("ghost/serializers/post", var root = Ember.String.pluralize(type.typeKey), data = this.serialize(record, options); - // Don't ever pass uuid's + // Properties that exist on the model but we don't want sent in the payload + delete data.uuid; - // Don't send HTML delete data.html; + // Inserted locally as a convenience. + delete data.author_id; + // Read-only virtual property. + delete data.url; hash[root] = [data]; } @@ -8094,7 +8179,6 @@ define("ghost/utils/editor-shortcuts", var shortcuts = {}; // General editor shortcuts - shortcuts[ctrlOrCmd + '+s'] = 'save'; shortcuts[ctrlOrCmd + '+alt+p'] = 'publish'; shortcuts['alt+shift+z'] = 'toggleZenMode'; @@ -8128,14 +8212,20 @@ define("ghost/utils/ghost-paths", function(__exports__) { "use strict"; var makeRoute = function (root, args) { - var parts = Array.prototype.slice.call(args, 0).join('/'), - route = [root, parts].join('/'); - - if (route.slice(-1) !== '/') { - route += '/'; - } - - return route; + var slashAtStart, + slashAtEnd, + parts, + route; + + slashAtStart = /^\//; + slashAtEnd = /\/$/; + route = root.replace(slashAtEnd, ''); + parts = Array.prototype.slice.call(args, 0); + + parts.forEach(function (part) { + route = [route, part.replace(slashAtStart, '').replace(slashAtEnd, '')].join('/'); + }); + return route += '/'; }; function ghostPaths() { @@ -8163,6 +8253,16 @@ define("ghost/utils/ghost-paths", return makeRoute(apiRoot, arguments); }, + join: function () { + if (arguments.length > 1) { + return makeRoute(arguments[0], Array.prototype.slice.call(arguments, 1)); + } else if (arguments.length === 1) { + var arg = arguments[0]; + return arg.slice(-1) === '/' ? arg : arg + '/'; + } + return '/'; + }, + asset: assetUrl } }; @@ -8677,6 +8777,39 @@ define("ghost/validators/signup", __exports__["default"] = NewUserValidator.create(); }); +define("ghost/validators/tag-settings", + ["exports"], + function(__exports__) { + "use strict"; + var TagSettingsValidator = Ember.Object.create({ + check: function (model) { + var validationErrors = [], + data = model.getProperties('name', 'meta_title', 'meta_description'); + + if (validator.empty(data.name)) { + validationErrors.push({ + message: 'You must specify a name for the tag.' + }); + } + + if (!validator.isLength(data.meta_title, 0, 150)) { + validationErrors.push({ + message: 'Meta Title cannot be longer than 150 characters.' + }); + } + + if (!validator.isLength(data.meta_description, 0, 200)) { + validationErrors.push({ + message: 'Meta Description cannot be longer than 200 characters.' + }); + } + + return validationErrors; + } + }); + + __exports__["default"] = TagSettingsValidator; + }); define("ghost/validators/user", ["exports"], function(__exports__) { @@ -9029,8 +9162,40 @@ define("ghost/views/post-item-view", click: function () { this.get('controller').send('showPostContent'); - } - + }, + scrollIntoView: function () { + if (!this.get('active')) { + return; + } + var element = this.$(), + offset = element.offset().top, + elementHeight = element.height(), + container = Ember.$('.js-content-scrollbox'), + containerHeight = container.height(), + currentScroll = container.scrollTop(), + isBelowTop, + isAboveBottom, + isOnScreen; + + isAboveBottom = offset < containerHeight; + isBelowTop = offset > elementHeight; + + isOnScreen = isBelowTop && isAboveBottom; + + if (!isOnScreen) { + // Scroll so that element is centered in container + // 40 is the amount of padding on the container + container.clearQueue().animate({ + scrollTop: currentScroll + offset - 40 - containerHeight / 2 + }); + } + }, + removeScrollBehaviour: function () { + this.removeObserver('active', this, this.scrollIntoView); + }.on('willDestroyElement'), + addScrollBehaviour: function () { + this.addObserver('active', this, this.scrollIntoView); + }.on('didInsertElement') }); __exports__["default"] = PostItemView; @@ -9075,8 +9240,7 @@ define("ghost/views/post-tags-input", ESCAPE: 27, UP: 38, DOWN: 40, - NUMPAD_ENTER: 108, - COMMA: 188 + NUMPAD_ENTER: 108 }, didInsertElement: function () { @@ -9112,6 +9276,23 @@ define("ghost/views/post-tags-input", this.get('parentView').set('hasFocus', false); }, + keyPress: function (event) { + // listen to keypress event to handle comma key on international keyboard + var controller = this.get('parentView.controller'), + isComma = ','.localeCompare(String.fromCharCode(event.keyCode || event.charCode)) === 0; + + // use localeCompare in case of international keyboard layout + if (isComma) { + event.preventDefault(); + + if (controller.get('selectedSuggestion')) { + controller.send('addSelectedSuggestion'); + } else { + controller.send('addNewTag'); + } + } + }, + keyDown: function (event) { var controller = this.get('parentView.controller'), keys = this.get('parentView.keys'), @@ -9131,11 +9312,6 @@ define("ghost/views/post-tags-input", case keys.TAB: case keys.ENTER: case keys.NUMPAD_ENTER: - case keys.COMMA: - if (event.keyCode === keys.COMMA && event.shiftKey) { - break; - } - if (controller.get('selectedSuggestion')) { event.preventDefault(); controller.send('addSelectedSuggestion'); @@ -9365,6 +9541,21 @@ define("ghost/views/settings/tags/settings-menu", return this.get('controller.model.isNew') ? 'Add Tag' : 'Save Tag'; + }), + + // This observer loads and resets the uploader whenever the active tag changes, + // ensuring that we can reuse the whole settings menu. + updateUploader: Ember.observer('controller.activeTag.image', 'controller.uploaderReference', function () { + var uploader = this.get('controller.uploaderReference'), + image = this.get('controller.activeTag.image'); + + if (uploader && uploader[0]) { + if (image) { + uploader[0].uploaderUi.initWithImage(); + } else { + uploader[0].uploaderUi.initWithDropzone(); + } + } }) }); diff --git a/core/built/scripts/ghost-tests.js b/core/built/scripts/ghost-tests.js index 23625b19d..2689f2821 100644 --- a/core/built/scripts/ghost-tests.js +++ b/core/built/scripts/ghost-tests.js @@ -42,4 +42,69 @@ define("ghost/tests/unit/components/gh-trim-focus-input_test", }); }); }); +define("ghost/tests/unit/utils/ghost-paths_test", + ["ghost/utils/ghost-paths"], + function(__dependency1__) { + "use strict"; + /* jshint expr:true */ + + var ghostPaths = __dependency1__["default"]; + + describe('ghost-paths', function () { + describe('join', function () { + var join = ghostPaths().url.join; + + it('should join two or more paths, normalizing slashes', function () { + var path; + + path = join('/one/', '/two/'); + expect(path).to.equal('/one/two/'); + + path = join('/one', '/two/'); + expect(path).to.equal('/one/two/'); + + path = join('/one/', 'two/'); + expect(path).to.equal('/one/two/'); + + path = join('/one/', 'two/', '/three/'); + expect(path).to.equal('/one/two/three/'); + + path = join('/one/', 'two', 'three/'); + expect(path).to.equal('/one/two/three/'); + }); + + it('should not change the slash at the beginning', function () { + var path; + + path = join('one/'); + expect(path).to.equal('one/'); + path = join('one/', 'two'); + expect(path).to.equal('one/two/'); + path = join('/one/', 'two'); + expect(path).to.equal('/one/two/'); + path = join('one/', 'two', 'three'); + expect(path).to.equal('one/two/three/'); + path = join('/one/', 'two', 'three'); + expect(path).to.equal('/one/two/three/'); + }); + + it('should always return a slash at the end', function () { + var path; + + path = join(); + expect(path).to.equal('/'); + path = join(''); + expect(path).to.equal('/'); + path = join('one'); + expect(path).to.equal('one/'); + path = join('one/'); + expect(path).to.equal('one/'); + path = join('one', 'two'); + expect(path).to.equal('one/two/'); + path = join('one', 'two/'); + expect(path).to.equal('one/two/'); + }); + }); + }); + }); //# sourceMappingURL=ghost-tests.js.map \ No newline at end of file diff --git a/core/built/scripts/ghost.min.js b/core/built/scripts/ghost.min.js index fe936be97..1ee8f28b7 100644 --- a/core/built/scripts/ghost.min.js +++ b/core/built/scripts/ghost.min.js @@ -1,9 +1,10 @@ -define("ghost/adapters/application",["ghost/utils/ghost-paths","exports"],function(a,b){"use strict";var c=a["default"],d=DS.RESTAdapter.extend({host:window.location.origin,namespace:c().apiRoot.slice(1),findQuery:function(a,b,c){var d;return c.id&&(d=c.id,delete c.id),this.ajax(this.buildURL(b.typeKey,d),"GET",{data:c})},buildURL:function(a,b){var c=this._super(a,b);return"/"!==c.slice(-1)&&(c+="/"),c},deleteRecord:function(){var a=this._super.apply(this,arguments);return a.then(function(){return null})}});b["default"]=d}),define("ghost/adapters/embedded-relation-adapter",["ghost/adapters/application","exports"],function(a,b){"use strict";var c=a["default"],d=c.extend({find:function(a,b,c){return this.findQuery(a,b,this.buildQuery(a,b,c))},findQuery:function(a,b,c){return this._super(a,b,this.buildQuery(a,b,c))},findAll:function(a,b,c){return this.findQuery(a,b,this.buildQuery(a,b,c))},buildQuery:function(a,b,c){var d,e=[],f={},g={};return d=a.modelFor(b),d.eachRelationship(function(a,b){"hasMany"===b.kind&&Object.prototype.hasOwnProperty.call(b.options,"embedded")&&"always"===b.options.embedded&&e.push(a)}),e.length&&("string"==typeof c||"number"==typeof c?(f.id=c,f.include=e.join(",")):("object"==typeof c||Ember.isNone(c))&&(f=c||f,e=e.concat(f.include?f.include.split(","):[]),e.forEach(function(a){g[a]=!0}),f.include=Object.keys(g).join(","))),f}});b["default"]=d}),define("ghost/adapters/post",["ghost/adapters/embedded-relation-adapter","exports"],function(a,b){"use strict";var c=a["default"],d=c.extend({createRecord:function(a,b,c){var d={},e=a.serializerFor(b.typeKey),f=this.buildURL(b.typeKey);return f+="?include=tags",e.serializeIntoHash(d,b,c),this.ajax(f,"POST",{data:d})},updateRecord:function(a,b,c){var d={},e=a.serializerFor(b.typeKey),f=Ember.get(c,"id"),g=this.buildURL(b.typeKey,f);return g+="?include=tags",e.serializeIntoHash(d,b,c),this.ajax(g,"PUT",{data:d})}});b["default"]=d}),define("ghost/adapters/setting",["ghost/adapters/application","exports"],function(a,b){"use strict";var c=a["default"],d=c.extend({updateRecord:function(a,b,c){var d={},e=a.serializerFor(b.typeKey);return delete c.id,e.serializeIntoHash(d,b,c),this.ajax(this.buildURL(b.typeKey),"PUT",{data:d})}});b["default"]=d}),define("ghost/adapters/user",["ghost/adapters/embedded-relation-adapter","exports"],function(a,b){"use strict";var c=a["default"],d=c.extend({createRecord:function(a,b,c){var d={},e=a.serializerFor(b.typeKey),f=this.buildURL(b.typeKey);return f+="?include=roles",e.serializeIntoHash(d,b,c),this.ajax(f,"POST",{data:d})},updateRecord:function(a,b,c){var d={},e=a.serializerFor(b.typeKey),f=Ember.get(c,"id"),g=this.buildURL(b.typeKey,f);return g+="?include=roles",e.serializeIntoHash(d,b,c),this.ajax(g,"PUT",{data:d})},find:function(a,b,c){var d=this.buildQuery(a,b,c);return d.status="all",this.findQuery(a,b,d)}});b["default"]=d}),define("ghost/app",["ember/resolver","ember/load-initializers","ghost/utils/link-view","ghost/utils/text-field","ghost/config","ghost/helpers/ghost-paths","exports"],function(a,b,c,d,e,f,g){"use strict";var h=a["default"],i=b["default"],j=e["default"],k=f["default"];Ember.MODEL_FACTORY_INJECTIONS=!0;var l=Ember.Application.extend({modulePrefix:"ghost",Resolver:h["default"]});j(l),i(l,"ghost"),Ember.Handlebars.registerHelper("gh-path",k),g["default"]=l}),define("ghost/assets/lib/touch-editor",["exports"],function(a){"use strict";var b=function(){var a,b=function(){};return a=function(a){this.textarea=a,this.win={document:this.textarea},this.ready=!0,this.wrapping=document.createElement("div");var b=this.textarea.parentNode;this.wrapping.appendChild(this.textarea),b.appendChild(this.wrapping),this.textarea.style.opacity=1},a.prototype={setOption:function(a,b){"onChange"===a&&$(this.textarea).change(b)},eachLine:function(){return[]},getValue:function(){return this.textarea.value},setValue:function(a){this.textarea.value=a},focus:b,getCursor:function(){return{line:0,ch:0}},setCursor:b,currentLine:function(){return 0},cursorPosition:function(){return{character:0}},addMarkdown:b,nthLine:b,refresh:b,selectLines:b,on:b,off:b},a};a["default"]=b}),define("ghost/assets/lib/uploader",["ghost/utils/ghost-paths","exports"],function(a,b){"use strict";var c,d,e=a["default"],f=e();c=function(a,b){var c='
',d='',e=$("
",{"class":"js-upload-progress progress progress-success active",role:"progressbar","aria-valuemin":"0","aria-valuemax":"100"}).append($("
",{"class":"js-upload-progress-bar bar",style:"width:0%"}));$.extend(this,{complete:function(c){function d(b,c){a.find("img.js-upload-target").attr({width:b,height:c}).css({display:"block"}),a.find(".fileupload-loading").remove(),a.css({height:"auto"}),a.delay(250).animate({opacity:100},1e3,function(){$(".js-button-accept").prop("disabled",!1),i.init()})}function g(b){a.animate({opacity:0},250,function(){a.removeClass("image-uploader").addClass("pre-image-uploader"),a.css({minHeight:0}),i.removeExtras(),a.animate({height:b.height()},250,function(){d(b.width(),b.height())})})}function h(){var d=a.find("img.js-upload-target").attr({src:"",width:"auto",height:"auto"});e.animate({opacity:0},250,function(){a.find("span.media").after(''),b.editor||e.find(".fileupload-loading").css({top:"56px"})}),a.trigger("uploadsuccess",[c]),d.one("load",function(){g(d)}).attr("src",c)}var i=this;h()},bindFileUpload:function(){var c=this;a.find(".js-fileupload").fileupload().fileupload("option",{url:f.apiRoot+"/uploads/",add:function(c,d){$(".js-button-accept").prop("disabled",!0),a.find(".js-fileupload").removeClass("right"),a.find(".js-url").remove(),e.find(".js-upload-progress-bar").removeClass("fail"),a.trigger("uploadstart",[a.attr("id")]),a.find("span.media, div.description, a.image-url, a.image-webcam").animate({opacity:0},250,function(){a.find("div.description").hide().css({opacity:100}),b.progressbar&&(a.find("div.js-fail").after(e),e.animate({opacity:100},250)),d.submit()})},dropZone:b.fileStorage?a:null,progressall:function(c,d){var f=parseInt(d.loaded/d.total*100,10);b.editor||e.find("div.js-progress").css({position:"absolute",top:"40px"}),b.progressbar&&(a.trigger("uploadprogress",[f,d]),e.find(".js-upload-progress-bar").css("width",f+"%"))},fail:function(b,d){$(".js-button-accept").prop("disabled",!1),a.trigger("uploadfailure",[d.result]),a.find(".js-upload-progress-bar").addClass("fail"),a.find("div.js-fail").text(413===d.jqXHR.status?"The image you uploaded was larger than the maximum file size your server allows.":415===d.jqXHR.status?"The image type you uploaded is not supported. Please use .PNG, .JPG, .GIF, .SVG.":"Something went wrong :("),a.find("div.js-fail, button.js-fail").fadeIn(1500),a.find("button.js-fail").on("click",function(){a.css({minHeight:0}),a.find("div.description").show(),c.removeExtras(),c.init()})},done:function(a,b){c.complete(b.result)}})},buildExtras:function(){a.find("span.media")[0]||a.prepend(''),a.find("div.description")[0]||a.append('
Add image
'),a.find("div.js-fail")[0]||a.append(''),a.find("button.js-fail")[0]||a.append(''),a.find("a.image-url")[0]||a.append('')},removeExtras:function(){a.find("span.media, div.js-upload-progress, a.image-url, a.image-upload, a.image-webcam, div.js-fail, button.js-fail, a.js-cancel").remove()},initWithDropzone:function(){var c=this;return a.find("img.js-upload-target").css({display:"none"}),a.removeClass("pre-image-uploader image-uploader-url").addClass("image-uploader"),this.removeExtras(),this.buildExtras(),this.bindFileUpload(),b.fileStorage?void a.find("a.image-url").on("click",function(){c.initUrl()}):void c.initUrl()},initUrl:function(){var e,f=this;this.removeExtras(),a.addClass("image-uploader-url").removeClass("pre-image-uploader"),a.find(".js-fileupload").addClass("right"),b.fileStorage&&a.append(d),a.find(".js-cancel").on("click",function(){a.find(".js-url").remove(),a.find(".js-fileupload").removeClass("right"),f.removeExtras(),f.initWithDropzone()}),a.find("div.description").before(c),b.editor&&a.find("div.js-url").append(''),a.find(".js-button-accept").on("click",function(){e=a.find(".js-upload-url").val(),a.find("div.description").hide(),a.find(".js-fileupload").removeClass("right"),a.find(".js-url").remove(),""===e?(a.trigger("uploadsuccess","http://"),f.initWithDropzone()):f.complete(e)}),b.fileStorage!==!1&&a.append(''),a.find("a.image-upload").on("click",function(){a.find(".js-url").remove(),a.find(".js-fileupload").removeClass("right"),f.initWithDropzone()})},initWithImage:function(){var b=this;a.removeClass("image-uploader image-uploader-url").addClass("pre-image-uploader"),a.find("div.description").hide(),a.append(d),a.find(".js-cancel").on("click",function(){a.find("img.js-upload-target").attr({src:""}),a.find("div.description").show(),a.delay(2500).animate({opacity:100},1e3,function(){b.init()}),a.trigger("uploadsuccess","http://"),b.initWithDropzone()})},init:function(){var b=a.find("img.js-upload-target");b[0]||a.prepend(''),$(".js-button-accept").prop("disabled",!1),""===b.attr("src")||void 0===b.attr("src")?this.initWithDropzone():this.initWithImage()},reset:function(){a.find(".js-url").remove(),a.find(".js-fileupload").removeClass("right"),this.removeExtras(),this.initWithDropzone()}})},d=function(a){var b=$.extend({progressbar:!0,editor:!1,fileStorage:!0},a);return this.each(function(){var a,d=$(this);a=new c(d,b),this.uploaderUi=a,a.init()})},b["default"]=d}),define("ghost/components/gh-activating-list-item",["exports"],function(a){"use strict";var b=Ember.Component.extend({tagName:"li",classNameBindings:["active"],active:!1});a["default"]=b}),define("ghost/components/gh-codemirror",["ghost/mixins/marker-manager","ghost/utils/codemirror-mobile","ghost/utils/set-scroll-classname","ghost/utils/codemirror-shortcuts","exports"],function(a,b,c,d,e){"use strict";var f,g,h,i=a["default"],j=b["default"],k=c["default"],l=d["default"];l.init(),f=function(a,b){var c,d=a.component;for(c=b.from.line;c-1&&this.$("option:eq("+c+")").prop("selected",!0)},change:function(){this._changeSelection()},_changeSelection:function(){var a=this._selectedValue();Ember.set(this,"value",a),this.sendAction("onChange",a)},_selectedValue:function(){var a=this.$("select")[0].selectedIndex;return this.get("options").objectAt(a)}});a["default"]=b}),define("ghost/components/gh-tab-pane",["exports"],function(a){"use strict";var b=Ember.Component.extend({classNameBindings:["active"],tabsManager:Ember.computed(function(){return this.nearestWithProperty("isTabsManager")}),tab:Ember.computed("tabsManager.tabs.[]","tabsManager.tabPanes.[]",function(){var a=this.get("tabsManager.tabPanes").indexOf(this),b=this.get("tabsManager.tabs");return b&&b.objectAt(a)}),active:Ember.computed.alias("tab.active"),registerWithTabs:function(){this.get("tabsManager").registerTabPane(this)}.on("didInsertElement"),unregisterWithTabs:function(){this.get("tabsManager").unregisterTabPane(this)}.on("willDestroyElement")});a["default"]=b}),define("ghost/components/gh-tab",["exports"],function(a){"use strict";var b=Ember.Component.extend({tabsManager:Ember.computed(function(){return this.nearestWithProperty("isTabsManager")}),active:Ember.computed("tabsManager.activeTab",function(){return this.get("tabsManager.activeTab")===this}),index:Ember.computed("tabsManager.tabs.@each",function(){return this.get("tabsManager.tabs").indexOf(this)}),click:function(){this.get("tabsManager").select(this)},registerWithTabs:function(){this.get("tabsManager").registerTab(this)}.on("didInsertElement"),unregisterWithTabs:function(){this.get("tabsManager").unregisterTab(this)}.on("willDestroyElement")});a["default"]=b}),define("ghost/components/gh-tabs-manager",["exports"],function(a){"use strict";var b=Ember.Component.extend({activeTab:null,tabs:[],tabPanes:[],select:function(a){this.set("activeTab",a),this.sendAction("selected")},isTabsManager:!0,registerTab:function(a){this.get("tabs").addObject(a)},unregisterTab:function(a){this.get("tabs").removeObject(a)},registerTabPane:function(a){this.get("tabPanes").addObject(a)},unregisterTabPane:function(a){this.get("tabPanes").removeObject(a)}});a["default"]=b}),define("ghost/components/gh-textarea",["ghost/mixins/text-input","exports"],function(a,b){"use strict";var c=a["default"],d=Ember.TextArea.extend(c);b["default"]=d}),define("ghost/components/gh-trim-focus-input",["exports"],function(a){"use strict";var b=Ember.TextField.extend({focus:!0,attributeBindings:["autofocus"],autofocus:Ember.computed(function(){return device.ios()?!1:"autofocus"}),setFocus:function(){this.focus&&!device.ios()&&this.$().val(this.$().val()).focus()}.on("didInsertElement"),focusOut:function(){var a=this.$().val();this.$().val(a.trim())}});a["default"]=b}),define("ghost/components/gh-upload-modal",["ghost/components/gh-modal-dialog","ghost/assets/lib/uploader","exports"],function(a,b,c){"use strict";var d=a["default"],e=b["default"],f=d.extend({layoutName:"components/gh-modal-dialog",didInsertElement:function(){this._super(),e.call(this.$(".js-drop-zone"),{fileStorage:this.get("config.fileStorage")})},confirm:{reject:{func:function(){return!0},buttonClass:"btn btn-default",text:"Cancel"},accept:{buttonClass:"btn btn-blue right",text:"Save",func:function(){var a="model."+this.get("imageType");return this.$(".js-upload-url").val()?this.set(a,this.$(".js-upload-url").val()):this.set(a,this.$(".js-upload-target").attr("src")),!0}}},actions:{closeModal:function(){this.sendAction()},confirm:function(a){var b=this.get("confirm."+a+".func");"function"==typeof b&&b.apply(this),this.sendAction(),this.sendAction("confirm"+a)}}});c["default"]=f}),define("ghost/components/gh-uploader",["ghost/assets/lib/uploader","exports"],function(a,b){"use strict";var c=a["default"],d=Ember.Component.extend({classNames:["image-uploader","js-post-image-upload"],setup:function(){var a=this.$(),b=this;this.set("uploaderReference",c.call(a,{editor:!0,fileStorage:this.get("config.fileStorage")})),a.on("uploadsuccess",function(a,c){c&&""!==c&&"http://"!==c&&b.sendAction("uploaded",c)}),a.find(".js-cancel").on("click",function(){b.sendAction("canceled")})}.on("didInsertElement"),removeListeners:function(){var a=this.$();a.off(),a.find(".js-cancel").off()}.on("willDestroyElement")});b["default"]=d}),define("ghost/config",["exports"],function(a){"use strict";function b(a){!a instanceof Ember.Application}a["default"]=b}),define("ghost/controllers/application",["exports"],function(a){"use strict";var b=Ember.Controller.extend({hideNav:Ember.computed.match("currentPath",/(error|signin|signup|setup|forgotten|reset)/),topNotificationCount:0,showGlobalMobileNav:!1,showSettingsMenu:!1,userImageAlt:Ember.computed("session.user.name",function(){var a=this.get("session.user.name");return a+"'s profile picture"}),actions:{topNotificationChange:function(a){this.set("topNotificationCount",a)}}});a["default"]=b}),define("ghost/controllers/editor/edit",["ghost/mixins/editor-base-controller","exports"],function(a,b){"use strict";var c=a["default"],d=Ember.ObjectController.extend(c);b["default"]=d}),define("ghost/controllers/editor/new",["ghost/mixins/editor-base-controller","exports"],function(a,b){"use strict";var c=a["default"],d=Ember.ObjectController.extend(c,{actions:{save:function(a){var b=this;return this._super(a).then(function(a){a.get("id")&&b.replaceRoute("editor.edit",a)})}}});b["default"]=d}),define("ghost/controllers/error",["exports"],function(a){"use strict";var b=Ember.Controller.extend({code:Ember.computed("content.status",function(){return this.get("content.status")>200?this.get("content.status"):500}),message:Ember.computed("content.statusText",function(){return 404===this.get("code")?"No Ghost Found":"error"!==this.get("content.statusText")?this.get("content.statusText"):"Internal Server Error"}),stack:!1});a["default"]=b}),define("ghost/controllers/forgotten",["ghost/utils/ajax","ghost/mixins/validation-engine","exports"],function(a,b,c){"use strict";var d=a["default"],e=b["default"],f=Ember.Controller.extend(e,{email:"",submitting:!1,validationType:"forgotten",actions:{submit:function(){var a=this,b=a.getProperties("email");this.toggleProperty("submitting"),this.validate({format:!1}).then(function(){d({url:a.get("ghostPaths.url").api("authentication","passwordreset"),type:"POST",data:{passwordreset:[{email:b.email}]}}).then(function(){a.toggleProperty("submitting"),a.notifications.showSuccess("Please check your email for instructions.",{delayed:!0}),a.set("email",""),a.transitionToRoute("signin")}).catch(function(b){a.toggleProperty("submitting"),a.notifications.showAPIError(b,{defaultErrorText:"There was a problem with the reset, please try again."})})}).catch(function(b){a.toggleProperty("submitting"),a.notifications.showErrors(b)})}}});c["default"]=f}),define("ghost/controllers/modals/auth-failed-unsaved",["exports"],function(a){"use strict";var b=Ember.Controller.extend({editorController:Ember.computed.alias("model"),actions:{confirmAccept:function(){var a=this.get("editorController");a&&a.get("model").rollback(),window.onbeforeunload=null,window.location=this.get("ghostPaths").adminRoot+"/signin/"},confirmReject:function(){}},confirm:{accept:{text:"Leave",buttonClass:"btn btn-red"},reject:{text:"Stay",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/copy-html",["exports"],function(a){"use strict";var b=Ember.Controller.extend({generatedHTML:Ember.computed.alias("model.generatedHTML")});a["default"]=b}),define("ghost/controllers/modals/delete-all",["exports"],function(a){"use strict";var b=Ember.Controller.extend({actions:{confirmAccept:function(){var a=this;ic.ajax.request(this.get("ghostPaths.url").api("db"),{type:"DELETE"}).then(function(){a.notifications.showSuccess("All content deleted from database.")}).catch(function(b){a.notifications.showErrors(b)})},confirmReject:function(){return!1}},confirm:{accept:{text:"Delete",buttonClass:"btn btn-red"},reject:{text:"Cancel",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/delete-post",["exports"],function(a){"use strict";var b=Ember.Controller.extend({actions:{confirmAccept:function(){var a=this,b=this.get("model");b.updateTags(),b.destroyRecord().then(function(){a.get("dropdown").closeDropdowns(),a.transitionToRoute("posts.index"),a.notifications.showSuccess("Your post has been deleted.",{delayed:!0})},function(){a.notifications.showError("Your post could not be deleted. Please try again.")})},confirmReject:function(){return!1}},confirm:{accept:{text:"Delete",buttonClass:"btn btn-red"},reject:{text:"Cancel",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/delete-user",["exports"],function(a){"use strict";var b=Ember.Controller.extend({actions:{confirmAccept:function(){var a=this,b=this.get("model");b.destroyRecord().then(function(){a.store.unloadAll("post"),a.transitionToRoute("settings.users"),a.notifications.showSuccess("The user has been deleted.",{delayed:!0})},function(){a.notifications.showError("The user could not be deleted. Please try again.")})},confirmReject:function(){return!1}},confirm:{accept:{text:"Delete User",buttonClass:"btn btn-red"},reject:{text:"Cancel",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/invite-new-user",["exports"],function(a){"use strict";var b=Ember.Controller.extend({authorRole:Ember.computed(function(){var a=this;return this.store.find("role").then(function(b){var c=b.findBy("name","Author");return a.set("role",c),a.set("authorRole",c),c})}),confirm:{accept:{text:"send invitation now"},reject:{buttonClass:"hidden"}},actions:{setRole:function(a){this.set("role",a)},confirmAccept:function(){var a,b=this.get("email"),c=this.get("role"),d=this;d.set("email",""),d.set("role",d.get("authorRole")),d.send("closeModal"),this.store.find("user").then(function(e){var f=e.findBy("email",b);f?d.notifications.showWarn("invited"===f.get("status")||"invited-pending"===f.get("status")?"A user with that email address was already invited.":"A user with that email address already exists."):(a=d.store.createRecord("user",{email:b,status:"invited",role:c}),a.save().then(function(){var c="Invitation sent! ("+b+")";"invited-pending"===a.get("status")?d.notifications.showWarn("Invitation email was not sent. Please try resending."):d.notifications.showSuccess(c)}).catch(function(b){a.deleteRecord(),d.notifications.showErrors(b)}))})},confirmReject:function(){return!1}}});a["default"]=b}),define("ghost/controllers/modals/leave-editor",["exports"],function(a){"use strict";var b=Ember.Controller.extend({args:Ember.computed.alias("model"),actions:{confirmAccept:function(){var a,b,c,d=this.get("args");return Ember.isArray(d)&&(a=d[0],c=d[1],b=a.get("model")),c&&a?(b.updateTags(),b.get("isNew")?b.deleteRecord():b.rollback(),a.set("isDirty",!1),window.onbeforeunload=null,void c.retry()):(this.notifications.showError("Sorry, there was an error in the application. Please let the Ghost team know what happened."),!0)},confirmReject:function(){}},confirm:{accept:{text:"Leave",buttonClass:"btn btn-red"},reject:{text:"Stay",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/transfer-owner",["exports"],function(a){"use strict";var b=Ember.Controller.extend({actions:{confirmAccept:function(){var a=this.get("model"),b=this.get("ghostPaths.url").api("users","owner"),c=this;c.get("dropdown").closeDropdowns(),ic.ajax.request(b,{type:"PUT",data:{owner:[{id:a.get("id")}]}}).then(function(b){b&&Ember.isArray(b.users)&&b.users.forEach(function(a){var b=c.store.getById("user",a.id),d=c.store.getById("role",a.roles[0].id); -b.set("role",d)}),c.notifications.showSuccess("Ownership successfully transferred to "+a.get("name"))}).catch(function(a){c.notifications.showAPIError(a)})},confirmReject:function(){return!1}},confirm:{accept:{text:"Yep - I'm sure",buttonClass:"btn btn-red"},reject:{text:"Cancel",buttonClass:"btn btn-default btn-minor"}}});a["default"]=b}),define("ghost/controllers/modals/upload",["exports"],function(a){"use strict";var b=Ember.Controller.extend({acceptEncoding:"image/*",actions:{confirmAccept:function(){var a=this;this.get("model").save().then(function(b){return a.notifications.showSuccess("Saved"),b}).catch(function(b){a.notifications.showErrors(b)})},confirmReject:function(){return!1}}});a["default"]=b}),define("ghost/controllers/post-settings-menu",["ghost/utils/date-formatting","ghost/models/slug-generator","ghost/utils/bound-one-way","ghost/utils/isNumber","exports"],function(a,b,c,d,e){"use strict";var f=a.parseDateString,g=a.formatDate,h=b["default"],i=c["default"],j=d["default"],k=Ember.ObjectController.extend({needs:"application",lastPromise:null,isViewingSubview:Ember.computed("controllers.application.showSettingsMenu",function(a,b){return this.get("controllers.application.showSettingsMenu")&&arguments.length>1?b:!1}),selectedAuthor:null,initializeSelectedAuthor:function(){var a=this;return this.get("author").then(function(b){return a.set("selectedAuthor",b),b})}.observes("model"),changeAuthor:function(){var a=this.get("author"),b=this.get("selectedAuthor"),c=this.get("model"),d=this;b.get("id")!==a.get("id")&&(c.set("author",b),this.get("isNew")||c.save().catch(function(b){d.showErrors(b),d.set("selectedAuthor",a),c.rollback()}))}.observes("selectedAuthor"),authors:Ember.computed(function(){var a={};return a.promise=this.store.find("user",{limit:"all"}).then(function(a){return a.rejectBy("id","me").sortBy("name")}).then(function(a){return a.filter(function(a){return a.get("active")})}),Ember.ArrayProxy.extend(Ember.PromiseProxyMixin).create(a)}),publishedAtValue:Ember.computed("published_at",function(){var a=this.get("published_at");return g(a?a:moment())}),slugValue:i("slug"),slugGenerator:Ember.computed(function(){return h.create({ghostPaths:this.get("ghostPaths"),slugType:"post"})}),generateAndSetSlug:function(a){var b,c=this,d=this.get("titleScratch"),e=this.get("lastPromise");"(Untitled)"===d&&this.get("slug")||(b=Ember.RSVP.resolve(e).then(function(){return c.get("slugGenerator").generateSlug(d).then(function(b){c.set(a,b)}).catch(function(){})}),this.set("lastPromise",b))},metaTitleScratch:i("meta_title"),metaDescriptionScratch:i("meta_description"),seoTitle:Ember.computed("titleScratch","metaTitleScratch",function(){var a=this.get("metaTitleScratch")||"";return a=a.length>0?a:this.get("titleScratch"),a.length>70&&(a=a.substring(0,70).trim(),a=Ember.Handlebars.Utils.escapeExpression(a),a=new Ember.Handlebars.SafeString(a+"…")),a}),seoDescription:Ember.computed("scratch","metaDescriptionScratch",function(){var a,b,c=this.get("metaDescriptionScratch")||"",d="";return c.length>0?b=c:(a=$(".rendered-markdown"),void 0!==a&&a.length>0&&(d=a.clone(),d.find(".js-drop-zone").remove(),d=d[0].innerHTML),b=$("
",{html:d}).text(),b=b.replace(/\n+/g," ").trim()),b.length>156&&(b=b.substring(0,156).trim(),b=Ember.Handlebars.Utils.escapeExpression(b),b=new Ember.Handlebars.SafeString(b+"…")),b}),seoURL:Ember.computed("slug",function(){var a=this.get("config").blogUrl,b=this.get("slug")?this.get("slug"):"",c=a+"/"+b;return b&&(c+="/"),c.length>70&&(c=c.substring(0,70).trim(),c=new Ember.Handlebars.SafeString(c+"…")),c}),addTitleObserver:function(){(this.get("isNew")||"(Untitled)"===this.get("title"))&&this.addObserver("titleScratch",this,"titleObserver")}.observes("model"),titleObserver:function(){var a,b=this.get("title");(this.get("isNew")&&!b||"(Untitled)"===b)&&(a=Ember.run.debounce(this,"generateAndSetSlug",["slug"],700)),this.set("debounceId",a)},showErrors:function(a){a=Ember.isArray(a)?a:[a],this.notifications.showErrors(a)},showSuccess:function(a){this.notifications.showSuccess(a)},actions:{togglePage:function(){var a=this;this.toggleProperty("page"),this.get("isNew")||this.get("model").save().catch(function(b){a.showErrors(b),a.get("model").rollback()})},toggleFeatured:function(){var a=this;this.toggleProperty("featured"),this.get("isNew")||this.get("model").save(this.get("saveOptions")).catch(function(b){a.showErrors(b),a.get("model").rollback()})},updateSlug:function(a){var b=this.get("slug"),c=this;return a=a||b,a=a&&a.trim(),a&&b!==a?void this.get("slugGenerator").generateSlug(a).then(function(d){if(d!==b){var e=d.split("-"),f=Number(e.pop());if(j(f)&&f>0&&b===e.join("-")&&d!==a)return void c.set("slugValue",b);if(c.set("slug",d),c.hasObserverFor("titleScratch")&&c.removeObserver("titleScratch",c,"titleObserver"),!c.get("isNew"))return c.get("model").save()}}).catch(function(a){c.showErrors(a),c.get("model").rollback()}):void this.set("slugValue",b)},setPublishedAt:function(a){var b="",c=f(a),d=this.get("published_at"),e=this;return a?(c.isValid()||(b="Published Date must be a valid date with format: DD MMM YY @ HH:mm (e.g. 6 Dec 14 @ 15:00)"),c.diff(new Date,"h")>0&&(b="Published Date cannot currently be in the future."),b?void this.showErrors(b):void(d&&d.isSame(c)||(this.set("published_at",c),this.get("isNew")||this.get("model").save().catch(function(a){e.showErrors(a),e.get("model").rollback()})))):void(this.get("isDraft")&&this.set("published_at",null))},setMetaTitle:function(a){var b=this,c=this.get("meta_title")||"";c!==a&&(this.set("meta_title",a),this.get("isNew")||this.get("model").save().catch(function(a){b.showErrors(a)}))},setMetaDescription:function(a){var b=this,c=this.get("meta_description")||"";c!==a&&(this.set("meta_description",a),this.get("isNew")||this.get("model").save().catch(function(a){b.showErrors(a)}))},setCoverImage:function(a){var b=this;this.set("image",a),this.get("isNew")||this.get("model").save().catch(function(a){b.showErrors(a),b.get("model").rollback()})},clearCoverImage:function(){var a=this;this.set("image",""),this.get("isNew")||this.get("model").save().catch(function(b){a.showErrors(b),a.get("model").rollback()})},showSubview:function(){this.set("isViewingSubview",!0)},closeSubview:function(){this.set("isViewingSubview",!1)},resetUploader:function(){var a=this.get("uploaderReference");a&&a[0]&&a[0].uploaderUi.reset()}}});e["default"]=k}),define("ghost/controllers/post-tags-input",["exports"],function(a){"use strict";var b=Ember.Controller.extend({tagEnteredOrder:Ember.A(),tags:Ember.computed("parentController.tags",function(){var a=Ember.ArrayProxy.create({content:this.get("parentController.tags")}),b=a.get("arrangedContent").slice();return a.get("arrangedContent").clear(),this.get("tagEnteredOrder").forEach(function(c){var d=b.find(function(a){return a.get("name")===c});d&&(a.get("arrangedContent").addObject(d),b.removeObject(d))}),a.get("arrangedContent").unshiftObjects(b),a}),suggestions:null,newTagText:null,actions:{loadAllTags:function(){this.store.find("tag")},addNewTag:function(){var a,b,c,d=this.get("newTagText");return Ember.isEmpty(d)||this.hasTag(d)?void this.send("reset"):(d=d.trim(),a=d.toLowerCase(),b=this.store.all("tag").filter(function(b){return b.get("name").toLowerCase()===a}),b.get("length")?this.send("addTag",b.get("firstObject")):(c=this.store.createRecord("tag"),c.set("name",d),this.send("addTag",c)),void this.send("reset"))},addTag:function(a){Ember.isEmpty(a)||(this.get("tags").addObject(a),this.get("tagEnteredOrder").addObject(a.get("name"))),this.send("reset")},deleteTag:function(a){a&&(this.get("tags").removeObject(a),this.get("tagEnteredOrder").removeObject(a.get("name")))},deleteLastTag:function(){this.send("deleteTag",this.get("tags.lastObject"))},selectSuggestion:function(a){Ember.isEmpty(a)||(this.get("suggestions").setEach("selected",!1),a.set("selected",!0))},selectNextSuggestion:function(){var a,b,c=this.get("suggestions"),d=this.get("selectedSuggestion");Ember.isEmpty(c)||(a=c.indexOf(d),a+1=0?(c=d[a-1],this.send("selectSuggestion",c)):d.setEach("selected",!1))},addSelectedSuggestion:function(){var a=this.get("selectedSuggestion");Ember.isEmpty(a)||this.send("addTag",a.get("tag"))},reset:function(){this.set("suggestions",null),this.set("newTagText",null)}},selectedSuggestion:Ember.computed("suggestions.@each.selected",function(){var a=this.get("suggestions");return a&&a.get("length")?a.filterBy("selected").get("firstObject"):null}),updateSuggestionsList:function(){var a,b=this.get("newTagText"),c=5,d=Ember.A();return!b||Ember.isEmpty(b.trim())?void this.set("suggestions",null):(b=b.trim(),a=this.findMatchingTags(b),a=a.slice(0,c),a.forEach(function(a){var c=this.makeSuggestionObject(a,b);d.pushObject(c)},this),void this.set("suggestions",d))}.observes("newTagText"),findMatchingTags:function(a){var b,c=this,d=this.store.all("tag"),e={};return 0===d.get("length")?[]:(a=a.toLowerCase(),b=d.filter(function(b){var d,f,g=b.get("name");return d=-1!==g.toLowerCase().indexOf(a),f=c.hasTag(g),d&&!f&&("undefined"==typeof e[g]?e[g]=1:e[g]+=1),1===e[g]}))},hasTag:function(a){return this.get("tags").mapBy("name").contains(a)},makeSuggestionObject:function(a,b){var c,d=Ember.Handlebars.Utils.escapeExpression(b),e=d.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),f=Ember.Handlebars.Utils.escapeExpression(a.get("name")),g=new RegExp("("+e+")","gi"),h=Ember.Object.create();return c=f.replace(g,"$1"),c=new Ember.Handlebars.SafeString(c),h.set("tag",a),h.set("highlightedName",c),h}});a["default"]=b}),define("ghost/controllers/posts",["ghost/mixins/pagination-controller","exports"],function(a,b){"use strict";function c(a,b){var c=a.get("published_at"),d=b.get("published_at");return c||d?!c&&d?-1:!d&&c?1:Ember.compare(c.valueOf(),d.valueOf()):0}var d=a["default"],e=Ember.ArrayController.extend(d,{postListFocused:Ember.computed.equal("keyboardFocus","postList"),postContentFocused:Ember.computed.equal("keyboardFocus","postContent"),sortProperties:["status","published_at","updated_at"],orderBy:function(a,b){var d,e,f,g=a.get("updated_at"),h=b.get("updated_at");return a.get("isNew")||!g?-1:b.get("isNew")||!h?1:(d=Ember.compare(a.get("status"),b.get("status")),e=Ember.compare(g.valueOf(),h.valueOf()),f=c(a,b),0===d?0===f?-1*e:-1*f:d)},init:function(){this._super({modelType:"post"})}});b["default"]=e}),define("ghost/controllers/posts/post",["exports"],function(a){"use strict";var b=Ember.ObjectController.extend({isPublished:Ember.computed.equal("status","published"),classNameBindings:["featured"],actions:{toggleFeatured:function(){var a={disableNProgress:!0},b=this;this.toggleProperty("featured"),this.get("model").save(a).catch(function(a){b.notifications.showErrors(a)})},showPostContent:function(){this.transitionToRoute("posts.post",this.get("model"))}}});a["default"]=b}),define("ghost/controllers/reset",["ghost/utils/ajax","ghost/mixins/validation-engine","exports"],function(a,b,c){"use strict";var d=a["default"],e=b["default"],f=Ember.Controller.extend(e,{newPassword:"",ne2Password:"",token:"",submitButtonDisabled:!1,validationType:"reset",email:Ember.computed("token",function(){return atob(this.get("token")).split("|")[1]}),clearData:function(){this.setProperties({newPassword:"",ne2Password:"",token:""})},actions:{submit:function(){var a=this.getProperties("newPassword","ne2Password","token"),b=this;this.toggleProperty("submitting"),this.validate({format:!1}).then(function(){d({url:b.get("ghostPaths.url").api("authentication","passwordreset"),type:"PUT",data:{passwordreset:[a]}}).then(function(c){b.toggleProperty("submitting"),b.notifications.showSuccess(c.passwordreset[0].message,!0),b.get("session").authenticate("simple-auth-authenticator:oauth2-password-grant",{identification:b.get("email"),password:a.newPassword})}).catch(function(a){b.notifications.showAPIError(a),b.toggleProperty("submitting")})}).catch(function(a){b.toggleProperty("submitting"),b.notifications.showErrors(a)})}}});c["default"]=f}),define("ghost/controllers/settings",["exports"],function(a){"use strict";var b=Ember.Controller.extend({showGeneral:Ember.computed("session.user.name",function(){return this.get("session.user.isAuthor")||this.get("session.user.isEditor")?!1:!0}),showUsers:Ember.computed("session.user.name",function(){return this.get("session.user.isAuthor")?!1:!0}),showTags:Ember.computed("session.user.name","config.tagsUI",function(){return this.get("session.user.isAuthor")||!this.get("config.tagsUI")?!1:!0}),showCodeInjection:Ember.computed("session.user.name","config.codeInjectionUI",function(){return this.get("session.user.isAuthor")||this.get("session.user.isEditor")||!this.get("config.codeInjectionUI")?!1:!0}),showLabs:Ember.computed("session.user.name",function(){return this.get("session.user.isAuthor")||this.get("session.user.isEditor")?!1:!0}),showAbout:Ember.computed("session.user.name",function(){return this.get("session.user.isAuthor")?!1:!0})});a["default"]=b}),define("ghost/controllers/settings/app",["exports"],function(a){"use strict";var b,c;b={active:"active",working:"working",inactive:"inactive"},c=Ember.ObjectController.extend({appState:b.active,buttonText:"",setAppState:function(){this.set("appState",this.get("active")?b.active:b.inactive)}.on("init"),buttonTextSetter:function(){switch(this.get("appState")){case b.active:this.set("buttonText","Deactivate");break;case b.inactive:this.set("buttonText","Activate");break;case b.working:this.set("buttonText","Working")}}.observes("appState").on("init"),activeClass:Ember.computed("appState",function(){return this.appState===b.active?!0:!1}),inactiveClass:Ember.computed("appState",function(){return this.appState===b.inactive?!0:!1}),actions:{toggleApp:function(a){var c=this;this.set("appState",b.working),a.set("active",!a.get("active")),a.save().then(function(){c.setAppState()}).then(function(){alert("@TODO: Success")}).catch(function(){alert("@TODO: Failure")})}}}),a["default"]=c}),define("ghost/controllers/settings/code-injection",["exports"],function(a){"use strict";var b=Ember.ObjectController.extend({actions:{save:function(){var a=this;return this.get("model").save().then(function(b){return a.notifications.closePassive(),a.notifications.showSuccess("Settings successfully saved."),b}).catch(function(b){a.notifications.closePassive(),a.notifications.showErrors(b)})}}});a["default"]=b}),define("ghost/controllers/settings/general",["exports"],function(a){"use strict";var b=Ember.ObjectController.extend({isDatedPermalinks:Ember.computed("permalinks",function(a,b){arguments.length>1&&this.set("permalinks",b?"/:year/:month/:day/:slug/":"/:slug/");var c=this.get("permalinks");return"/:slug/"!==c}),themes:Ember.computed(function(){return this.get("availableThemes").reduce(function(a,b){var c={};return c.name=b.name,c.label=b.package?b.package.name+" - "+b.package.version:b.name,c.package=b.package,c.active=!!b.active,a.push(c),a},[])}).readOnly(),actions:{save:function(){var a=this;return this.get("model").save().then(function(b){return a.notifications.showSuccess("Settings successfully saved."),b}).catch(function(b){a.notifications.showErrors(b)})},checkPostsPerPage:function(){(this.get("postsPerPage")<1||this.get("postsPerPage")>1e3||isNaN(this.get("postsPerPage")))&&this.set("postsPerPage",5)}}});a["default"]=b}),define("ghost/controllers/settings/labs",["exports"],function(a){"use strict";var b=Ember.Controller.extend(Ember.Evented,{uploadButtonText:"Import",importErrors:"",actions:{onUpload:function(a){var b=this,c=new FormData;this.set("uploadButtonText","Importing"),this.notifications.closePassive(),c.append("importfile",a),ic.ajax.request(this.get("ghostPaths.url").api("db"),{type:"POST",data:c,dataType:"json",cache:!1,contentType:!1,processData:!1}).then(function(){b.notifications.showSuccess("Import successful.")}).catch(function(a){a&&a.jqXHR&&a.jqXHR.responseJSON&&a.jqXHR.responseJSON.errors&&b.set("importErrors",a.jqXHR.responseJSON.errors),b.notifications.showError("Import Failed")}).finally(function(){b.set("uploadButtonText","Import"),b.trigger("reset")})},exportData:function(){var a=$("#iframeDownload"),b=this.get("ghostPaths.url").api("db")+"?access_token="+this.get("session.access_token");0===a.length&&(a=$("