Merge pull request #4748 from rwjblue/remove-proxying

Remove ObjectController proxying behavior.
This commit is contained in:
Jason Williams 2015-01-02 15:18:15 -06:00
commit ac5d98e656
38 changed files with 219 additions and 170 deletions

View File

@ -1,4 +1,5 @@
{
"additionalRules": [ "core/test/utils/jscs-rules/*.js" ],
"requireCurlyBraces": [
"if",
"else",

View File

@ -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: {

View File

@ -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;

View File

@ -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

View File

@ -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: {

View File

@ -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'
};

View File

@ -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;
}

View File

@ -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();

View File

@ -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);
});

View File

@ -9,7 +9,7 @@ appStates = {
inactive: 'inactive'
};
SettingsAppController = Ember.ObjectController.extend({
SettingsAppController = Ember.Controller.extend({
appState: appStates.active,
buttonText: '',

View File

@ -1,4 +1,4 @@
var SettingsCodeInjectionController = Ember.ObjectController.extend({
var SettingsCodeInjectionController = Ember.Controller.extend({
actions: {
save: function () {
var self = this;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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');

View File

@ -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 += '&nbsp;<a href="' + path + '">View Post</a>';
@ -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});
}
}

View File

@ -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

View File

@ -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'),

View File

@ -4,7 +4,7 @@
<div class="publish-bar-actions">
<button type="button" class="post-settings" {{action "toggleSettingsMenu"}}></button>
{{view "editor-save-button" id="entry-actions" classNameBindings="isNew:unsaved"}}
{{view "editor-save-button" id="entry-actions" classNameBindings="model.isNew:unsaved"}}
</div>
</div>
</footer>

View File

@ -16,4 +16,4 @@
<a {{action "openModal" "delete-post" this}} href="#">Delete Post</a>
</li>
</ul>
{{/gh-dropdown}}
{{/gh-dropdown}}

View File

@ -6,7 +6,7 @@
<div class="page-content">
<header>
<section class="box entry-title">
{{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}}
</section>
</header>
@ -17,7 +17,7 @@
<a class="markdown-help" href="" {{action "openModal" "markdown"}}><span class="hidden">What is Markdown?</span></a>
</header>
<section id="entry-markdown-content" class="entry-markdown-content">
{{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"}}
</section>
@ -25,11 +25,11 @@
<section {{bind-attr class=":entry-preview :js-entry-preview isPreview:active"}}>
<header {{action "togglePreview" true}} class="floatingheader">
<small>Preview <span class="entry-word-count js-entry-word-count">{{gh-count-words scratch}}</span></small>
<small>Preview <span class="entry-word-count js-entry-word-count">{{gh-count-words model.scratch}}</span></small>
</header>
<section class="entry-preview-content js-entry-preview-content">
{{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"}}
</section>
</section>

View File

@ -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}}
<strong>WARNING:</strong> <span class="red">This tag is attached to {{post_count}} {{postInflection}}.</span> You're about to delete "<strong>{{name}}</strong>". This is permanent! No backups, no restores, no magic undo button. We warned you, ok?
{{#if model.post_count}}
<strong>WARNING:</strong> <span class="red">This tag is attached to {{model.post_count}} {{postInflection}}.</span> You're about to delete "<strong>{{model.name}}</strong>". This is permanent! No backups, no restores, no magic undo button. We warned you, ok?
{{else}}
<strong>WARNING:</strong> You're about to delete "<strong>{{name}}</strong>". This is permanent! No backups, no restores, no magic undo button. We warned you, ok?
<strong>WARNING:</strong> You're about to delete "<strong>{{model.name}}</strong>". This is permanent! No backups, no restores, no magic undo button. We warned you, ok?
{{/if}}
{{/gh-modal-dialog}}

View File

@ -7,7 +7,7 @@
<button class="close icon-x settings-menu-header-action" {{action "closeSettingsMenu"}}><span class="hidden">Close</span></button>
</div>
<div class="settings-menu-content">
{{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"}}
<form>
<div class="form-group">
<label for="url">Post URL</label>
@ -52,13 +52,13 @@
<div class="form-group for-checkbox">
<label class="checkbox" for="static-page" {{action "togglePage" bubbles="false"}}>
{{input type="checkbox" name="static-page" id="static-page" class="post-setting-static-page" checked=page}}
{{input type="checkbox" name="static-page" id="static-page" class="post-setting-static-page" checked=model.page}}
<span class="input-toggle-component"></span>
<p>Turn this post into a static page</p>
</label>
<label class="checkbox" for="featured" {{action "toggleFeatured" bubbles="false"}}>
{{input type="checkbox" name="featured" id="featured" class="post-setting-featured" checked=featured}}
{{input type="checkbox" name="featured" id="featured" class="post-setting-featured" checked=model.featured}}
<span class="input-toggle-component"></span>
<p>Feature this post</p>
</label>

View File

@ -15,15 +15,15 @@
<ol class="posts-list">
{{#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"}}
<h3 class="entry-title">{{post.title}}</h3>
<h3 class="entry-title">{{post.model.title}}</h3>
<section class="entry-meta">
<span class="status">
{{#if post.isPublished}}
{{#if post.page}}
{{#if post.model.page}}
<span class="page">Page</span>
{{else}}
<time datetime="{{unbound post.published_at}}" class="date published">
Published {{gh-format-timeago post.published_at}}
<time datetime="{{unbound post.model.published_at}}" class="date published">
Published {{gh-format-timeago post.model.published_at}}
</time>
{{/if}}
{{else}}

View File

@ -1,13 +1,13 @@
<header class="post-preview-header clearfix">
{{#link-to "posts" tagName="button" class="btn btn-default btn-back"}}Back{{/link-to}}
<h2 class="page-title">Preview</h2>
<button type="button" {{bind-attr class="featured:featured:unfeatured"}} title="Feature this post" {{action "toggleFeatured"}}>
<button type="button" {{bind-attr class="model.featured:featured:unfeatured"}} title="Feature this post" {{action "toggleFeatured"}}>
<span class="hidden">Star</span>
</button>
<small class="post-published-by">
<span class="status">{{#if isPublished}}Published{{else}}Written{{/if}}</span>
<span class="normal">by</span>
<span class="author">{{#if author.name}}{{author.name}}{{else}}{{author.email}}{{/if}}</span>
<span class="author">{{#if model.author.name}}{{model.author.name}}{{else}}{{model.author.email}}{{/if}}</span>
</small>
<section class="post-controls">
{{#link-to "editor.edit" this class="btn btn-default post-edit"}} Edit{{/link-to}}
@ -16,7 +16,7 @@
{{#view "content-preview-content-view" tagName="section"}}
<div class="wrapper">
<h1>{{title}}</h1>
{{gh-format-html html}}
<h1>{{model.title}}</h1>
{{gh-format-html model.html}}
</div>
{{/view}}

View File

@ -9,7 +9,7 @@
<span class="ghost_logo">
<span class="hidden">Ghost</span>
</span>
<span class="version blue">v{{version}}</span>
<span class="version blue">v{{model.version}}</span>
</h1>
<p>A free, open, simple publishing platform</p>
@ -17,13 +17,13 @@
<div class="about-environment">
<dl>
<dt>Version:</dt>
<dd class="about-environment-detail">{{version}}</dd>
<dd class="about-environment-detail">{{model.version}}</dd>
<dt>Environment:</dt>
<dd class="about-environment-detail">{{environment}}</dd>
<dd class="about-environment-detail">{{model.environment}}</dd>
<dt>Database:</dt>
<dd class="about-environment-detail about-environment-database">{{database}}</dd>
<dd class="about-environment-detail about-environment-database">{{model.database}}</dd>
<dt>Mail:</dt>
<dd class="about-environment-detail">{{#if mail}}{{mail}}{{else}}Native{{/if}}</dd>
<dd class="about-environment-detail">{{#if model.mail}}{{model.mail}}{{else}}Native{{/if}}</dd>
</dl>
</div>
<div class="about-help">

View File

@ -10,14 +10,14 @@
<th>Status</th>
</thead>
<tbody>
{{#each app in model itemController="settings/app"}}
{{#each appController in model itemController="settings/app"}}
<tr>
<td>
{{#if app.package}}{{app.package.name}} - {{app.package.version}}{{else}}{{app.name}} - package.json missing :({{/if}}
{{#if appController.model.package}}{{appController.model.package.name}} - {{appController.model.package.version}}{{else}}{{appController.model.name}} - package.json missing :({{/if}}
</td>
<td>
<button type="button" {{action toggleApp app}} {{bind-attr class=":btn :js-button-active activeClass:btn-red inactiveClass:btn-green activeClass:js-button-deactivate"}}>
{{app.buttonText}}
<button type="button" {{action toggleApp appController}} {{bind-attr class=":btn :js-button-active activeClass:btn-red inactiveClass:btn-green activeClass:js-button-deactivate"}}>
{{appController.buttonText}}
</button>
</td>
</tr>

View File

@ -18,13 +18,13 @@
<div class="form-group">
<label for="ghost-head">Blog Header</label>
<p>Code here will be injected to the \{{ghost_head}} helper at the top of your page</p>
{{textarea id="ghost-head" name="codeInjection[ghost_head]" type="text" value=ghost_head}}
{{textarea id="ghost-head" name="codeInjection[ghost_head]" type="text" value=model.ghost_head}}
</div>
<div class="form-group">
<label for="ghost-foot">Blog Footer</label>
<p>Code here will be injected to the \{{ghost_foot}} helper at the bottom of your page</p>
{{textarea id="ghost-foot" name="codeInjection[ghost_foot]" type="text" value=ghost_foot}}
{{textarea id="ghost-foot" name="codeInjection[ghost_foot]" type="text" value=model.ghost_foot}}
</div>
</fieldset>
</form>

View File

@ -12,16 +12,16 @@
<div class="form-group">
<label for="blog-title">Blog Title</label>
{{input id="blog-title" name="general[title]" type="text" value=title}}
{{input id="blog-title" name="general[title]" type="text" value=model.title}}
<p>The name of your blog</p>
</div>
<div class="form-group description-container">
<label for="blog-description">Blog Description</label>
{{textarea id="blog-description" name="general[description]" value=description}}
{{textarea id="blog-description" name="general[description]" value=model.description}}
<p>
Describe what your blog is about
{{gh-count-characters description}}
{{gh-count-characters model.description}}
</p>
</div>
@ -29,8 +29,8 @@
<div class="form-group">
<label for="blog-logo">Blog Logo</label>
{{#if logo}}
<button type="button" class="js-modal-logo" {{action "openModal" "upload" this "logo"}}><img id="blog-logo" {{bind-attr src=logo}} alt="logo"></button>
{{#if model.logo}}
<button type="button" class="js-modal-logo" {{action "openModal" "upload" this "logo"}}><img id="blog-logo" {{bind-attr src=model.logo}} alt="logo"></button>
{{else}}
<button type="button" class="btn btn-green js-modal-logo" {{action "openModal" "upload" this "logo"}}>Upload Image</button>
{{/if}}
@ -39,8 +39,8 @@
<div class="form-group">
<label for="blog-cover">Blog Cover</label>
{{#if cover}}
<button type="button" class="js-modal-cover" {{action "openModal" "upload" this "cover"}}><img id="blog-cover" {{bind-attr src=cover}} alt="cover photo"></button>
{{#if model.cover}}
<button type="button" class="js-modal-cover" {{action "openModal" "upload" this "cover"}}><img id="blog-cover" {{bind-attr src=model.cover}} alt="cover photo"></button>
{{else}}
<button type="button" class="btn btn-green js-modal-cover" {{action "openModal" "upload" this "cover"}}>Upload Image</button>
{{/if}}
@ -50,14 +50,14 @@
<fieldset>
<div class="form-group">
<label for="email-address">Email Address</label>
{{input id="email-address" name="general[email-address]" type="email" value=email autocapitalize="off" autocorrect="off"}}
{{input id="email-address" name="general[email-address]" type="email" value=model.email autocapitalize="off" autocorrect="off"}}
<p>Address to use for admin notifications</p>
</div>
<div class="form-group">
<label for="postsPerPage">Posts per page</label>
{{! `pattern` brings up numeric keypad allowing any number of digits}}
{{input id="postsPerPage" name="general[postsPerPage]" focus-out="checkPostsPerPage" value=postsPerPage min="1" max="1000" type="number" pattern="[0-9]*"}}
{{input id="postsPerPage" name="general[postsPerPage]" focus-out="checkPostsPerPage" value=model.postsPerPage min="1" max="1000" type="number" pattern="[0-9]*"}}
<p>How many posts should be displayed on each page</p>
</div>
@ -79,11 +79,11 @@
content=themes
optionValuePath="content.name"
optionLabelPath="content.label"
value=activeTheme
value=model.activeTheme
selection=selectedTheme}}
</span>
<p>Select a theme for your blog</p>
</div>
</fieldset>
</form>
</section>
</section>

View File

@ -26,10 +26,10 @@
<div class="user-list-item-body">
<span class="name">{{user.email}}</span><br>
{{#if user.pending}}
{{#if user.model.pending}}
<span class="red">Invitation not sent - please try again</span>
{{else}}
<span class="description">Invitation sent: {{user.created_at}}</span>
<span class="description">Invitation sent: {{user.model.created_at}}</span>
{{/if}}
</div>
<aside class="user-list-item-aside">
@ -50,19 +50,19 @@
{{#each user in activeUsers itemController="settings/users/user"}}
{{#link-to 'settings.users.user' user class="user-list-item" }}
<span class="user-list-item-figure" {{bind-attr style=user.image}}>
<span class="hidden">Photo of {{unbound user.name}}</span>
<span class="hidden">Photo of {{unbound user.model.name}}</span>
</span>
<div class="user-list-item-body">
<span class="name">
{{user.name}}
{{user.model.name}}
</span>
<br>
<span class="description">Last seen: {{unbound user.last_login}}</span>
</div>
<aside class="user-list-item-aside">
{{#unless user.isAuthor}}
{{#each role in user.roles}}
{{#unless user.model.isAuthor}}
{{#each role in user.model.roles}}
<span class="role-label {{unbound role.lowerCaseName}}">{{role.name}}</span>
{{/each}}
{{/unless}}

View File

@ -35,7 +35,7 @@
<fieldset class="user-details-top">
<figure class="user-image">
<div id="user-image" class="img" {{bind-attr style=image}} href="#"><span class="hidden">{{name}}"s Picture</span></div>
<div id="user-image" class="img" {{bind-attr style=image}} href="#"><span class="hidden">{{user.name}}"s Picture</span></div>
<button type="button" {{action "openModal" "upload" user "image"}} class="edit-user-image js-modal-image">Edit Picture</button>
</figure>
@ -120,4 +120,4 @@
</form>
</div>
</div>

View File

@ -35,4 +35,4 @@
</footer>
</form>
</div>
</section>
</section>

View File

@ -12,17 +12,17 @@
</header>
<div class="form-group">
<label for="email">Email Address</label>
{{input type="email" name="email" autocorrect="off" value=email }}
{{input type="email" name="email" autocorrect="off" value=model.email }}
<p>Used for important notifications</p>
</div>
<div class="form-group">
<label for="name">Full Name</label>
{{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 }}
<p>The name that you will sign your posts with</p>
</div>
<div class="form-group">
<label for="password">Password</label>
{{input type="password" name="password" autofocus="autofocus" autocorrect="off" value=password }}
{{input type="password" name="password" autofocus="autofocus" autocorrect="off" value=model.password }}
<p>Must be at least 8 characters</p>
</div>
<footer>

View File

@ -1,5 +1,5 @@
Ember.LinkView.reopen({
active: Ember.computed('resolvedParams', 'routeArgs', function () {
active: Ember.computed('loadedParams', 'resolvedParams', 'routeArgs', function () {
var isActive = this._super();
Ember.set(this, 'alternateActive', isActive);

View File

@ -4,16 +4,16 @@ var EditorSaveButtonView = Ember.View.extend({
classNames: ['splitbtn', 'js-publish-splitbutton'],
// Tracks whether we're going to change the state of the post on save
isDangerous: Ember.computed('controller.isPublished', 'controller.willPublish', function () {
return this.get('controller.isPublished') !== this.get('controller.willPublish');
isDangerous: Ember.computed('controller.model.isPublished', 'controller.willPublish', function () {
return this.get('controller.model.isPublished') !== this.get('controller.willPublish');
}),
publishText: Ember.computed('controller.isPublished', function () {
return this.get('controller.isPublished') ? 'Update Post' : 'Publish Now';
publishText: Ember.computed('controller.model.isPublished', function () {
return this.get('controller.model.isPublished') ? 'Update Post' : 'Publish Now';
}),
draftText: Ember.computed('controller.isPublished', function () {
return this.get('controller.isPublished') ? 'Unpublish' : 'Save Draft';
draftText: Ember.computed('controller.model.isPublished', function () {
return this.get('controller.model.isPublished') ? 'Unpublish' : 'Save Draft';
}),
saveText: Ember.computed('controller.willPublish', function () {

View File

@ -4,8 +4,6 @@ var PostTagsInputView = Ember.View.extend({
classNames: 'publish-bar-inner',
classNameBindings: ['hasFocus:focused'],
templateName: 'post-tags-input',
hasFocus: false,
keys: {

View File

@ -290,6 +290,8 @@ CasperTest.begin('Tag editor', 7, function suite(test) {
casper.thenClick('#entry-tags input.tag-input');
casper.then(function () {
casper.sendKeys('#entry-tags input.tag-input', tagName, {keepFocus: true});
});
casper.then(function () {
casper.sendKeys('#entry-tags input.tag-input', casper.page.event.key.Enter);
});

View File

@ -0,0 +1,32 @@
var assert = require('assert');
module.exports = function () {};
module.exports.prototype = {
configure: function (disallowObjectController) {
assert(
typeof disallowObjectController === 'boolean',
'disallowObjectController option requires boolean value'
);
assert(
disallowObjectController === true,
'disallowObjectController option requires true value or should be removed'
);
},
getOptionName: function () {
return 'disallowObjectController';
},
check: function (file, errors) {
var lines = file.getLines();
lines.forEach(function (line, index) {
var location = line.indexOf(/ObjectController.extend/);
if (location !== -1) {
errors.add('Ember.ObjectController is deprecated, please use Ember.Controller and access model properties directly.', index + 1, location + 1);
}
});
}
};