From a1ed9adf928d999977e4d521f4604b6c797d5e93 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 29 Dec 2014 21:11:24 -0500 Subject: [PATCH] Remove ObjectController proxying behavior. Ember.ObjectController (and Ember.ArrayController) will be deprecated in Ember 1.11 (and removed from core in Ember 2.0). The reasoning is detailed in the Ember 2.0 RFC. This PR does the following: * Updates templates/controllers/views to explicitly reference model properties (instead of relying on proxying behavior). * Clearly delineate where certain properties are being set or retrieved from (for example it was not clear exactly where `scratch` and `titleScratch` were stored). * Remove usage of `Ember.ObjectController`. * Add JSCS rule to prevent future PR's from adding regressions. --- .jscsrc | 1 + Gruntfile.js | 6 +- core/client/controllers/editor/edit.js | 2 +- core/client/controllers/editor/new.js | 2 +- core/client/controllers/modals/delete-tag.js | 6 +- core/client/controllers/modals/delete-user.js | 6 +- core/client/controllers/post-settings-menu.js | 92 ++++++++++--------- core/client/controllers/post-tags-input.js | 4 +- core/client/controllers/posts/post.js | 8 +- core/client/controllers/settings/app.js | 2 +- .../controllers/settings/code-injection.js | 2 +- core/client/controllers/settings/general.js | 18 ++-- .../client/controllers/settings/users/user.js | 10 +- core/client/controllers/setup.js | 2 +- core/client/controllers/signup.js | 8 +- core/client/mixins/editor-base-controller.js | 53 ++++++----- core/client/mixins/editor-base-route.js | 6 +- core/client/models/post.js | 3 + core/client/templates/-publish-bar.hbs | 2 +- core/client/templates/editor-save-button.hbs | 2 +- core/client/templates/editor/edit.hbs | 8 +- core/client/templates/modals/delete-tag.hbs | 6 +- core/client/templates/post-settings-menu.hbs | 6 +- core/client/templates/posts.hbs | 8 +- core/client/templates/posts/post.hbs | 8 +- core/client/templates/settings/about.hbs | 10 +- core/client/templates/settings/apps.hbs | 8 +- .../templates/settings/code-injection.hbs | 4 +- core/client/templates/settings/general.hbs | 22 ++--- .../client/templates/settings/users/index.hbs | 12 +-- core/client/templates/settings/users/user.hbs | 4 +- core/client/templates/setup.hbs | 2 +- core/client/templates/signup.hbs | 6 +- core/client/utils/link-view.js | 2 +- core/client/views/editor-save-button.js | 12 +-- core/client/views/post-tags-input.js | 2 - core/test/functional/client/editor_test.js | 2 + .../jscs-rules/disallow-object-controller.js | 32 +++++++ 38 files changed, 219 insertions(+), 170 deletions(-) create mode 100644 core/test/utils/jscs-rules/disallow-object-controller.js diff --git a/.jscsrc b/.jscsrc index 6a60f1ef3921..bb1e481d10c5 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,4 +1,5 @@ { + "additionalRules": [ "core/test/utils/jscs-rules/*.js" ], "requireCurlyBraces": [ "if", "else", diff --git a/Gruntfile.js b/Gruntfile.js index 94e91eb50aa7..ea96ebf3e525 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -203,13 +203,15 @@ var _ = require('lodash'), client: { options: { config: '.jscsrc', - esnext: true + esnext: true, + disallowObjectController: true } }, clientTests: { options: { config: '.jscsrc', - esnext: true + esnext: true, + disallowObjectController: true } }, test: { diff --git a/core/client/controllers/editor/edit.js b/core/client/controllers/editor/edit.js index 49d36f4a0357..d8cb1d1d63d0 100644 --- a/core/client/controllers/editor/edit.js +++ b/core/client/controllers/editor/edit.js @@ -1,5 +1,5 @@ import EditorControllerMixin from 'ghost/mixins/editor-base-controller'; -var EditorEditController = Ember.ObjectController.extend(EditorControllerMixin); +var EditorEditController = Ember.Controller.extend(EditorControllerMixin); export default EditorEditController; diff --git a/core/client/controllers/editor/new.js b/core/client/controllers/editor/new.js index 94c109c0c91b..1d1bfab9b529 100644 --- a/core/client/controllers/editor/new.js +++ b/core/client/controllers/editor/new.js @@ -1,6 +1,6 @@ import EditorControllerMixin from 'ghost/mixins/editor-base-controller'; -var EditorNewController = Ember.ObjectController.extend(EditorControllerMixin, { +var EditorNewController = Ember.Controller.extend(EditorControllerMixin, { actions: { /** * Redirect to editor after the first save diff --git a/core/client/controllers/modals/delete-tag.js b/core/client/controllers/modals/delete-tag.js index bd8ce677d043..e77ced827428 100644 --- a/core/client/controllers/modals/delete-tag.js +++ b/core/client/controllers/modals/delete-tag.js @@ -1,6 +1,6 @@ -var DeleteTagController = Ember.ObjectController.extend({ - postInflection: Ember.computed('post_count', function () { - return this.get('post_count') > 1 ? 'posts' : 'post'; +var DeleteTagController = Ember.Controller.extend({ + postInflection: Ember.computed('model.post_count', function () { + return this.get('model.post_count') > 1 ? 'posts' : 'post'; }), actions: { diff --git a/core/client/controllers/modals/delete-user.js b/core/client/controllers/modals/delete-user.js index ed6ce9e1feb3..5dfbd52c3ddc 100644 --- a/core/client/controllers/modals/delete-user.js +++ b/core/client/controllers/modals/delete-user.js @@ -1,8 +1,8 @@ -var DeleteUserController = Ember.ObjectController.extend({ - userPostCount: Ember.computed('id', function () { +var DeleteUserController = Ember.Controller.extend({ + userPostCount: Ember.computed('model.id', function () { var promise, query = { - author: this.get('slug'), + author: this.get('model.slug'), status: 'all' }; diff --git a/core/client/controllers/post-settings-menu.js b/core/client/controllers/post-settings-menu.js index 147faf8f71f5..4025c16de942 100644 --- a/core/client/controllers/post-settings-menu.js +++ b/core/client/controllers/post-settings-menu.js @@ -5,21 +5,23 @@ import SlugGenerator from 'ghost/models/slug-generator'; import boundOneWay from 'ghost/utils/bound-one-way'; import isNumber from 'ghost/utils/isNumber'; -var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin, { +var PostSettingsMenuController = Ember.Controller.extend(SettingsMenuMixin, { + debounceId: null, lastPromise: null, - selectedAuthor: null, + uploaderReference: null, + initializeSelectedAuthor: function () { var self = this; - return this.get('author').then(function (author) { + return this.get('model.author').then(function (author) { self.set('selectedAuthor', author); return author; }); }.observes('model'), changeAuthor: function () { - var author = this.get('author'), + var author = this.get('model.author'), selectedAuthor = this.get('selectedAuthor'), model = this.get('model'), self = this; @@ -32,7 +34,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin model.set('author', selectedAuthor); // if this is a new post (never been saved before), don't try to save it - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -61,8 +63,8 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin }), /*jshint unused:false */ - publishedAtValue: Ember.computed('published_at', function (key, value) { - var pubDate = this.get('published_at'); + publishedAtValue: Ember.computed('model.published_at', function (key, value) { + var pubDate = this.get('model.published_at'); // We're using a fake setter to reset // the cache for this property @@ -78,7 +80,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin }), /*jshint unused:true */ - slugValue: boundOneWay('slug'), + slugValue: boundOneWay('model.slug'), // Lazy load the slug generator slugGenerator: Ember.computed(function () { @@ -91,12 +93,12 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin // Requests slug from title generateAndSetSlug: function (destination) { var self = this, - title = this.get('titleScratch'), + title = this.get('model.titleScratch'), afterSave = this.get('lastPromise'), promise; // Only set an "untitled" slug once per post - if (title === '(Untitled)' && this.get('slug')) { + if (title === '(Untitled)' && this.get('model.slug')) { return; } @@ -113,13 +115,13 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin this.set('lastPromise', promise); }, - metaTitleScratch: boundOneWay('meta_title'), - metaDescriptionScratch: boundOneWay('meta_description'), + metaTitleScratch: boundOneWay('model.meta_title'), + metaDescriptionScratch: boundOneWay('model.meta_description'), - seoTitle: Ember.computed('titleScratch', 'metaTitleScratch', function () { + seoTitle: Ember.computed('model.titleScratch', 'metaTitleScratch', function () { var metaTitle = this.get('metaTitleScratch') || ''; - metaTitle = metaTitle.length > 0 ? metaTitle : this.get('titleScratch'); + metaTitle = metaTitle.length > 0 ? metaTitle : this.get('model.titleScratch'); if (metaTitle.length > 70) { metaTitle = metaTitle.substring(0, 70).trim(); @@ -130,7 +132,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin return metaTitle; }), - seoDescription: Ember.computed('scratch', 'metaDescriptionScratch', function () { + seoDescription: Ember.computed('model.scratch', 'metaDescriptionScratch', function () { var metaDescription = this.get('metaDescriptionScratch') || '', el, html = '', @@ -166,9 +168,9 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin return placeholder; }), - seoURL: Ember.computed('slug', function () { + seoURL: Ember.computed('model.slug', function () { var blogUrl = this.get('config').blogUrl, - seoSlug = this.get('slug') ? this.get('slug') : '', + seoSlug = this.get('model.slug') ? this.get('model.slug') : '', seoURL = blogUrl + '/' + seoSlug; // only append a slash to the URL if the slug exists @@ -187,18 +189,18 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin // observe titleScratch, keeping the post's slug in sync // with it until saved for the first time. addTitleObserver: function () { - if (this.get('isNew') || this.get('title') === '(Untitled)') { - this.addObserver('titleScratch', this, 'titleObserver'); + if (this.get('model.isNew') || this.get('model.title') === '(Untitled)') { + this.addObserver('model.titleScratch', this, 'titleObserver'); } }.observes('model'), titleObserver: function () { var debounceId, - title = this.get('title'); + title = this.get('model.title'); // generate a slug if a post is new and doesn't have a title yet or // if the title is still '(Untitled)' and the slug is unaltered. - if ((this.get('isNew') && !title) || title === '(Untitled)') { + if ((this.get('model.isNew') && !title) || title === '(Untitled)') { debounceId = Ember.run.debounce(this, 'generateAndSetSlug', ['slug'], 700); } @@ -218,10 +220,10 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin togglePage: function () { var self = this; - this.toggleProperty('page'); + this.toggleProperty('model.page'); // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -234,11 +236,11 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin toggleFeatured: function () { var self = this; - this.toggleProperty('featured'); + this.toggleProperty('model.featured'); // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -252,7 +254,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin * triggered by user manually changing slug */ updateSlug: function (newSlug) { - var slug = this.get('slug'), + var slug = this.get('model.slug'), self = this; newSlug = newSlug || slug; @@ -294,15 +296,15 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin } } - self.set('slug', serverSlug); + self.set('model.slug', serverSlug); - if (self.hasObserverFor('titleScratch')) { - self.removeObserver('titleScratch', self, 'titleObserver'); + if (self.hasObserverFor('model.titleScratch')) { + self.removeObserver('model.titleScratch', self, 'titleObserver'); } // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (self.get('isNew')) { + if (self.get('model.isNew')) { return; } @@ -321,13 +323,13 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin setPublishedAt: function (userInput) { var errMessage = '', newPublishedAt = parseDateString(userInput), - publishedAt = this.get('published_at'), + publishedAt = this.get('model.published_at'), self = this; if (!userInput) { // Clear out the published_at field for a draft - if (this.get('isDraft')) { - this.set('published_at', null); + if (this.get('model.isDraft')) { + this.set('model.published_at', null); } return; @@ -355,11 +357,11 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin } // Validation complete - this.set('published_at', newPublishedAt); + this.set('model.published_at', newPublishedAt); // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -371,18 +373,18 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin setMetaTitle: function (metaTitle) { var self = this, - currentTitle = this.get('meta_title') || ''; + currentTitle = this.get('model.meta_title') || ''; // Only update if the title has changed if (currentTitle === metaTitle) { return; } - this.set('meta_title', metaTitle); + this.set('model.meta_title', metaTitle); // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -393,18 +395,18 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin setMetaDescription: function (metaDescription) { var self = this, - currentDescription = this.get('meta_description') || ''; + currentDescription = this.get('model.meta_description') || ''; // Only update if the description has changed if (currentDescription === metaDescription) { return; } - this.set('meta_description', metaDescription); + this.set('model.meta_description', metaDescription); // If this is a new post. Don't save the model. Defer the save // to the user pressing the save button - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -416,9 +418,9 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin setCoverImage: function (image) { var self = this; - this.set('image', image); + this.set('model.image', image); - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } @@ -431,9 +433,9 @@ var PostSettingsMenuController = Ember.ObjectController.extend(SettingsMenuMixin clearCoverImage: function () { var self = this; - this.set('image', ''); + this.set('model.image', ''); - if (this.get('isNew')) { + if (this.get('model.isNew')) { return; } diff --git a/core/client/controllers/post-tags-input.js b/core/client/controllers/post-tags-input.js index 189d9d7dad83..eed7d4fccffd 100644 --- a/core/client/controllers/post-tags-input.js +++ b/core/client/controllers/post-tags-input.js @@ -1,9 +1,9 @@ var PostTagsInputController = Ember.Controller.extend({ tagEnteredOrder: Ember.A(), - tags: Ember.computed('parentController.tags', function () { + tags: Ember.computed('parentController.model.tags', function () { var proxyTags = Ember.ArrayProxy.create({ - content: this.get('parentController.tags') + content: this.get('parentController.model.tags') }), temp = proxyTags.get('arrangedContent').slice(); diff --git a/core/client/controllers/posts/post.js b/core/client/controllers/posts/post.js index 8bcfd9fc8eab..621c71f849b6 100644 --- a/core/client/controllers/posts/post.js +++ b/core/client/controllers/posts/post.js @@ -1,13 +1,13 @@ -var PostController = Ember.ObjectController.extend({ - isPublished: Ember.computed.equal('status', 'published'), - classNameBindings: ['featured'], +var PostController = Ember.Controller.extend({ + isPublished: Ember.computed.equal('model.status', 'published'), + classNameBindings: ['model.featured'], actions: { toggleFeatured: function () { var options = {disableNProgress: true}, self = this; - this.toggleProperty('featured'); + this.toggleProperty('model.featured'); this.get('model').save(options).catch(function (errors) { self.notifications.showErrors(errors); }); diff --git a/core/client/controllers/settings/app.js b/core/client/controllers/settings/app.js index ba7c8d2f368e..1179eaef3395 100644 --- a/core/client/controllers/settings/app.js +++ b/core/client/controllers/settings/app.js @@ -9,7 +9,7 @@ appStates = { inactive: 'inactive' }; -SettingsAppController = Ember.ObjectController.extend({ +SettingsAppController = Ember.Controller.extend({ appState: appStates.active, buttonText: '', diff --git a/core/client/controllers/settings/code-injection.js b/core/client/controllers/settings/code-injection.js index 95af5d53444e..2b87c9d14eaf 100644 --- a/core/client/controllers/settings/code-injection.js +++ b/core/client/controllers/settings/code-injection.js @@ -1,4 +1,4 @@ -var SettingsCodeInjectionController = Ember.ObjectController.extend({ +var SettingsCodeInjectionController = Ember.Controller.extend({ actions: { save: function () { var self = this; diff --git a/core/client/controllers/settings/general.js b/core/client/controllers/settings/general.js index 33c0a8962855..eb0e2871d525 100644 --- a/core/client/controllers/settings/general.js +++ b/core/client/controllers/settings/general.js @@ -1,18 +1,20 @@ -var SettingsGeneralController = Ember.ObjectController.extend({ - isDatedPermalinks: Ember.computed('permalinks', function (key, value) { +var SettingsGeneralController = Ember.Controller.extend({ + selectedTheme: null, + + isDatedPermalinks: Ember.computed('model.permalinks', function (key, value) { // setter if (arguments.length > 1) { - this.set('permalinks', value ? '/:year/:month/:day/:slug/' : '/:slug/'); + this.set('model.permalinks', value ? '/:year/:month/:day/:slug/' : '/:slug/'); } // getter - var slugForm = this.get('permalinks'); + var slugForm = this.get('model.permalinks'); return slugForm !== '/:slug/'; }), themes: Ember.computed(function () { - return this.get('availableThemes').reduce(function (themes, t) { + return this.get('model.availableThemes').reduce(function (themes, t) { var theme = {}; theme.name = t.name; @@ -40,8 +42,10 @@ var SettingsGeneralController = Ember.ObjectController.extend({ }, checkPostsPerPage: function () { - if (this.get('postsPerPage') < 1 || this.get('postsPerPage') > 1000 || isNaN(this.get('postsPerPage'))) { - this.set('postsPerPage', 5); + var postsPerPage = this.get('model.postsPerPage'); + + if (postsPerPage < 1 || postsPerPage > 1000 || isNaN(postsPerPage)) { + this.set('model.postsPerPage', 5); } } } diff --git a/core/client/controllers/settings/users/user.js b/core/client/controllers/settings/users/user.js index 0d13514b7908..c9e690689dac 100644 --- a/core/client/controllers/settings/users/user.js +++ b/core/client/controllers/settings/users/user.js @@ -2,13 +2,13 @@ import SlugGenerator from 'ghost/models/slug-generator'; import isNumber from 'ghost/utils/isNumber'; import boundOneWay from 'ghost/utils/bound-one-way'; -var SettingsUserController = Ember.ObjectController.extend({ +var SettingsUserController = Ember.Controller.extend({ user: Ember.computed.alias('model'), - email: Ember.computed.readOnly('user.email'), + email: Ember.computed.readOnly('model.email'), - slugValue: boundOneWay('user.slug'), + slugValue: boundOneWay('model.slug'), lastPromise: null, @@ -74,7 +74,7 @@ var SettingsUserController = Ember.ObjectController.extend({ // reload the model to get the most up-to-date user information model.reload().then(function () { - if (self.get('invited')) { + if (model.get('invited')) { model.destroyRecord().then(function () { var notificationText = 'Invitation revoked. (' + email + ')'; self.notifications.showSuccess(notificationText, false); @@ -178,7 +178,7 @@ var SettingsUserController = Ember.ObjectController.extend({ promise; promise = Ember.RSVP.resolve(afterSave).then(function () { - var slug = self.get('slug'); + var slug = self.get('model.slug'); newSlug = newSlug || slug; diff --git a/core/client/controllers/setup.js b/core/client/controllers/setup.js index f72158e1b659..1126a9c70b10 100644 --- a/core/client/controllers/setup.js +++ b/core/client/controllers/setup.js @@ -1,7 +1,7 @@ import ajax from 'ghost/utils/ajax'; import ValidationEngine from 'ghost/mixins/validation-engine'; -var SetupController = Ember.ObjectController.extend(ValidationEngine, { +var SetupController = Ember.Controller.extend(ValidationEngine, { blogTitle: null, name: null, email: null, diff --git a/core/client/controllers/signup.js b/core/client/controllers/signup.js index d120a9ea1854..82843101b0b9 100644 --- a/core/client/controllers/signup.js +++ b/core/client/controllers/signup.js @@ -1,7 +1,7 @@ import ajax from 'ghost/utils/ajax'; import ValidationEngine from 'ghost/mixins/validation-engine'; -var SignupController = Ember.ObjectController.extend(ValidationEngine, { +var SignupController = Ember.Controller.extend(ValidationEngine, { submitting: false, // ValidationEngine settings @@ -10,7 +10,7 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, { actions: { signup: function () { var self = this, - data = self.getProperties('name', 'email', 'password', 'token'); + data = self.getProperties('model.name', 'model.email', 'model.password', 'model.token'); self.notifications.closePassive(); @@ -30,8 +30,8 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, { } }).then(function () { self.get('session').authenticate('simple-auth-authenticator:oauth2-password-grant', { - identification: self.get('email'), - password: self.get('password') + identification: self.get('model.email'), + password: self.get('model.password') }); }, function (resp) { self.toggleProperty('submitting'); diff --git a/core/client/mixins/editor-base-controller.js b/core/client/mixins/editor-base-controller.js index e5b3cc94173a..5a4cd7c2bb5c 100644 --- a/core/client/mixins/editor-base-controller.js +++ b/core/client/mixins/editor-base-controller.js @@ -8,7 +8,7 @@ var watchedProps, // this array will hold properties we need to watch // to know if the model has been changed (`controller.isDirty`) -watchedProps = ['scratch', 'titleScratch', 'model.isDirty', 'tags.[]']; +watchedProps = ['model.scratch', 'model.titleScratch', 'model.isDirty', 'model.tags.[]']; PostModel.eachAttribute(function (name) { watchedProps.push('model.' + name); @@ -17,6 +17,11 @@ PostModel.eachAttribute(function (name) { EditorControllerMixin = Ember.Mixin.create(MarkerManager, { needs: ['post-tags-input', 'post-settings-menu'], + autoSaveId: null, + timedSaveId: null, + codemirror: null, + codemirrorComponent: null, + init: function () { var self = this; @@ -32,7 +37,7 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { * Only with a user-set value (via setSaveType action) * can the post's status change. */ - willPublish: boundOneWay('isPublished'), + willPublish: boundOneWay('model.isPublished'), // Make sure editor starts with markdown shown isPreview: false, @@ -41,8 +46,8 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { // whether the number of tags has changed for `isDirty`. previousTagNames: null, - tagNames: Ember.computed('tags.@each.name', function () { - return this.get('tags').mapBy('name'); + tagNames: Ember.computed('model.tags.@each.name', function () { + return this.get('model.tags').mapBy('name'); }), // compares previousTagNames to tagNames @@ -82,8 +87,8 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { // if the two "scratch" properties (title and content) match the model, then // it's ok to set isDirty to false - if (this.get('titleScratch') === model.get('title') && - this.get('scratch') === model.get('markdown')) { + if (model.get('titleScratch') === model.get('title') && + model.get('scratch') === model.get('markdown')) { this.set('isDirty', false); } }, @@ -96,9 +101,9 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { } var model = this.get('model'), - markdown = this.get('markdown'), - title = this.get('title'), - titleScratch = this.get('titleScratch'), + markdown = model.get('markdown'), + title = model.get('title'), + titleScratch = model.get('titleScratch'), scratch = this.getMarkdown().withoutMarkers, changedAttributes; @@ -183,7 +188,7 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { showSaveNotification: function (prevStatus, status, delay) { var message = this.messageMap.success.post[prevStatus][status], - path = this.get('ghostPaths.url').join(this.get('config.blogUrl'), this.get('url')); + path = this.get('ghostPaths.url').join(this.get('config.blogUrl'), this.get('model.url')); if (status === 'published') { message += ' View Post'; @@ -206,8 +211,8 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { actions: { save: function (options) { var status = this.get('willPublish') ? 'published' : 'draft', - prevStatus = this.get('status'), - isNew = this.get('isNew'), + prevStatus = this.get('model.status'), + isNew = this.get('model.isNew'), autoSaveId = this.get('autoSaveId'), timedSaveId = this.get('timedSaveId'), self = this, @@ -233,24 +238,24 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { // Set the properties that are indirected // set markdown equal to what's in the editor, minus the image markers. - this.set('markdown', this.getMarkdown().withoutMarkers); - this.set('status', status); + this.set('model.markdown', this.getMarkdown().withoutMarkers); + this.set('model.status', status); // Set a default title - if (!this.get('titleScratch').trim()) { - this.set('titleScratch', '(Untitled)'); + if (!this.get('model.titleScratch').trim()) { + this.set('model.titleScratch', '(Untitled)'); } - this.set('title', this.get('titleScratch')); - this.set('meta_title', psmController.get('metaTitleScratch')); - this.set('meta_description', psmController.get('metaDescriptionScratch')); + this.set('model.title', this.get('model.titleScratch')); + this.set('model.meta_title', psmController.get('metaTitleScratch')); + this.set('model.meta_description', psmController.get('metaDescriptionScratch')); - if (!this.get('slug')) { + if (!this.get('model.slug')) { // Cancel any pending slug generation that may still be queued in the // run loop because we need to run it before the post is saved. Ember.run.cancel(psmController.get('debounceId')); - psmController.generateAndSetSlug('slug'); + psmController.generateAndSetSlug('model.slug'); } promise = Ember.RSVP.resolve(psmController.get('lastPromise')).then(function () { @@ -263,10 +268,10 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { }); }).catch(function (errors) { if (!options.silent) { - self.showErrorNotification(prevStatus, self.get('status'), errors); + self.showErrorNotification(prevStatus, self.get('model.status'), errors); } - self.set('status', prevStatus); + self.set('model.status', prevStatus); return self.get('model'); }); @@ -360,7 +365,7 @@ EditorControllerMixin = Ember.Mixin.create(MarkerManager, { }, autoSaveNew: function () { - if (this.get('isNew')) { + if (this.get('model.isNew')) { this.send('save', {silent: true, disableNProgress: true}); } } diff --git a/core/client/mixins/editor-base-route.js b/core/client/mixins/editor-base-route.js index ab577ac881d8..8bee160333a8 100644 --- a/core/client/mixins/editor-base-route.js +++ b/core/client/mixins/editor-base-route.js @@ -32,7 +32,7 @@ var EditorBaseRoute = Ember.Mixin.create(styleBody, ShortcutsRoute, loadingIndic willTransition: function (transition) { var controller = this.get('controller'), - scratch = controller.get('scratch'), + scratch = controller.get('model.scratch'), controllerIsDirty = controller.get('isDirty'), model = controller.get('model'), state = model.getProperties('isDeleted', 'isSaving', 'isDirty', 'isNew'), @@ -112,9 +112,9 @@ var EditorBaseRoute = Ember.Mixin.create(styleBody, ShortcutsRoute, loadingIndic this._super(controller, model); var tags = model.get('tags'); - controller.set('scratch', model.get('markdown')); + controller.set('model.scratch', model.get('markdown')); - controller.set('titleScratch', model.get('title')); + controller.set('model.titleScratch', model.get('title')); if (tags) { // used to check if anything has changed in the editor diff --git a/core/client/models/post.js b/core/client/models/post.js index 88fc7721ca86..58e2e84e8905 100644 --- a/core/client/models/post.js +++ b/core/client/models/post.js @@ -27,6 +27,9 @@ var Post = DS.Model.extend(NProgressSaveMixin, ValidationEngine, { tags: DS.hasMany('tag', {embedded: 'always'}), url: DS.attr('string'), + scratch: null, + titleScratch: null, + // Computed post properties isPublished: Ember.computed.equal('status', 'published'), diff --git a/core/client/templates/-publish-bar.hbs b/core/client/templates/-publish-bar.hbs index 10c6ce02092e..075adf1a62d9 100644 --- a/core/client/templates/-publish-bar.hbs +++ b/core/client/templates/-publish-bar.hbs @@ -4,7 +4,7 @@
- {{view "editor-save-button" id="entry-actions" classNameBindings="isNew:unsaved"}} + {{view "editor-save-button" id="entry-actions" classNameBindings="model.isNew:unsaved"}}
diff --git a/core/client/templates/editor-save-button.hbs b/core/client/templates/editor-save-button.hbs index 4ba42962d317..1377b6cebfc9 100644 --- a/core/client/templates/editor-save-button.hbs +++ b/core/client/templates/editor-save-button.hbs @@ -16,4 +16,4 @@ Delete Post -{{/gh-dropdown}} \ No newline at end of file +{{/gh-dropdown}} diff --git a/core/client/templates/editor/edit.hbs b/core/client/templates/editor/edit.hbs index f54e84514f09..d39682f1b450 100644 --- a/core/client/templates/editor/edit.hbs +++ b/core/client/templates/editor/edit.hbs @@ -6,7 +6,7 @@
- {{gh-trim-focus-input type="text" id="entry-title" placeholder="Your Post Title" value=titleScratch + {{gh-trim-focus-input type="text" id="entry-title" placeholder="Your Post Title" value=model.titleScratch tabindex="1" focus=shouldFocusTitle}}
@@ -17,7 +17,7 @@
- {{gh-codemirror value=scratch scrollInfo=view.markdownScrollInfo + {{gh-codemirror value=model.scratch scrollInfo=view.markdownScrollInfo setCodeMirror="setCodeMirror" openModal="openModal" typingPause="autoSave" focus=shouldFocusEditor focusCursorAtEnd=model.isDirty onFocusIn="autoSaveNew"}}
@@ -25,11 +25,11 @@
- Preview {{gh-count-words scratch}} + Preview {{gh-count-words model.scratch}}
{{gh-markdown classNames="rendered-markdown js-rendered-markdown" - markdown=scratch scrollPosition=view.scrollPosition + markdown=model.scratch scrollPosition=view.scrollPosition uploadStarted="disableCodeMirror" uploadFinished="enableCodeMirror" uploadSuccess="handleImgUpload"}}
diff --git a/core/client/templates/modals/delete-tag.hbs b/core/client/templates/modals/delete-tag.hbs index 8e9c3c7479b3..a00448c5a865 100644 --- a/core/client/templates/modals/delete-tag.hbs +++ b/core/client/templates/modals/delete-tag.hbs @@ -1,9 +1,9 @@ {{#gh-modal-dialog action="closeModal" showClose=true type="action" style="wide" title="Are you sure you want to delete this tag?" confirm=confirm}} - {{#if post_count}} - WARNING: This tag is attached to {{post_count}} {{postInflection}}. You're about to delete "{{name}}". This is permanent! No backups, no restores, no magic undo button. We warned you, ok? + {{#if model.post_count}} + WARNING: This tag is attached to {{model.post_count}} {{postInflection}}. You're about to delete "{{model.name}}". This is permanent! No backups, no restores, no magic undo button. We warned you, ok? {{else}} - WARNING: You're about to delete "{{name}}". This is permanent! No backups, no restores, no magic undo button. We warned you, ok? + WARNING: You're about to delete "{{model.name}}". This is permanent! No backups, no restores, no magic undo button. We warned you, ok? {{/if}} {{/gh-modal-dialog}} diff --git a/core/client/templates/post-settings-menu.hbs b/core/client/templates/post-settings-menu.hbs index 930e99f1004c..d5631d8ff00d 100644 --- a/core/client/templates/post-settings-menu.hbs +++ b/core/client/templates/post-settings-menu.hbs @@ -7,7 +7,7 @@
- {{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" description="Add post image" image=image uploaderReference=uploaderReference tagName="section"}} + {{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" description="Add post image" image=model.image uploaderReference=uploaderReference tagName="section"}}
@@ -52,13 +52,13 @@
diff --git a/core/client/templates/posts.hbs b/core/client/templates/posts.hbs index 37f7eeaa312b..f4c82ea2f067 100644 --- a/core/client/templates/posts.hbs +++ b/core/client/templates/posts.hbs @@ -15,15 +15,15 @@
    {{#each post in model itemController="posts/post" itemView="post-item-view" itemTagName="li"}} {{#link-to "posts.post" post class="permalink" alternateActive=view.active title="Edit this post"}} -

    {{post.title}}

    +

    {{post.model.title}}

    diff --git a/core/client/templates/settings/users/index.hbs b/core/client/templates/settings/users/index.hbs index f52a569035fc..9ba935026b19 100644 --- a/core/client/templates/settings/users/index.hbs +++ b/core/client/templates/settings/users/index.hbs @@ -26,10 +26,10 @@
    {{user.email}}
    - {{#if user.pending}} + {{#if user.model.pending}} Invitation not sent - please try again {{else}} - Invitation sent: {{user.created_at}} + Invitation sent: {{user.model.created_at}} {{/if}}
\ No newline at end of file +
diff --git a/core/client/templates/setup.hbs b/core/client/templates/setup.hbs index 623072834925..1904081af36e 100644 --- a/core/client/templates/setup.hbs +++ b/core/client/templates/setup.hbs @@ -35,4 +35,4 @@
- \ No newline at end of file + diff --git a/core/client/templates/signup.hbs b/core/client/templates/signup.hbs index f4dffbc63320..c6b040dd0272 100644 --- a/core/client/templates/signup.hbs +++ b/core/client/templates/signup.hbs @@ -12,17 +12,17 @@
- {{input type="email" name="email" autocorrect="off" value=email }} + {{input type="email" name="email" autocorrect="off" value=model.email }}

Used for important notifications

- {{gh-trim-focus-input type="text" name="name" autofocus="autofocus" autocorrect="off" value=name }} + {{gh-trim-focus-input type="text" name="name" autofocus="autofocus" autocorrect="off" value=model.name }}

The name that you will sign your posts with

- {{input type="password" name="password" autofocus="autofocus" autocorrect="off" value=password }} + {{input type="password" name="password" autofocus="autofocus" autocorrect="off" value=model.password }}

Must be at least 8 characters