mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-23 19:02:29 +03:00
Ember-cli, Ember, & Ember Data 1.13.x upgrades
closes #5630 - upgrade ember-cli to latest version - upgrade ember to latest 1.13.x release - upgrade ember data to latest 1.13.x release - update custom adapters and serialisers for new internal JSON-API compatible formats [(docs)][1] - update all store queries to use new standardised query methods [(docs)][2] - add ember-data-filter addon ready for store.filter removal in ember-data 2.0 [(docs)][3] - remove use of prototype extensions for computed properties and observers - consolidate pagination into a single route mixin and simplify configuration [1]: http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html#toc_transition-to-the-new-jsonserializer-and-restserializer-apis [2]: http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html#toc_simplified-find-methods [3]: http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html#toc_ds-store-filter-moved-to-an-addon
This commit is contained in:
parent
5c9a824d53
commit
5c0b63f300
@ -5,7 +5,7 @@ export default DS.RESTAdapter.extend({
|
||||
host: window.location.origin,
|
||||
namespace: ghostPaths().apiRoot.slice(1),
|
||||
|
||||
findQuery: function (store, type, query) {
|
||||
query: function (store, type, query) {
|
||||
var id;
|
||||
|
||||
if (query.id) {
|
||||
|
@ -2,7 +2,7 @@ import Ember from 'ember';
|
||||
import BaseAdapter from 'ghost/adapters/base';
|
||||
|
||||
// EmbeddedRelationAdapter will augment the query object in calls made to
|
||||
// DS.Store#find, findQuery, and findAll with the correct "includes"
|
||||
// DS.Store#findRecord, findAll, query, and queryRecord with the correct "includes"
|
||||
// (?include=relatedType) by introspecting on the provided subclass of the DS.Model.
|
||||
// In cases where there is no query object (DS.Model#save, or simple finds) the URL
|
||||
// that is built will be augmented with ?include=... where appropriate.
|
||||
@ -12,58 +12,68 @@ import BaseAdapter from 'ghost/adapters/base';
|
||||
// roles: DS.hasMany('role', { embedded: 'always' }) => ?include=roles
|
||||
|
||||
export default BaseAdapter.extend({
|
||||
find: function (store, type, id) {
|
||||
return this.ajax(this.buildIncludeURL(store, type, id), 'GET');
|
||||
find: function (store, type, id, snapshot) {
|
||||
return this.ajax(this.buildIncludeURL(store, type.modelName, id, snapshot, 'find'), 'GET');
|
||||
},
|
||||
|
||||
findQuery: function (store, type, query) {
|
||||
return this._super(store, type, this.buildQuery(store, type, query));
|
||||
findRecord: function (store, type, id, snapshot) {
|
||||
return this.ajax(this.buildIncludeURL(store, type.modelName, id, snapshot, 'findRecord'), 'GET');
|
||||
},
|
||||
|
||||
findAll: function (store, type, sinceToken) {
|
||||
var query = {};
|
||||
var query, url;
|
||||
|
||||
if (sinceToken) {
|
||||
query.since = sinceToken;
|
||||
query = {since: sinceToken};
|
||||
}
|
||||
|
||||
return this.findQuery(store, type, query);
|
||||
url = this.buildIncludeURL(store, type.modelName, null, null, 'findAll');
|
||||
|
||||
return this.ajax(url, 'GET', {data: query});
|
||||
},
|
||||
|
||||
createRecord: function (store, type, record) {
|
||||
return this.saveRecord(store, type, record, {method: 'POST'});
|
||||
query: function (store, type, query) {
|
||||
return this._super(store, type, this.buildQuery(store, type.modelName, query));
|
||||
},
|
||||
|
||||
updateRecord: function (store, type, record) {
|
||||
queryRecord: function (store, type, query) {
|
||||
return this._super(store, type, this.buildQuery(store, type.modelName, query));
|
||||
},
|
||||
|
||||
createRecord: function (store, type, snapshot) {
|
||||
return this.saveRecord(store, type, snapshot, {method: 'POST'});
|
||||
},
|
||||
|
||||
updateRecord: function (store, type, snapshot) {
|
||||
var options = {
|
||||
method: 'PUT',
|
||||
id: Ember.get(record, 'id')
|
||||
id: Ember.get(snapshot, 'id')
|
||||
};
|
||||
|
||||
return this.saveRecord(store, type, record, options);
|
||||
return this.saveRecord(store, type, snapshot, options);
|
||||
},
|
||||
|
||||
saveRecord: function (store, type, record, options) {
|
||||
saveRecord: function (store, type, snapshot, options) {
|
||||
options = options || {};
|
||||
|
||||
var url = this.buildIncludeURL(store, type, options.id),
|
||||
payload = this.preparePayload(store, type, record);
|
||||
var url = this.buildIncludeURL(store, type.modelName, options.id, snapshot, 'createRecord'),
|
||||
payload = this.preparePayload(store, type, snapshot);
|
||||
|
||||
return this.ajax(url, options.method, payload);
|
||||
},
|
||||
|
||||
preparePayload: function (store, type, record) {
|
||||
preparePayload: function (store, type, snapshot) {
|
||||
var serializer = store.serializerFor(type.modelName),
|
||||
payload = {};
|
||||
|
||||
serializer.serializeIntoHash(payload, type, record);
|
||||
serializer.serializeIntoHash(payload, type, snapshot);
|
||||
|
||||
return {data: payload};
|
||||
},
|
||||
|
||||
buildIncludeURL: function (store, type, id) {
|
||||
var url = this.buildURL(type.modelName, id),
|
||||
includes = this.getEmbeddedRelations(store, type);
|
||||
buildIncludeURL: function (store, modelName, id, snapshot, requestType, query) {
|
||||
var url = this.buildURL(modelName, id, snapshot, requestType, query),
|
||||
includes = this.getEmbeddedRelations(store, modelName);
|
||||
|
||||
if (includes.length) {
|
||||
url += '?include=' + includes.join(',');
|
||||
@ -72,8 +82,8 @@ export default BaseAdapter.extend({
|
||||
return url;
|
||||
},
|
||||
|
||||
buildQuery: function (store, type, options) {
|
||||
var toInclude = this.getEmbeddedRelations(store, type),
|
||||
buildQuery: function (store, modelName, options) {
|
||||
var toInclude = this.getEmbeddedRelations(store, modelName),
|
||||
query = options || {},
|
||||
deDupe = {};
|
||||
|
||||
@ -102,8 +112,8 @@ export default BaseAdapter.extend({
|
||||
return query;
|
||||
},
|
||||
|
||||
getEmbeddedRelations: function (store, type) {
|
||||
var model = store.modelFor(type),
|
||||
getEmbeddedRelations: function (store, modelName) {
|
||||
var model = store.modelFor(modelName),
|
||||
ret = [];
|
||||
|
||||
// Iterate through the model's relationships and build a list
|
||||
|
@ -3,5 +3,9 @@ import ApplicationAdapter from 'ghost/adapters/application';
|
||||
export default ApplicationAdapter.extend({
|
||||
find: function (store, type, id) {
|
||||
return this.findQuery(store, type, {id: id, status: 'all'});
|
||||
},
|
||||
|
||||
findAll: function (store, type, id) {
|
||||
return this.query(store, type, {id: id, status: 'all'});
|
||||
}
|
||||
});
|
||||
|
@ -6,9 +6,9 @@ export default Ember.Component.extend({
|
||||
active: false,
|
||||
linkClasses: null,
|
||||
|
||||
unfocusLink: function () {
|
||||
unfocusLink: Ember.on('click', function () {
|
||||
this.$('a').blur();
|
||||
}.on('click'),
|
||||
}),
|
||||
|
||||
actions: {
|
||||
setActive: function (value) {
|
||||
|
@ -41,7 +41,7 @@ export default Ember.Component.extend({
|
||||
|
||||
_loadPosts: function () {
|
||||
var store = this.get('_store'),
|
||||
postsUrl = store.adapterFor('post').urlForFindQuery({}, 'post') + '/',
|
||||
postsUrl = store.adapterFor('post').urlForQuery({}, 'post') + '/',
|
||||
postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all', staticPages: 'all'},
|
||||
content = this.get('content'),
|
||||
self = this;
|
||||
@ -61,7 +61,7 @@ export default Ember.Component.extend({
|
||||
|
||||
_loadUsers: function () {
|
||||
var store = this.get('_store'),
|
||||
usersUrl = store.adapterFor('user').urlForFindQuery({}, 'user') + '/',
|
||||
usersUrl = store.adapterFor('user').urlForQuery({}, 'user') + '/',
|
||||
usersQuery = {fields: 'name,slug', limit: 'all'},
|
||||
content = this.get('content'),
|
||||
self = this;
|
||||
|
@ -13,7 +13,7 @@ export default Ember.Component.extend({
|
||||
// anchor behaviors or ignored
|
||||
href: Ember.String.htmlSafe('javascript:;'),
|
||||
|
||||
scrollTo: function () {
|
||||
scrollTo: Ember.on('click', function () {
|
||||
var anchor = this.get('anchor'),
|
||||
$el = Ember.$(anchor);
|
||||
|
||||
@ -30,5 +30,5 @@ export default Ember.Component.extend({
|
||||
$(this).removeAttr('tabindex');
|
||||
}).focus();
|
||||
}
|
||||
}.on('click')
|
||||
})
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ export default Ember.Component.extend({
|
||||
return this.get('tabsManager.activeTab') === this;
|
||||
}),
|
||||
|
||||
index: Ember.computed('tabsManager.tabs.@each', function () {
|
||||
index: Ember.computed('tabsManager.tabs.[]', function () {
|
||||
return this.get('tabsManager.tabs').indexOf(this);
|
||||
}),
|
||||
|
||||
|
@ -4,7 +4,7 @@ export default Ember.Controller.extend(Ember.PromiseProxyMixin, {
|
||||
init: function () {
|
||||
var promise;
|
||||
|
||||
promise = this.store.find('setting', {type: 'blog,theme'}).then(function (settings) {
|
||||
promise = this.store.query('setting', {type: 'blog,theme'}).then(function (settings) {
|
||||
return settings.get('firstObject');
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,7 @@ export default Ember.Controller.extend({
|
||||
status: 'all'
|
||||
};
|
||||
|
||||
promise = this.store.find('post', query).then(function (results) {
|
||||
promise = this.store.query('post', query).then(function (results) {
|
||||
return results.meta.pagination.total;
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,7 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
authorRole: null,
|
||||
|
||||
roles: Ember.computed(function () {
|
||||
return this.store.find('role', {permissions: 'assign'});
|
||||
return this.store.query('role', {permissions: 'assign'});
|
||||
}),
|
||||
|
||||
// Used to set the initial value for the dropdown
|
||||
@ -53,7 +53,7 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
this.set('email', '');
|
||||
this.set('role', self.get('authorRole'));
|
||||
|
||||
this.store.find('user').then(function (result) {
|
||||
this.store.findAll('user', {reload: true}).then(function (result) {
|
||||
var invitedUser = result.findBy('email', email);
|
||||
|
||||
if (invitedUser) {
|
||||
|
@ -32,11 +32,11 @@ export default Ember.Controller.extend({
|
||||
model.deleteRecord();
|
||||
} else {
|
||||
// roll back changes on model props
|
||||
model.rollback();
|
||||
model.rollbackAttributes();
|
||||
}
|
||||
|
||||
// setting isDirty to false here allows willTransition on the editor route to succeed
|
||||
editorController.set('isDirty', false);
|
||||
// setting hasDirtyAttributes to false here allows willTransition on the editor route to succeed
|
||||
editorController.set('hasDirtyAttributes', false);
|
||||
|
||||
// since the transition is now certain to complete, we can unset window.onbeforeunload here
|
||||
window.onbeforeunload = null;
|
||||
|
@ -26,8 +26,8 @@ export default Ember.Controller.extend({
|
||||
// because store.pushPayload is not working with embedded relations
|
||||
if (response && Ember.isArray(response.users)) {
|
||||
response.users.forEach(function (userJSON) {
|
||||
var user = self.store.getById('user', userJSON.id),
|
||||
role = self.store.getById('role', userJSON.roles[0].id);
|
||||
var user = self.store.peekRecord('user', userJSON.id),
|
||||
role = self.store.peekRecord('role', userJSON.roles[0].id);
|
||||
|
||||
user.set('role', role);
|
||||
});
|
||||
|
@ -29,7 +29,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
// Loaded asynchronously, so must use promise proxies.
|
||||
var deferred = {};
|
||||
|
||||
deferred.promise = this.store.find('user', {limit: 'all'}).then(function (users) {
|
||||
deferred.promise = this.store.query('user', {limit: 'all'}).then(function (users) {
|
||||
return users.rejectBy('id', 'me').sortBy('name');
|
||||
}).then(function (users) {
|
||||
return users.filter(function (user) {
|
||||
@ -217,7 +217,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
|
||||
this.get('model').save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -234,7 +234,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
|
||||
this.get('model').save(this.get('saveOptions')).catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -299,7 +299,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
return self.get('model').save();
|
||||
}).catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -355,7 +355,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
|
||||
this.get('model').save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -412,7 +412,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
|
||||
this.get('model').save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -427,7 +427,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
|
||||
this.get('model').save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -467,7 +467,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
model.save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.set('selectedAuthor', author);
|
||||
model.rollback();
|
||||
model.rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import Ember from 'ember';
|
||||
import PaginationControllerMixin from 'ghost/mixins/pagination-controller';
|
||||
|
||||
// a custom sort function is needed in order to sort the posts list the same way the server would:
|
||||
// status: ASC
|
||||
@ -64,7 +63,8 @@ function publishedAtCompare(item1, item2) {
|
||||
return Ember.compare(published1.valueOf(), published2.valueOf());
|
||||
}
|
||||
|
||||
export default Ember.Controller.extend(PaginationControllerMixin, {
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
// See PostsRoute's shortcuts
|
||||
postListFocused: Ember.computed.equal('keyboardFocus', 'postList'),
|
||||
postContentFocused: Ember.computed.equal('keyboardFocus', 'postContent'),
|
||||
@ -75,12 +75,6 @@ export default Ember.Controller.extend(PaginationControllerMixin, {
|
||||
return postsArray.sort(comparator);
|
||||
}),
|
||||
|
||||
init: function () {
|
||||
// let the PaginationControllerMixin know what type of model we will be paginating
|
||||
// this is necessary because we do not have access to the model inside the Controller::init method
|
||||
this._super({modelType: 'post'});
|
||||
},
|
||||
|
||||
actions: {
|
||||
showPostContent: function (post) {
|
||||
if (!post) {
|
||||
|
@ -59,7 +59,7 @@ export default Ember.Controller.extend(SettingsSaveMixin, {
|
||||
|
||||
generatePassword: Ember.observer('model.isPrivate', function () {
|
||||
this.get('model.errors').remove('password');
|
||||
if (this.get('model.isPrivate') && this.get('model.isDirty')) {
|
||||
if (this.get('model.isPrivate') && this.get('model.hasDirtyAttributes')) {
|
||||
this.get('model').set('password', randomPassword());
|
||||
}
|
||||
}),
|
||||
|
@ -24,7 +24,7 @@ export default Ember.Controller.extend({
|
||||
|
||||
this.get('model').save().catch(function (errors) {
|
||||
self.showErrors(errors);
|
||||
self.get('model').rollback();
|
||||
self.get('model').rollbackAttributes();
|
||||
});
|
||||
},
|
||||
|
||||
@ -51,7 +51,7 @@ export default Ember.Controller.extend({
|
||||
// Clear the store, so that all the new data gets fetched correctly.
|
||||
self.store.unloadAll();
|
||||
// Reload currentUser and set session
|
||||
self.set('session.user', self.store.find('user', currentUserId));
|
||||
self.set('session.user', self.store.findRecord('user', currentUserId));
|
||||
// TODO: keep as notification, add link to view content
|
||||
notifications.showNotification('Import successful.');
|
||||
}).catch(function (response) {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import Ember from 'ember';
|
||||
import PaginationMixin from 'ghost/mixins/pagination-controller';
|
||||
import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller';
|
||||
import boundOneWay from 'ghost/utils/bound-one-way';
|
||||
|
||||
export default Ember.Controller.extend(PaginationMixin, SettingsMenuMixin, {
|
||||
export default Ember.Controller.extend(SettingsMenuMixin, {
|
||||
tags: Ember.computed.alias('model'),
|
||||
|
||||
activeTag: null,
|
||||
@ -13,12 +12,6 @@ export default Ember.Controller.extend(PaginationMixin, SettingsMenuMixin, {
|
||||
activeTagMetaTitleScratch: boundOneWay('activeTag.meta_title'),
|
||||
activeTagMetaDescriptionScratch: boundOneWay('activeTag.meta_description'),
|
||||
|
||||
init: function (options) {
|
||||
options = options || {};
|
||||
options.modelType = 'tag';
|
||||
this._super(options);
|
||||
},
|
||||
|
||||
application: Ember.inject.controller(),
|
||||
config: Ember.inject.service(),
|
||||
notifications: Ember.inject.service(),
|
||||
|
@ -119,7 +119,7 @@ export default Ember.Controller.extend({
|
||||
}),
|
||||
|
||||
authorRole: Ember.computed(function () {
|
||||
return this.store.find('role').then(function (roles) {
|
||||
return this.store.findAll('role', {reload: true}).then(function (roles) {
|
||||
return roles.findBy('name', 'Author');
|
||||
});
|
||||
}),
|
||||
|
@ -1,12 +1,6 @@
|
||||
import Ember from 'ember';
|
||||
import PaginationControllerMixin from 'ghost/mixins/pagination-controller';
|
||||
|
||||
export default Ember.Controller.extend(PaginationControllerMixin, {
|
||||
init: function () {
|
||||
// let the PaginationControllerMixin know what type of model we will be paginating
|
||||
// this is necessary because we do not have access to the model inside the Controller::init method
|
||||
this._super({modelType: 'user'});
|
||||
},
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
users: Ember.computed.alias('model'),
|
||||
|
||||
|
@ -83,7 +83,7 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
}),
|
||||
|
||||
roles: Ember.computed(function () {
|
||||
return this.store.find('role', {permissions: 'assign'});
|
||||
return this.store.query('role', {permissions: 'assign'});
|
||||
}),
|
||||
|
||||
actions: {
|
||||
|
@ -1,15 +1,15 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
var el = document.createElement('span'),
|
||||
length,
|
||||
content;
|
||||
|
||||
if (!arr || !arr.length) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
content = arr[0] || '';
|
||||
content = params[0] || '';
|
||||
length = content.length;
|
||||
|
||||
el.className = 'word-count';
|
||||
|
@ -1,17 +1,17 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
var el = document.createElement('span'),
|
||||
content,
|
||||
maxCharacters,
|
||||
length;
|
||||
|
||||
if (!arr || arr.length < 2) {
|
||||
if (!params || params.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
content = arr[0] || '';
|
||||
maxCharacters = arr[1];
|
||||
content = params[0] || '';
|
||||
maxCharacters = params[1];
|
||||
length = content.length;
|
||||
|
||||
el.className = 'word-count';
|
||||
|
@ -1,15 +1,15 @@
|
||||
import Ember from 'ember';
|
||||
import counter from 'ghost/utils/word-count';
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
if (!arr || !arr.length) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var markdown,
|
||||
count;
|
||||
|
||||
markdown = arr[0] || '';
|
||||
markdown = params[0] || '';
|
||||
|
||||
if (/^\s*$/.test(markdown)) {
|
||||
return '0 words';
|
||||
|
@ -2,12 +2,12 @@ import Ember from 'ember';
|
||||
/* global html_sanitize*/
|
||||
import cajaSanitizers from 'ghost/utils/caja-sanitizers';
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
if (!arr || !arr.length) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var escapedhtml = arr[0] || '';
|
||||
var escapedhtml = params[0] || '';
|
||||
|
||||
// replace script and iFrame
|
||||
escapedhtml = escapedhtml.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||
|
@ -4,13 +4,13 @@ import cajaSanitizers from 'ghost/utils/caja-sanitizers';
|
||||
|
||||
var showdown = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm', 'footnotes', 'highlight']});
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
if (!arr || !arr.length) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var escapedhtml = '',
|
||||
markdown = arr[0] || '';
|
||||
markdown = params[0] || '';
|
||||
|
||||
// convert markdown to HTML
|
||||
escapedhtml = showdown.makeHtml(markdown);
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(function (arr /* hashParams */) {
|
||||
if (!arr || !arr.length) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
if (!params || !params.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var timeago = arr[0];
|
||||
var timeago = params[0];
|
||||
|
||||
return moment(timeago).fromNow();
|
||||
// stefanpenner says cool for small number of timeagos.
|
||||
|
@ -8,7 +8,7 @@ import ghostPaths from 'ghost/utils/ghost-paths';
|
||||
// {{gh-path 'api'}} for Ghost's api root (/myblog/ghost/api/v0.1/)
|
||||
// {{gh-path 'admin' '/assets/hi.png'}} for resolved url (/myblog/ghost/assets/hi.png)
|
||||
|
||||
function ghostPathsHelper(params/*, hash */) {
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
var base,
|
||||
paths = ghostPaths(),
|
||||
[path, url] = params;
|
||||
@ -50,6 +50,4 @@ function ghostPathsHelper(params/*, hash */) {
|
||||
}
|
||||
|
||||
return Ember.String.htmlSafe(base);
|
||||
}
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(ghostPathsHelper);
|
||||
});
|
||||
|
@ -8,4 +8,6 @@ export function ghUserCanAdmin(params) {
|
||||
return !!(params[0].get('isOwner') || params[0].get('isAdmin'));
|
||||
}
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(ghUserCanAdmin);
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
return ghUserCanAdmin(params);
|
||||
});
|
||||
|
@ -1,9 +1,11 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export function isEqual(params/*, hash*/) {
|
||||
export function isEqual(params) {
|
||||
var [lhs, rhs] = params;
|
||||
|
||||
return lhs === rhs;
|
||||
}
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(isEqual);
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
return isEqual(params);
|
||||
});
|
||||
|
@ -1,7 +1,9 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export function isNot(params/*, hash*/) {
|
||||
export function isNot(params) {
|
||||
return !params;
|
||||
}
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(isNot);
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
return isNot(params);
|
||||
});
|
||||
|
@ -1,9 +1,11 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export function readPath(params/*, hash*/) {
|
||||
export function readPath(params) {
|
||||
var [obj, path] = params;
|
||||
|
||||
return Ember.get(obj, path);
|
||||
}
|
||||
|
||||
export default Ember.HTMLBars.makeBoundHelper(readPath);
|
||||
export default Ember.Helper.helper(function (params) {
|
||||
return readPath(params);
|
||||
});
|
||||
|
@ -3,8 +3,8 @@ import GhostOauth2Authenticator from 'ghost/authenticators/oauth2';
|
||||
export default {
|
||||
name: 'ghost-authentictor',
|
||||
|
||||
initialize: function (container) {
|
||||
container.register(
|
||||
initialize: function (registry, application) {
|
||||
application.register(
|
||||
'ghost-authenticator:oauth2-password-grant',
|
||||
GhostOauth2Authenticator
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ var trailingHistory = Ember.HistoryLocation.extend({
|
||||
export default {
|
||||
name: 'registerTrailingLocationHistory',
|
||||
|
||||
initialize: function (container, application) {
|
||||
initialize: function (registry, application) {
|
||||
application.register('location:trailing-history', trailingHistory);
|
||||
}
|
||||
};
|
||||
|
@ -1,16 +1,18 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export function initialize(instance) {
|
||||
var store = instance.container.lookup('service:store'),
|
||||
Session = instance.container.lookup('simple-auth-session:main');
|
||||
|
||||
Session.reopen({
|
||||
user: Ember.computed(function () {
|
||||
return store.findRecord('user', 'me');
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'authentication',
|
||||
|
||||
initialize: function (instance) {
|
||||
var store = instance.container.lookup('store:main'),
|
||||
Session = instance.container.lookup('simple-auth-session:main');
|
||||
|
||||
Session.reopen({
|
||||
user: Ember.computed(function () {
|
||||
return store.find('user', 'me');
|
||||
})
|
||||
});
|
||||
}
|
||||
after: 'ember-data',
|
||||
initialize: initialize
|
||||
};
|
||||
|
@ -4,8 +4,8 @@ import boundOneWay from 'ghost/utils/bound-one-way';
|
||||
import imageManager from 'ghost/utils/ed-image-manager';
|
||||
|
||||
// this array will hold properties we need to watch
|
||||
// to know if the model has been changed (`controller.isDirty`)
|
||||
var watchedProps = ['model.scratch', 'model.titleScratch', 'model.isDirty', 'model.tags.[]'];
|
||||
// to know if the model has been changed (`controller.hasDirtyAttributes`)
|
||||
var watchedProps = ['model.scratch', 'model.titleScratch', 'model.hasDirtyAttributes', 'model.tags.[]'];
|
||||
|
||||
PostModel.eachAttribute(function (name) {
|
||||
watchedProps.push('model.' + name);
|
||||
@ -27,7 +27,7 @@ export default Ember.Mixin.create({
|
||||
this._super();
|
||||
|
||||
window.onbeforeunload = function () {
|
||||
return self.get('isDirty') ? self.unloadDirtyMessage() : null;
|
||||
return self.get('hasDirtyAttributes') ? self.unloadDirtyMessage() : null;
|
||||
};
|
||||
},
|
||||
|
||||
@ -61,8 +61,8 @@ export default Ember.Mixin.create({
|
||||
*/
|
||||
willPublish: boundOneWay('model.isPublished'),
|
||||
|
||||
// set by the editor route and `isDirty`. useful when checking
|
||||
// whether the number of tags has changed for `isDirty`.
|
||||
// set by the editor route and `hasDirtyAttributes`. useful when checking
|
||||
// whether the number of tags has changed for `hasDirtyAttributes`.
|
||||
previousTagNames: null,
|
||||
|
||||
tagNames: Ember.computed('model.tags.@each.name', function () {
|
||||
@ -102,23 +102,23 @@ export default Ember.Mixin.create({
|
||||
// rather than in all other places save is called
|
||||
model.updateTags();
|
||||
|
||||
// set previousTagNames to current tagNames for isDirty check
|
||||
// set previousTagNames to current tagNames for hasDirtyAttributes check
|
||||
this.set('previousTagNames', this.get('tagNames'));
|
||||
|
||||
// `updateTags` triggers `isDirty => true`.
|
||||
// `updateTags` triggers `hasDirtyAttributes => true`.
|
||||
// for a saved model it would otherwise be false.
|
||||
|
||||
// if the two "scratch" properties (title and content) match the model, then
|
||||
// it's ok to set isDirty to false
|
||||
// it's ok to set hasDirtyAttributes to false
|
||||
if (model.get('titleScratch') === model.get('title') &&
|
||||
model.get('scratch') === model.get('markdown')) {
|
||||
this.set('isDirty', false);
|
||||
this.set('hasDirtyAttributes', false);
|
||||
}
|
||||
},
|
||||
|
||||
// an ugly hack, but necessary to watch all the model's properties
|
||||
// and more, without having to be explicit and do it manually
|
||||
isDirty: Ember.computed.apply(Ember, watchedProps.concat({
|
||||
hasDirtyAttributes: Ember.computed.apply(Ember, watchedProps.concat({
|
||||
get: function () {
|
||||
var model = this.get('model'),
|
||||
markdown = model.get('markdown'),
|
||||
@ -147,10 +147,10 @@ export default Ember.Mixin.create({
|
||||
return true;
|
||||
}
|
||||
|
||||
// models created on the client always return `isDirty: true`,
|
||||
// models created on the client always return `hasDirtyAttributes: true`,
|
||||
// so we need to see which properties have actually changed.
|
||||
if (model.get('isNew')) {
|
||||
changedAttributes = Ember.keys(model.changedAttributes());
|
||||
changedAttributes = Object.keys(model.changedAttributes());
|
||||
|
||||
if (changedAttributes.length) {
|
||||
return true;
|
||||
@ -160,10 +160,10 @@ export default Ember.Mixin.create({
|
||||
}
|
||||
|
||||
// even though we use the `scratch` prop to show edits,
|
||||
// which does *not* change the model's `isDirty` property,
|
||||
// `isDirty` will tell us if the other props have changed,
|
||||
// which does *not* change the model's `hasDirtyAttributes` property,
|
||||
// `hasDirtyAttributes` will tell us if the other props have changed,
|
||||
// as long as the model is not new (model.isNew === false).
|
||||
return model.get('isDirty');
|
||||
return model.get('hasDirtyAttributes');
|
||||
},
|
||||
set: function (key, value) {
|
||||
return value;
|
||||
|
@ -33,9 +33,9 @@ export default Ember.Mixin.create(styleBody, ShortcutsRoute, {
|
||||
willTransition: function (transition) {
|
||||
var controller = this.get('controller'),
|
||||
scratch = controller.get('model.scratch'),
|
||||
controllerIsDirty = controller.get('isDirty'),
|
||||
controllerIsDirty = controller.get('hasDirtyAttributes'),
|
||||
model = controller.get('model'),
|
||||
state = model.getProperties('isDeleted', 'isSaving', 'isDirty', 'isNew'),
|
||||
state = model.getProperties('isDeleted', 'isSaving', 'hasDirtyAttributes', 'isNew'),
|
||||
fromNewToEdit,
|
||||
deletedWithoutChanges;
|
||||
|
||||
@ -57,7 +57,7 @@ export default Ember.Mixin.create(styleBody, ShortcutsRoute, {
|
||||
transition.intent.contexts[0].id === model.get('id');
|
||||
|
||||
deletedWithoutChanges = state.isDeleted &&
|
||||
(state.isSaving || !state.isDirty);
|
||||
(state.isSaving || !state.hasDirtyAttributes);
|
||||
|
||||
if (!fromNewToEdit && !deletedWithoutChanges && controllerIsDirty) {
|
||||
transition.abort();
|
||||
@ -99,7 +99,7 @@ export default Ember.Mixin.create(styleBody, ShortcutsRoute, {
|
||||
|
||||
attachModelHooks: function (controller, model) {
|
||||
// this will allow us to track when the model is saved and update the controller
|
||||
// so that we can be sure controller.isDirty is correct, without having to update the
|
||||
// so that we can be sure controller.hasDirtyAttributes is correct, without having to update the
|
||||
// controller on each instance of `model.save()`.
|
||||
//
|
||||
// another reason we can't do this on `model.save().then()` is because the post-settings-menu
|
||||
|
@ -1,61 +0,0 @@
|
||||
import Ember from 'ember';
|
||||
import getRequestErrorMessage from 'ghost/utils/ajax';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
notifications: Ember.inject.service(),
|
||||
|
||||
// set from PaginationRouteMixin
|
||||
paginationSettings: null,
|
||||
|
||||
// indicates whether we're currently loading the next page
|
||||
isLoading: null,
|
||||
|
||||
/**
|
||||
* Takes an ajax response, concatenates any error messages, then generates an error notification.
|
||||
* @param {jqXHR} response The jQuery ajax reponse object.
|
||||
* @return
|
||||
*/
|
||||
reportLoadError: function (response) {
|
||||
var message = 'A problem was encountered while loading more records';
|
||||
|
||||
if (response) {
|
||||
// Get message from response
|
||||
message += ': ' + getRequestErrorMessage(response, true);
|
||||
} else {
|
||||
message += '.';
|
||||
}
|
||||
|
||||
this.get('notifications').showAlert(message, {type: 'error'});
|
||||
},
|
||||
|
||||
actions: {
|
||||
/**
|
||||
* Loads the next paginated page of posts into the ember-data store. Will cause the posts list UI to update.
|
||||
* @return
|
||||
*/
|
||||
loadNextPage: function () {
|
||||
var self = this,
|
||||
store = this.get('store'),
|
||||
recordType = this.get('model').get('type'),
|
||||
metadata = this.store.metadataFor(recordType),
|
||||
nextPage = metadata.pagination && metadata.pagination.next,
|
||||
paginationSettings = this.get('paginationSettings');
|
||||
|
||||
if (nextPage) {
|
||||
this.set('isLoading', true);
|
||||
this.set('paginationSettings.page', nextPage);
|
||||
|
||||
store.find(recordType, paginationSettings).then(function () {
|
||||
self.set('isLoading', false);
|
||||
}, function (response) {
|
||||
self.reportLoadError(response);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
resetPagination: function () {
|
||||
this.set('paginationSettings.page', 1);
|
||||
this.store.setMetadataFor('tag', {pagination: undefined});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,4 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
import getRequestErrorMessage from 'ghost/utils/ajax';
|
||||
|
||||
var defaultPaginationSettings = {
|
||||
page: 1,
|
||||
@ -6,21 +7,87 @@ var defaultPaginationSettings = {
|
||||
};
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
notifications: Ember.inject.service(),
|
||||
|
||||
paginationModel: null,
|
||||
paginationSettings: null,
|
||||
paginationMeta: null,
|
||||
|
||||
init: function () {
|
||||
var paginationSettings = this.get('paginationSettings'),
|
||||
settings = Ember.$.extend({}, defaultPaginationSettings, paginationSettings);
|
||||
|
||||
this._super(...arguments);
|
||||
this.set('paginationSettings', settings);
|
||||
this.set('paginationMeta', {});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets up pagination details
|
||||
* @param {object} settings specifies additional pagination details
|
||||
* Takes an ajax response, concatenates any error messages, then generates an error notification.
|
||||
* @param {jqXHR} response The jQuery ajax reponse object.
|
||||
* @return
|
||||
*/
|
||||
setupPagination: function (settings) {
|
||||
settings = settings || {};
|
||||
for (var key in defaultPaginationSettings) {
|
||||
if (defaultPaginationSettings.hasOwnProperty(key)) {
|
||||
if (!settings.hasOwnProperty(key)) {
|
||||
settings[key] = defaultPaginationSettings[key];
|
||||
}
|
||||
}
|
||||
reportLoadError: function (response) {
|
||||
var message = 'A problem was encountered while loading more records';
|
||||
|
||||
if (response) {
|
||||
// Get message from response
|
||||
message += ': ' + getRequestErrorMessage(response, true);
|
||||
} else {
|
||||
message += '.';
|
||||
}
|
||||
|
||||
this.set('paginationSettings', settings);
|
||||
this.controller.set('paginationSettings', settings);
|
||||
this.get('notifications').showAlert(message, {type: 'error'});
|
||||
},
|
||||
|
||||
loadFirstPage: function () {
|
||||
var paginationSettings = this.get('paginationSettings'),
|
||||
modelName = this.get('paginationModel'),
|
||||
self = this;
|
||||
|
||||
paginationSettings.page = 1;
|
||||
|
||||
return this.get('store').query(modelName, paginationSettings).then(function (results) {
|
||||
self.set('paginationMeta', results.meta);
|
||||
return results;
|
||||
}, function (response) {
|
||||
self.reportLoadError(response);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadFirstPage: function () {
|
||||
return this.loadFirstPage();
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the next paginated page of posts into the ember-data store. Will cause the posts list UI to update.
|
||||
* @return
|
||||
*/
|
||||
loadNextPage: function () {
|
||||
var self = this,
|
||||
store = this.get('store'),
|
||||
modelName = this.get('paginationModel'),
|
||||
metadata = this.get('paginationMeta'),
|
||||
nextPage = metadata.pagination && metadata.pagination.next,
|
||||
paginationSettings = this.get('paginationSettings');
|
||||
|
||||
if (nextPage) {
|
||||
this.set('isLoading', true);
|
||||
this.set('paginationSettings.page', nextPage);
|
||||
|
||||
store.query(modelName, paginationSettings).then(function (results) {
|
||||
self.set('isLoading', false);
|
||||
self.set('paginationMeta', results.meta);
|
||||
return results;
|
||||
}, function (response) {
|
||||
self.reportLoadError(response);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
resetPagination: function () {
|
||||
this.set('paginationSettings.page', 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ export default Ember.Mixin.create({
|
||||
var self = this,
|
||||
shortcuts = this.get('shortcuts');
|
||||
|
||||
Ember.keys(shortcuts).forEach(function (shortcut) {
|
||||
Object.keys(shortcuts).forEach(function (shortcut) {
|
||||
var scope = shortcuts[shortcut].scope || 'default',
|
||||
action = shortcuts[shortcut],
|
||||
options;
|
||||
@ -68,7 +68,7 @@ export default Ember.Mixin.create({
|
||||
removeShortcuts: function () {
|
||||
var shortcuts = this.get('shortcuts');
|
||||
|
||||
Ember.keys(shortcuts).forEach(function (shortcut) {
|
||||
Object.keys(shortcuts).forEach(function (shortcut) {
|
||||
var scope = shortcuts[shortcut].scope || 'default';
|
||||
key.unbind(shortcut, scope);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ export default DS.Model.extend(ValidationEngine, {
|
||||
language: DS.attr('string', {defaultValue: 'en_US'}),
|
||||
meta_title: DS.attr('string'),
|
||||
meta_description: DS.attr('string'),
|
||||
author: DS.belongsTo('user', {async: true}),
|
||||
author: DS.belongsTo('user', {async: true}),
|
||||
author_id: DS.attr('number'),
|
||||
updated_at: DS.attr('moment-date'),
|
||||
updated_by: DS.attr(),
|
||||
@ -25,7 +25,10 @@ export default DS.Model.extend(ValidationEngine, {
|
||||
published_by: DS.belongsTo('user', {async: true}),
|
||||
created_at: DS.attr('moment-date'),
|
||||
created_by: DS.attr(),
|
||||
tags: DS.hasMany('tag', {embedded: 'always'}),
|
||||
tags: DS.hasMany('tag', {
|
||||
embedded: 'always',
|
||||
async: false
|
||||
}),
|
||||
url: DS.attr('string'),
|
||||
|
||||
config: Ember.inject.service(),
|
||||
|
@ -25,7 +25,10 @@ export default DS.Model.extend(ValidationEngine, {
|
||||
created_by: DS.attr('number'),
|
||||
updated_at: DS.attr('moment-date'),
|
||||
updated_by: DS.attr('number'),
|
||||
roles: DS.hasMany('role', {embedded: 'always'}),
|
||||
roles: DS.hasMany('role', {
|
||||
embedded: 'always',
|
||||
async: false
|
||||
}),
|
||||
|
||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||
|
||||
|
@ -143,7 +143,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||
if (this.session.isAuthenticated) {
|
||||
this.get('session.user').then(function (user) {
|
||||
if (!user.get('isAuthor') && !user.get('isEditor')) {
|
||||
self.store.findAll('notification').then(function (serverNotifications) {
|
||||
self.store.findAll('notification', {reload: true}).then(function (serverNotifications) {
|
||||
serverNotifications.forEach(function (notification) {
|
||||
self.get('notifications').handleNotification(notification, isDelayed);
|
||||
});
|
||||
|
@ -29,7 +29,7 @@ export default AuthenticatedRoute.extend(base, {
|
||||
staticPages: 'all'
|
||||
};
|
||||
|
||||
return self.store.find('post', query).then(function (records) {
|
||||
return self.store.query('post', query).then(function (records) {
|
||||
var post = records.get('firstObject');
|
||||
|
||||
if (post) {
|
||||
|
@ -3,40 +3,38 @@ import AuthenticatedRoute from 'ghost/routes/authenticated';
|
||||
import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
|
||||
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
||||
|
||||
var paginationSettings = {
|
||||
status: 'all',
|
||||
staticPages: 'all',
|
||||
page: 1
|
||||
};
|
||||
|
||||
export default AuthenticatedRoute.extend(ShortcutsRoute, PaginationRouteMixin, {
|
||||
titleToken: 'Content',
|
||||
|
||||
paginationModel: 'post',
|
||||
paginationSettings: {
|
||||
status: 'all',
|
||||
staticPages: 'all'
|
||||
},
|
||||
|
||||
model: function () {
|
||||
var self = this;
|
||||
var paginationSettings = this.get('paginationSettings'),
|
||||
self = this;
|
||||
|
||||
return this.get('session.user').then(function (user) {
|
||||
if (user.get('isAuthor')) {
|
||||
paginationSettings.author = user.get('slug');
|
||||
}
|
||||
|
||||
// using `.filter` allows the template to auto-update when new models are pulled in from the server.
|
||||
// we just need to 'return true' to allow all models by default.
|
||||
return self.store.filter('post', paginationSettings, function (post) {
|
||||
if (user.get('isAuthor')) {
|
||||
return post.isAuthoredByUser(user);
|
||||
}
|
||||
return self.loadFirstPage().then(function () {
|
||||
// using `.filter` allows the template to auto-update when new models are pulled in from the server.
|
||||
// we just need to 'return true' to allow all models by default.
|
||||
return self.store.filter('post', function (post) {
|
||||
if (user.get('isAuthor')) {
|
||||
return post.isAuthoredByUser(user);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
this.setupPagination(paginationSettings);
|
||||
},
|
||||
|
||||
stepThroughPosts: function (step) {
|
||||
var currentPost = this.get('controller.currentPost'),
|
||||
posts = this.get('controller.sortedPosts'),
|
||||
|
@ -20,7 +20,7 @@ export default MobileIndexRoute.extend(AuthenticatedRouteMixin, {
|
||||
goToPost: function () {
|
||||
var self = this,
|
||||
// the store has been populated by PostsRoute
|
||||
posts = this.store.all('post'),
|
||||
posts = this.store.peekAll('post'),
|
||||
post;
|
||||
|
||||
return this.get('session.user').then(function (user) {
|
||||
|
@ -16,7 +16,7 @@ export default AuthenticatedRoute.extend(ShortcutsRoute, {
|
||||
return this.transitionTo('error404', params.post_id);
|
||||
}
|
||||
|
||||
post = this.store.getById('post', postId);
|
||||
post = this.store.peekRecord('post', postId);
|
||||
if (post) {
|
||||
return post;
|
||||
}
|
||||
@ -27,9 +27,7 @@ export default AuthenticatedRoute.extend(ShortcutsRoute, {
|
||||
staticPages: 'all'
|
||||
};
|
||||
|
||||
return self.store.find('post', query).then(function (records) {
|
||||
var post = records.get('firstObject');
|
||||
|
||||
return self.store.queryRecord('post', query).then(function (post) {
|
||||
if (post) {
|
||||
return post;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return this.store.query('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', {type: 'blog,theme,private'}).then(function (records) {
|
||||
return this.store.query('setting', {type: 'blog,theme,private'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return this.store.query('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return this.store.query('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
},
|
||||
|
@ -2,36 +2,31 @@ import AuthenticatedRoute from 'ghost/routes/authenticated';
|
||||
import CurrentUserSettings from 'ghost/mixins/current-user-settings';
|
||||
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
||||
|
||||
var paginationSettings;
|
||||
|
||||
paginationSettings = {
|
||||
page: 1,
|
||||
include: 'post_count',
|
||||
limit: 15
|
||||
};
|
||||
|
||||
export default AuthenticatedRoute.extend(CurrentUserSettings, PaginationRouteMixin, {
|
||||
titleToken: 'Settings - Tags',
|
||||
|
||||
beforeModel: function (transition) {
|
||||
this._super(transition);
|
||||
paginationModel: 'tag',
|
||||
paginationSettings: {
|
||||
include: 'post_count',
|
||||
limit: 15
|
||||
},
|
||||
|
||||
beforeModel: function () {
|
||||
this._super(...arguments);
|
||||
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor());
|
||||
},
|
||||
|
||||
model: function () {
|
||||
this.store.unloadAll('tag');
|
||||
this.loadFirstPage();
|
||||
|
||||
return this.store.filter('tag', paginationSettings, function (tag) {
|
||||
return this.store.filter('tag', function (tag) {
|
||||
return !tag.get('isNew');
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
this.setupPagination(paginationSettings);
|
||||
},
|
||||
|
||||
renderTemplate: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
this.render('settings/tags/settings-menu', {
|
||||
@ -41,6 +36,6 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, PaginationRouteMix
|
||||
},
|
||||
|
||||
deactivate: function () {
|
||||
this.controller.send('resetPagination');
|
||||
this.send('resetPagination');
|
||||
}
|
||||
});
|
||||
|
@ -3,33 +3,24 @@ import CurrentUserSettings from 'ghost/mixins/current-user-settings';
|
||||
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
||||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var paginationSettings;
|
||||
|
||||
paginationSettings = {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
status: 'active'
|
||||
};
|
||||
|
||||
export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, PaginationRouteMixin, {
|
||||
titleToken: 'Team',
|
||||
|
||||
classNames: ['view-team'],
|
||||
|
||||
setupController: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
this.setupPagination(paginationSettings);
|
||||
},
|
||||
|
||||
beforeModel: function (transition) {
|
||||
this._super(transition);
|
||||
paginationModel: 'user',
|
||||
paginationSettings: {
|
||||
status: 'active',
|
||||
limit: 20
|
||||
},
|
||||
|
||||
model: function () {
|
||||
var self = this;
|
||||
|
||||
return self.store.find('user', {limit: 'all', status: 'invited'}).then(function () {
|
||||
return self.store.filter('user', paginationSettings, function () {
|
||||
this.loadFirstPage();
|
||||
|
||||
return self.store.query('user', {limit: 'all', status: 'invited'}).then(function () {
|
||||
return self.store.filter('user', function () {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
// return this.store.find('user', { slug: params.slug });
|
||||
|
||||
// Instead, get all the users and then find by slug
|
||||
return this.store.find('user').then(function (result) {
|
||||
return this.store.findAll('user', {reload: true}).then(function (result) {
|
||||
var user = result.findBy('slug', params.slug);
|
||||
|
||||
if (!user) {
|
||||
@ -42,8 +42,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
||||
var model = this.modelFor('team.user');
|
||||
|
||||
// we want to revert any unsaved changes on exit
|
||||
if (model && model.get('isDirty')) {
|
||||
model.rollback();
|
||||
if (model && model.get('hasDirtyAttributes')) {
|
||||
model.rollbackAttributes();
|
||||
}
|
||||
|
||||
model.get('errors').clear();
|
||||
|
@ -2,6 +2,9 @@ import Ember from 'ember';
|
||||
import DS from 'ember-data';
|
||||
|
||||
export default DS.RESTSerializer.extend({
|
||||
|
||||
isNewSerializerAPI: true,
|
||||
|
||||
serializeIntoHash: function (hash, type, record, options) {
|
||||
// Our API expects an id on the posted object
|
||||
options = options || {};
|
||||
|
@ -8,30 +8,29 @@ export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
|
||||
tags: {embedded: 'always'}
|
||||
},
|
||||
|
||||
normalize: function (type, hash) {
|
||||
normalize: function (typeClass, hash, prop) {
|
||||
// this is to enable us to still access the raw author_id
|
||||
// without requiring an extra get request (since it is an
|
||||
// async relationship).
|
||||
hash.author_id = hash.author;
|
||||
|
||||
return this._super(type, hash);
|
||||
return this._super(typeClass, hash, prop);
|
||||
},
|
||||
|
||||
extractSingle: function (store, primaryType, payload) {
|
||||
var root = this.keyForAttribute(primaryType.modelName),
|
||||
pluralizedRoot = Ember.String.pluralize(primaryType.modelName);
|
||||
normalizeSingleResponse: function (store, primaryModelClass, payload) {
|
||||
var root = this.keyForAttribute(primaryModelClass.modelName),
|
||||
pluralizedRoot = Ember.String.pluralize(primaryModelClass.modelName);
|
||||
|
||||
// make payload { post: { title: '', tags: [obj, obj], etc. } }.
|
||||
// this allows ember-data to pull the embedded tags out again,
|
||||
// in the function `updatePayloadWithEmbeddedHasMany` of the
|
||||
// EmbeddedRecordsMixin (line: `if (!partial[attribute])`):
|
||||
// https://github.com/emberjs/data/blob/master/packages/activemodel-adapter/lib/system/embedded_records_mixin.js#L499
|
||||
payload[root] = payload[pluralizedRoot][0];
|
||||
delete payload[pluralizedRoot];
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
normalizeArrayResponse: function () {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
serializeIntoHash: function (hash, type, record, options) {
|
||||
options = options || {};
|
||||
options.includeId = true;
|
||||
|
@ -20,19 +20,23 @@ export default ApplicationSerializer.extend({
|
||||
hash[root] = payload;
|
||||
},
|
||||
|
||||
extractArray: function (store, type, _payload) {
|
||||
normalizeArrayResponse: function (store, primaryModelClass, _payload, id, requestType) {
|
||||
var payload = {settings: [this._extractObjectFromArrayPayload(_payload)]};
|
||||
return this._super(store, primaryModelClass, payload, id, requestType);
|
||||
},
|
||||
|
||||
normalizeSingleResponse: function (store, primaryModelClass, _payload, id, requestType) {
|
||||
var payload = {setting: this._extractObjectFromArrayPayload(_payload)};
|
||||
return this._super(store, primaryModelClass, payload, id, requestType);
|
||||
},
|
||||
|
||||
_extractObjectFromArrayPayload: function (_payload) {
|
||||
var payload = {id: '0'};
|
||||
|
||||
_payload.settings.forEach(function (setting) {
|
||||
payload[setting.key] = setting.value;
|
||||
});
|
||||
|
||||
payload = this.normalize(type, payload);
|
||||
|
||||
return [payload];
|
||||
},
|
||||
|
||||
extractSingle: function (store, type, payload) {
|
||||
return this.extractArray(store, type, payload).pop();
|
||||
return payload;
|
||||
}
|
||||
});
|
||||
|
@ -14,6 +14,16 @@ export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
|
||||
payload[root] = payload[pluralizedRoot][0];
|
||||
delete payload[pluralizedRoot];
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
normalizeSingleResponse: function (store, primaryModelClass, payload) {
|
||||
var root = this.keyForAttribute(primaryModelClass.modelName),
|
||||
pluralizedRoot = Ember.String.pluralize(primaryModelClass.modelName);
|
||||
|
||||
payload[root] = payload[pluralizedRoot][0];
|
||||
delete payload[pluralizedRoot];
|
||||
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
@ -45,9 +45,9 @@ export default function () {
|
||||
});
|
||||
|
||||
Ember.Router.reopen({
|
||||
updateTitle: function () {
|
||||
updateTitle: Ember.on('didTransition', function () {
|
||||
this.send('collectTitleTokens', []);
|
||||
}.on('didTransition'),
|
||||
}),
|
||||
|
||||
setTitle: function (title) {
|
||||
if (Ember.testing) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
Ember.TextField.reopen({
|
||||
attributeBindings: ['autofocus']
|
||||
});
|
||||
Ember.TextField.reopen({
|
||||
attributeBindings: ['autofocus']
|
||||
});
|
||||
|
@ -4,10 +4,10 @@
|
||||
"blueimp-md5": "1.1.0",
|
||||
"codemirror": "5.2.0",
|
||||
"devicejs": "0.2.7",
|
||||
"ember": "1.13.2",
|
||||
"ember": "1.13.10",
|
||||
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
|
||||
"ember-cli-test-loader": "0.1.3",
|
||||
"ember-data": "1.0.0-beta.18",
|
||||
"ember-data": "1.13.13",
|
||||
"ember-mocha": "0.8.2",
|
||||
"ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
|
||||
"ember-resolver": "0.1.18",
|
||||
|
@ -19,28 +19,32 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"broccoli-asset-rev": "^2.0.2",
|
||||
"ember-cli": "1.13.0",
|
||||
"ember-cli-app-version": "0.4.0",
|
||||
"ember-cli-babel": "^5.0.0",
|
||||
"broccoli-asset-rev": "^2.1.2",
|
||||
"ember-cli": "1.13.8",
|
||||
"ember-cli-app-version": "0.5.0",
|
||||
"ember-cli-babel": "^5.1.3",
|
||||
"ember-cli-content-security-policy": "0.4.0",
|
||||
"ember-cli-dependency-checker": "^1.0.0",
|
||||
"ember-cli-dependency-checker": "^1.0.1",
|
||||
"ember-cli-fastclick": "1.0.3",
|
||||
"ember-cli-htmlbars": "0.7.9",
|
||||
"ember-cli-htmlbars-inline-precompile": "^0.1.1",
|
||||
"ember-cli-htmlbars-inline-precompile": "^0.2.0",
|
||||
"ember-cli-ic-ajax": "0.2.1",
|
||||
"ember-cli-inject-live-reload": "^1.3.0",
|
||||
"ember-cli-inject-live-reload": "^1.3.1",
|
||||
"ember-cli-mocha": "0.9.3",
|
||||
"ember-cli-release": "0.2.3",
|
||||
"ember-cli-selectize": "0.4.0",
|
||||
"ember-cli-simple-auth": "0.8.0",
|
||||
"ember-cli-simple-auth-oauth2": "0.8.0",
|
||||
"ember-cli-uglify": "^1.0.1",
|
||||
"ember-data": "1.0.0-beta.18",
|
||||
"ember-cli-sri": "^1.0.3",
|
||||
"ember-cli-uglify": "^1.2.0",
|
||||
"ember-data": "1.13.13",
|
||||
"ember-data-filter": "1.13.0",
|
||||
"ember-disable-proxy-controllers": "^1.0.0",
|
||||
"ember-export-application-global": "^1.0.2",
|
||||
"ember-export-application-global": "^1.0.3",
|
||||
"ember-myth": "0.1.1",
|
||||
"ember-resize": "0.0.10",
|
||||
"ember-sinon": "0.2.1",
|
||||
"ember-watson": "^0.6.4",
|
||||
"fs-extra": "0.16.3",
|
||||
"glob": "^4.0.5",
|
||||
"walk-sync": "^0.1.3"
|
||||
|
@ -13,6 +13,7 @@ describeComponent(
|
||||
function () {
|
||||
it('identifies a URL as the base URL', function () {
|
||||
var component = this.subject({
|
||||
url: '',
|
||||
baseUrl: 'http://example.com/'
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user