mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Always call _super
when using Ember hooks
no issue - review use of Ember core hooks and add a call to `this._super` if missing - fix a few occurrences of using the wrong component lifecycle hooks that could result in multiple/duplicate event handlers being attached `_super` should always be called when overriding Ember's base hooks so that core functionality or app functionality added through extensions, mixins or addons is not lost. This is important as it guards against issues arising from later refactorings or core changes. As example of lost functionality, there were a number of routes that extended from `AuthenticatedRoute` but then overrode the `beforeModel` hook without calling `_super` which meant that the route was no longer treated as authenticated.
This commit is contained in:
parent
e5d9865792
commit
571b9e783a
42 changed files with 87 additions and 14 deletions
|
@ -18,6 +18,8 @@ export default Component.extend({
|
|||
_editor: null, // reference to CodeMirror editor
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
let options = this.getProperties('lineNumbers', 'indentUnit', 'mode', 'theme');
|
||||
let editor = new CodeMirror(this.get('element'), options);
|
||||
|
||||
|
@ -36,6 +38,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
let editor = this._editor.getWrapperElement();
|
||||
editor.parentNode.removeChild(editor);
|
||||
this._editor = null;
|
||||
|
|
|
@ -9,6 +9,8 @@ export default Component.extend({
|
|||
content: null,
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
let el = this.$();
|
||||
|
||||
el.on('scroll', run.bind(el, setScrollClassName, {
|
||||
|
@ -18,6 +20,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
didReceiveAttrs(options) {
|
||||
this._super(...arguments);
|
||||
|
||||
// adjust when didReceiveAttrs gets both newAttrs and oldAttrs
|
||||
if (options.newAttrs.content && this.get('content') !== options.newAttrs.content.value) {
|
||||
let el = this.$();
|
||||
|
@ -29,6 +33,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
let el = this.$();
|
||||
|
||||
el.off('scroll');
|
||||
|
|
|
@ -9,12 +9,15 @@ export default Component.extend({
|
|||
_scrollWrapper: null,
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this._scrollWrapper = this.$().closest('.entry-preview-content');
|
||||
this.adjustScrollPosition(this.get('scrollPosition'));
|
||||
run.scheduleOnce('afterRender', this, this.dropzoneHandler);
|
||||
},
|
||||
|
||||
didReceiveAttrs(attrs) {
|
||||
this._super(...arguments);
|
||||
|
||||
if (!attrs.oldAttrs) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.scheduleAfterRender();
|
||||
},
|
||||
|
||||
|
@ -61,6 +62,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
// removes scroll handlers from the view
|
||||
this.get('$previewViewPort').off('scroll');
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import setScrollClassName from 'ghost/utils/set-scroll-classname';
|
|||
const {Component, run} = Ember;
|
||||
|
||||
export default Component.extend(InfiniteScrollMixin, {
|
||||
didRender() {
|
||||
didInsertElement() {
|
||||
let el = this.$();
|
||||
|
||||
this._super(...arguments);
|
||||
|
|
|
@ -34,6 +34,7 @@ export default Component.extend({
|
|||
}),
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.$('.js-modal-container, .js-modal-background').addClass('fade-in open');
|
||||
this.$('.js-modal').addClass('open');
|
||||
},
|
||||
|
|
|
@ -31,6 +31,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
this.$('.ui-sortable').sortable('destroy');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -31,6 +31,8 @@ export default TextField.extend({
|
|||
}),
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
|
||||
let baseUrl = this.get('baseUrl');
|
||||
let url = this.get('url');
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ export default Component.extend({
|
|||
}),
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.$().on('animationend webkitAnimationEnd oanimationend MSAnimationEnd', (event) => {
|
||||
if (event.originalEvent.animationName === 'fade-out') {
|
||||
this.get('notifications').closeNotification(this.get('message'));
|
||||
|
@ -38,6 +40,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
this.$().off('animationend webkitAnimationEnd oanimationend MSAnimationEnd');
|
||||
},
|
||||
|
||||
|
|
|
@ -42,10 +42,12 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.addObserver('active', this, this.scrollIntoView);
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
this.removeObserver('active', this, this.scrollIntoView);
|
||||
},
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
didReceiveAttrs(attrs) {
|
||||
this._super(...arguments);
|
||||
let timeout = parseInt(attrs.newAttrs.throttle || this.get('debounce'));
|
||||
run.debounce(this, 'trySetValidEmail', timeout);
|
||||
},
|
||||
|
@ -68,6 +69,8 @@ export default Component.extend({
|
|||
let size = this.get('size');
|
||||
let uploadElement = this.$('.js-file-input');
|
||||
|
||||
this._super(...arguments);
|
||||
|
||||
// while theoretically the 'add' and 'processalways' functions could be
|
||||
// added as properties of the hash passed to fileupload(), for some reason
|
||||
// they needed to be placed in an on() call for the add method to work correctly
|
||||
|
@ -85,6 +88,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.$('.js-file-input').data()['blueimp-fileupload']) {
|
||||
this.$('.js-file-input').fileupload('destroy');
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willDestroy() {
|
||||
this._super(...arguments);
|
||||
this._resetKeymasterScope();
|
||||
},
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ export default Component.extend({
|
|||
}),
|
||||
|
||||
willDestroy() {
|
||||
this._super(...arguments);
|
||||
run.cancel(this.get('showSpinnerTimeout'));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -21,11 +21,13 @@ export default Component.extend({
|
|||
active: alias('tab.active'),
|
||||
|
||||
willRender() {
|
||||
this._super(...arguments);
|
||||
// Register with the tabs manager
|
||||
this.get('tabsManager').registerTabPane(this);
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
// Deregister with the tabs manager
|
||||
this.get('tabsManager').unregisterTabPane(this);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,13 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
willRender() {
|
||||
this._super(...arguments);
|
||||
// register the tabs with the tab manager
|
||||
this.get('tabsManager').registerTab(this);
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
// unregister the tabs with the tab manager
|
||||
this.get('tabsManager').unregisterTab(this);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ export default Component.extend({
|
|||
}),
|
||||
|
||||
didReceiveAttrs(attrs) {
|
||||
this._super(...arguments);
|
||||
|
||||
if (get(attrs, 'newAttrs.tag.value.id') !== get(attrs, 'oldAttrs.tag.value.id')) {
|
||||
this.reset();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ export default Component.extend({
|
|||
let oldValue = attrs.oldAttrs && get(attrs.oldAttrs, 'image.value');
|
||||
let newValue = attrs.newAttrs && get(attrs.newAttrs, 'image.value');
|
||||
|
||||
this._super(...arguments);
|
||||
|
||||
// always reset when we receive a blank image
|
||||
// - handles navigating to populated image from blank image
|
||||
if (isEmpty(newValue) && !isEmpty(oldValue)) {
|
||||
|
@ -45,10 +47,12 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
this.send('initUploader');
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
this.removeListeners();
|
||||
},
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ export default Controller.extend(PromiseProxyMixin, {
|
|||
}),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
let promise = this.store.query('setting', {type: 'blog,theme'}).then((settings) => {
|
||||
return settings.get('firstObject');
|
||||
});
|
||||
|
|
|
@ -125,7 +125,7 @@ export default Mixin.create(styleBody, ShortcutsRoute, {
|
|||
model.set('scratch', model.get('markdown'));
|
||||
model.set('titleScratch', model.get('title'));
|
||||
|
||||
this._super(controller, model);
|
||||
this._super(...arguments);
|
||||
|
||||
if (tags) {
|
||||
// used to check if anything has changed in the editor
|
||||
|
|
|
@ -24,6 +24,8 @@ export default Mixin.create({
|
|||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
let el = this.get('element');
|
||||
|
||||
el.onscroll = run.bind(this, this.checkScroll);
|
||||
|
@ -34,6 +36,8 @@ export default Mixin.create({
|
|||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
// turn off the scroll handler
|
||||
this.get('element').onscroll = null;
|
||||
}
|
||||
|
|
|
@ -78,12 +78,12 @@ export default Mixin.create({
|
|||
},
|
||||
|
||||
activate() {
|
||||
this._super();
|
||||
this._super(...arguments);
|
||||
this.registerShortcuts();
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this._super();
|
||||
this._super(...arguments);
|
||||
this.removeShortcuts();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -41,6 +41,8 @@ export default AuthenticatedRoute.extend(base, {
|
|||
},
|
||||
|
||||
afterModel(post) {
|
||||
this._super(...arguments);
|
||||
|
||||
return this.get('session.user').then((user) => {
|
||||
if (user.get('isAuthor') && !post.isAuthoredByUser(user)) {
|
||||
return this.replaceRoute('posts.index');
|
||||
|
|
|
@ -4,6 +4,7 @@ const {Route} = Ember;
|
|||
|
||||
export default Route.extend({
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
this.transitionTo('editor.new');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ export default AuthenticatedRoute.extend(base, {
|
|||
});
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
setupController() {
|
||||
let psm = this.controllerFor('post-settings-menu');
|
||||
|
||||
// make sure there are no titleObserver functions hanging around
|
||||
|
@ -36,7 +36,7 @@ export default AuthenticatedRoute.extend(base, {
|
|||
psm.send('resetUploader');
|
||||
psm.send('resetPubDate');
|
||||
|
||||
this._super(controller, model);
|
||||
this._super(...arguments);
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
|
|
@ -12,6 +12,7 @@ export default Route.extend({
|
|||
mediaQueries: inject.service(),
|
||||
|
||||
activate() {
|
||||
this._super(...arguments);
|
||||
this._callDesktopTransition = () => {
|
||||
if (!this.get('mediaQueries.isMobile')) {
|
||||
this.desktopTransition();
|
||||
|
@ -21,6 +22,7 @@ export default Route.extend({
|
|||
},
|
||||
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
if (this._callDesktopTransition) {
|
||||
removeObserver(this, 'mediaQueries.isMobile', this._callDesktopTransition);
|
||||
this._callDesktopTransition = null;
|
||||
|
|
|
@ -13,6 +13,7 @@ export default MobileIndexRoute.extend(AuthenticatedRouteMixin, {
|
|||
|
||||
// Transition to a specific post if we're not on mobile
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
if (!this.get('isMobile')) {
|
||||
return this.goToPost();
|
||||
}
|
||||
|
@ -20,6 +21,7 @@ export default MobileIndexRoute.extend(AuthenticatedRouteMixin, {
|
|||
|
||||
setupController(controller) {
|
||||
controller.set('noPosts', this.get('noPosts'));
|
||||
this._super(...arguments);
|
||||
},
|
||||
|
||||
goToPost() {
|
||||
|
|
|
@ -11,6 +11,7 @@ export default Route.extend(styleBody, {
|
|||
session: inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
this.get('notifications').showAlert('You can\'t reset your password while you\'re signed in.', {type: 'warn', delayed: true, key: 'password.reset.signed-in'});
|
||||
this.transitionTo(Configuration.routeAfterAuthentication);
|
||||
|
@ -18,6 +19,7 @@ export default Route.extend(styleBody, {
|
|||
},
|
||||
|
||||
setupController(controller, params) {
|
||||
this._super(...arguments);
|
||||
controller.token = params.token;
|
||||
},
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||
titleToken: 'Settings - Code Injection',
|
||||
classNames: ['settings-view-code'],
|
||||
|
||||
beforeModel(transition) {
|
||||
this._super(transition);
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor())
|
||||
.then(this.transitionEditor());
|
||||
|
|
|
@ -7,8 +7,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||
|
||||
classNames: ['settings-view-general'],
|
||||
|
||||
beforeModel(transition) {
|
||||
this._super(transition);
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor())
|
||||
.then(this.transitionEditor());
|
||||
|
|
|
@ -7,8 +7,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||
|
||||
classNames: ['settings'],
|
||||
|
||||
beforeModel(transition) {
|
||||
this._super(transition);
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor())
|
||||
.then(this.transitionEditor());
|
||||
|
|
|
@ -7,8 +7,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||
|
||||
classNames: ['settings-view-navigation'],
|
||||
|
||||
beforeModel(transition) {
|
||||
this._super(transition);
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
return this.get('session.user')
|
||||
.then(this.transitionAuthor());
|
||||
},
|
||||
|
|
|
@ -39,6 +39,7 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, PaginationRoute, S
|
|||
},
|
||||
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
this.send('resetPagination');
|
||||
},
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ export default AuthenticatedRoute.extend({
|
|||
|
||||
beforeModel() {
|
||||
let firstTag = this.modelFor('settings.tags').get('firstObject');
|
||||
|
||||
this._super(...arguments);
|
||||
|
||||
if (firstTag && !this.get('mediaQueries.maxWidth600')) {
|
||||
this.transitionTo('settings.tags.tag', firstTag);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export default AuthenticatedRoute.extend({
|
|||
|
||||
// reset the model so that mobile screens react to an empty selectedTag
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
this.set('controller.model', null);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ export default AuthenticatedRoute.extend({
|
|||
|
||||
// reset the model so that mobile screens react to an empty selectedTag
|
||||
deactivate() {
|
||||
this._super(...arguments);
|
||||
this.set('controller.model', null);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ export default Route.extend(styleBody, {
|
|||
// use the beforeModel hook to check to see whether or not setup has been
|
||||
// previously completed. If it has, stop the transition into the setup page.
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
|
||||
return;
|
||||
|
|
|
@ -4,6 +4,7 @@ const {Route} = Ember;
|
|||
|
||||
export default Route.extend({
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
this.transitionTo('setup.one');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ let DownloadCountPoller = Ember.Object.extend({
|
|||
runId: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.downloadCounter();
|
||||
this.poll();
|
||||
},
|
||||
|
|
|
@ -4,6 +4,7 @@ const {Route} = Ember;
|
|||
|
||||
export default Route.extend({
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
if (!this.controllerFor('setup.two').get('blogCreated')) {
|
||||
this.transitionTo('setup.two');
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ export default Route.extend(styleBody, {
|
|||
session: inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ export default Route.extend(styleBody, {
|
|||
session: inject.service(),
|
||||
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (this.get('session.isAuthenticated')) {
|
||||
this.get('notifications').showAlert('You need to sign out to register as a new user.', {type: 'warn', delayed: true, key: 'signup.create.already-authenticated'});
|
||||
this.transitionTo(Configuration.routeIfAlreadyAuthenticated);
|
||||
|
|
|
@ -17,6 +17,8 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
|
|||
},
|
||||
|
||||
afterModel(user) {
|
||||
this._super(...arguments);
|
||||
|
||||
return this.get('session.user').then((currentUser) => {
|
||||
let isOwnProfile = user.get('id') === currentUser.get('id');
|
||||
let isAuthor = currentUser.get('isAuthor');
|
||||
|
|
Loading…
Add table
Reference in a new issue