Composer and replying tweaks/bug-fixes

This commit is contained in:
Toby Zerner 2015-02-06 14:06:22 +10:30
parent 1db559e4c3
commit e53b3872c9
6 changed files with 61 additions and 44 deletions

View File

@ -9,7 +9,7 @@ export default Ember.Component.extend(Ember.Evented, {
submitLabel: 'Post Reply', submitLabel: 'Post Reply',
placeholder: '', placeholder: '',
value: '', content: '',
submit: null, submit: null,
loading: false, loading: false,
@ -29,21 +29,23 @@ export default Ember.Component.extend(Ember.Evented, {
}, },
actions: { actions: {
submit: function(value) { submit: function(content) {
this.get('submit')(value); this.get('submit')({
content: content
});
}, },
willExit: function(abort) { willExit: function(abort) {
// If the user has typed something, prompt them before exiting // If the user has typed something, prompt them before exiting
// this composer state. // this composer state.
if (this.get('value') && ! confirm('You have not posted your reply. Do you wish to discard it?')) { if (this.get('content') && ! confirm('You have not posted your reply. Do you wish to discard it?')) {
abort(); abort();
} }
}, },
reset: function() { reset: function() {
this.set('loading', false); this.set('loading', false);
this.set('value', ''); this.set('content', '');
} }
} }
}); });

View File

@ -27,6 +27,7 @@ export default Ember.Controller.extend(Ember.Evented, {
this.confirmExit().then(function() { this.confirmExit().then(function() {
composer.set('content', null); composer.set('content', null);
Ember.run.next(function() { Ember.run.next(function() {
newContent.set('composer', composer);
composer.set('content', newContent); composer.set('content', newContent);
}); });
}); });
@ -61,10 +62,10 @@ export default Ember.Controller.extend(Ember.Evented, {
hide: function() { hide: function() {
this.set('position', PositionEnum.HIDDEN); this.set('position', PositionEnum.HIDDEN);
var content = this.get('content'); },
if (content) {
content.send('reset'); clearContent: function() {
} this.set('content', null);
}, },
close: function() { close: function() {
@ -75,17 +76,23 @@ export default Ember.Controller.extend(Ember.Evented, {
}, },
minimize: function() { minimize: function() {
this.set('position', PositionEnum.MINIMIZED); if (this.get('position') !== PositionEnum.HIDDEN) {
this.set('position', PositionEnum.MINIMIZED);
}
}, },
fullscreen: function() { fullscreen: function() {
this.set('position', PositionEnum.FULLSCREEN); if (this.get('position') !== PositionEnum.HIDDEN) {
this.trigger('focus'); this.set('position', PositionEnum.FULLSCREEN);
this.trigger('focus');
}
}, },
exitFullscreen: function() { exitFullscreen: function() {
this.set('position', PositionEnum.NORMAL); if (this.get('position') === PositionEnum.FULLSCREEN) {
this.trigger('focus'); this.set('position', PositionEnum.NORMAL);
this.trigger('focus');
}
} }
} }

View File

@ -17,7 +17,9 @@ export default Ember.ObjectController.extend(Ember.Evented, {
// Save a reply. This may be called by a composer-reply component that was // Save a reply. This may be called by a composer-reply component that was
// set up on a different discussion, so we require a discussion model to // set up on a different discussion, so we require a discussion model to
// be explicitly passed rather than using the controller's implicit one. // be explicitly passed rather than using the controller's implicit one.
saveReply: function(discussion, content) { // @todo break this down into bite-sized functions so that extensions can
// easily override where they please.
saveReply: function(discussion, data) {
var controller = this; var controller = this;
var composer = this.get('controllers.composer'); var composer = this.get('controllers.composer');
var stream = this.get('stream'); var stream = this.get('stream');
@ -26,7 +28,7 @@ export default Ember.ObjectController.extend(Ember.Evented, {
controller.get('controllers.application').send('clearAlerts'); controller.get('controllers.application').send('clearAlerts');
var post = this.store.createRecord('post', { var post = this.store.createRecord('post', {
content: content, content: data.content,
discussion: discussion discussion: discussion
}); });
@ -91,12 +93,12 @@ export default Ember.ObjectController.extend(Ember.Evented, {
// If the composer is already set up for this discussion, then we // If the composer is already set up for this discussion, then we
// don't need to change its content - we can just show it. // don't need to change its content - we can just show it.
if (composer.get('content.discussion') != discussion) { if (!(composer.get('content') instanceof ComposerReply) || composer.get('content.discussion') != discussion) {
composer.switchContent(ComposerReply.create({ composer.switchContent(ComposerReply.create({
user: controller.get('session.user'), user: controller.get('session.user'),
discussion: discussion, discussion: discussion,
submit: function(value) { submit: function(data) {
controller.saveReply(discussion, value); controller.saveReply(discussion, data);
} }
})); }));
} }

View File

@ -4,8 +4,8 @@
{{ui/controls/item-list items=controls class="composer-header list-inline"}} {{ui/controls/item-list items=controls class="composer-header list-inline"}}
<div class="composer-editor"> <div class="composer-editor">
{{ui/controls/text-editor submit="submit" value=value placeholder=placeholder submitLabel=submitLabel disabled=loading}} {{ui/controls/text-editor submit="submit" value=content placeholder=placeholder submitLabel=submitLabel disabled=loading}}
</div> </div>
</div> </div>
{{ui/controls/loading-indicator classNameBindings=":composer-loading loading:active"}} {{ui/controls/loading-indicator classNameBindings=":composer-loading loading:active"}}

View File

@ -6,4 +6,4 @@
{{#if content}} {{#if content}}
{{view content}} {{view content}}
{{/if}} {{/if}}
</div> </div>

View File

@ -119,9 +119,9 @@ export default Ember.View.extend(Ember.Evented, {
// an element with the class .flexible-height — this element is intended // an element with the class .flexible-height — this element is intended
// to fill up the height of the composer, minus the space taken up by the // to fill up the height of the composer, minus the space taken up by the
// composer's header/footer/etc. // composer's header/footer/etc.
updateContentHeight: function() { setContentHeight: function(height) {
var content = this.$('.composer-content'); var content = this.$('.composer-content');
this.$('.flexible-height').height(this.get('computedHeight') this.$('.flexible-height').height(height
- parseInt(content.css('padding-top')) - parseInt(content.css('padding-top'))
- parseInt(content.css('padding-bottom')) - parseInt(content.css('padding-bottom'))
- this.$('.composer-header').outerHeight(true) - this.$('.composer-header').outerHeight(true)
@ -144,15 +144,17 @@ export default Ember.View.extend(Ember.Evented, {
// Whenever the composer's computed height changes, update the DOM to // Whenever the composer's computed height changes, update the DOM to
// reflect it. // reflect it.
updateHeight: function() { updateHeight: function() {
if (!this.$()) { return; } Ember.run.scheduleOnce('afterRender', this, function() {
this.$().height(this.get('computedHeight'));
var view = this;
Ember.run.scheduleOnce('afterRender', function() {
view.$().height(view.get('computedHeight'));
view.updateContentHeight();
}); });
}.observes('computedHeight'), }.observes('computedHeight'),
updateContentHeight: function() {
Ember.run.scheduleOnce('afterRender', this, function() {
this.setContentHeight(this.get('computedHeight'));
});
}.observes('computedHeight', 'controller.content'),
positionWillChange: function() { positionWillChange: function() {
this.set('oldPosition', this.get('position')); this.set('oldPosition', this.get('position'));
}.observesBefore('position'), }.observesBefore('position'),
@ -160,28 +162,28 @@ export default Ember.View.extend(Ember.Evented, {
// Whenever the composer's display state changes, update the DOM to slide // Whenever the composer's display state changes, update the DOM to slide
// it in or out. // it in or out.
positionDidChange: function() { positionDidChange: function() {
var $composer = this.$();
if (!$composer) { return; }
var view = this;
// At this stage, the position property has just changed, and the // At this stage, the position property has just changed, and the
// class name hasn't been altered in the DOM. So, we can grab the // class name hasn't been altered in the DOM. So, we can grab the
// composer's current height which we might want to animate from. // composer's current height which we might want to animate from.
// After the DOM has updated, we animate to its new height. // After the DOM has updated, we animate to its new height.
var oldHeight = $composer.height(); var $composer = this.$();
var oldHeight = $composer ? $composer.height() : 0;
Ember.run.scheduleOnce('afterRender', function() { Ember.run.scheduleOnce('afterRender', this, function() {
var $composer = this.$();
var newHeight = $composer.height(); var newHeight = $composer.height();
var view = this;
switch (view.get('position')) { switch (this.get('position')) {
case PositionEnum.HIDDEN: case PositionEnum.HIDDEN:
$composer.animate({bottom: -oldHeight}, 'fast', function() { $composer.animate({bottom: -newHeight}, 'fast', function() {
$composer.hide(); $composer.hide();
view.get('controller').send('clearContent');
}); });
break; break;
case PositionEnum.NORMAL: case PositionEnum.NORMAL:
if (view.get('oldPosition') !== PositionEnum.FULLSCREEN) { if (this.get('oldPosition') !== PositionEnum.FULLSCREEN) {
$composer.show(); $composer.show();
$composer.css({height: oldHeight}).animate({bottom: 0, height: newHeight}, 'fast', function() { $composer.css({height: oldHeight}).animate({bottom: 0, height: newHeight}, 'fast', function() {
view.focus(); view.focus();
@ -196,10 +198,10 @@ export default Ember.View.extend(Ember.Evented, {
break; break;
} }
if (view.get('position') !== PositionEnum.FULLSCREEN) { if (this.get('position') !== PositionEnum.FULLSCREEN) {
view.updateBodyPadding(true); this.updateBodyPadding(true);
} }
view.updateContentHeight(); this.setContentHeight(this.get('computedHeight'));
}); });
}.observes('position'), }.observes('position'),
@ -225,7 +227,7 @@ export default Ember.View.extend(Ember.Evented, {
var deltaPixels = event.data.mouseStart - event.clientY; var deltaPixels = event.data.mouseStart - event.clientY;
var height = event.data.heightStart + deltaPixels; var height = event.data.heightStart + deltaPixels;
view.set('height', height); view.set('height', height);
view.updateContentHeight(); view.setContentHeight(height);
view.updateBodyPadding(); view.updateBodyPadding();
localStorage.setItem('composerHeight', height); localStorage.setItem('composerHeight', height);
@ -238,7 +240,11 @@ export default Ember.View.extend(Ember.Evented, {
}, },
focus: function() { focus: function() {
this.$().find(':input:enabled:visible:first').focus(); if (this.$().is(':hidden')) { return; }
Ember.run.scheduleOnce('afterRender', this, function() {
this.$().find(':input:enabled:visible:first').focus();
});
}, },
populateControls: function(controls) { populateControls: function(controls) {