FIX: auto-focus input field on Safari was closing the modal

This commit is contained in:
Régis Hanol 2015-09-14 12:39:46 +02:00
parent 2c06db67a9
commit 48c3fa423a
13 changed files with 71 additions and 59 deletions

View File

@ -2,8 +2,8 @@ import computed from "ember-addons/ember-computed-decorators";
import { observes } from "ember-addons/ember-computed-decorators"; import { observes } from "ember-addons/ember-computed-decorators";
export default Ember.Component.extend({ export default Ember.Component.extend({
autoCloseValid: false,
limited: false, limited: false,
autoCloseValid: false,
@computed("limited") @computed("limited")
autoCloseUnits(limited) { autoCloseUnits(limited) {
@ -19,15 +19,14 @@ export default Ember.Component.extend({
@observes("autoCloseTime", "limited") @observes("autoCloseTime", "limited")
_updateAutoCloseValid() { _updateAutoCloseValid() {
const autoCloseTime = this.get("autoCloseTime"); const limited = this.get("limited"),
const limited = this.get("limited"); autoCloseTime = this.get("autoCloseTime"),
isValid = this._isAutoCloseValid(autoCloseTime, limited);
var isValid = this._isAutoCloseValid(autoCloseTime, limited);
this.set("autoCloseValid", isValid); this.set("autoCloseValid", isValid);
}, },
_isAutoCloseValid(autoCloseTime, limited) { _isAutoCloseValid(autoCloseTime, limited) {
var t = (autoCloseTime || "").toString().trim(); const t = (autoCloseTime || "").toString().trim();
if (t.length === 0) { if (t.length === 0) {
// "empty" is always valid // "empty" is always valid
return true; return true;

View File

@ -1,7 +1,12 @@
import { on } from "ember-addons/ember-computed-decorators";
export default Ember.TextField.extend({ export default Ember.TextField.extend({
becomeFocused: function() {
var input = this.get("element"); @on("didInsertElement")
becomeFocused() {
const input = this.get("element");
input.focus(); input.focus();
input.selectionStart = input.selectionEnd = input.value.length; input.selectionStart = input.selectionEnd = input.value.length;
}.on('didInsertElement') }
}); });

View File

@ -1,17 +1,19 @@
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
import { on } from 'ember-addons/ember-computed-decorators';
import TextField from 'discourse/components/text-field'; import TextField from 'discourse/components/text-field';
export default TextField.extend({ export default TextField.extend({
@computed('searchService.searchContextEnabled') @computed('searchService.searchContextEnabled')
placeholder: function(searchContextEnabled) { placeholder(searchContextEnabled) {
return searchContextEnabled ? "" : I18n.t('search.title'); return searchContextEnabled ? "" : I18n.t('search.title');
}, },
focusIn: function() { focusIn() {
Em.run.later(() => { this.$().select(); }); Em.run.later(() => this.$().select());
}, },
becomeFocused: function() { @on("didInsertElement")
becomeFocused() {
if (this.get('hasAutofocus')) this.$().focus(); if (this.get('hasAutofocus')) this.$().focus();
}.on('didInsertElement') }
}); });

View File

@ -1,19 +1,10 @@
/** import computed from "ember-addons/ember-computed-decorators";
This is a custom text field that allows i18n placeholders
@class TextField
@extends Ember.TextField
@namespace Discourse
@module Discourse
**/
export default Ember.TextField.extend({ export default Ember.TextField.extend({
attributeBindings: ['autocorrect', 'autocapitalize', 'autofocus', 'maxLength'], attributeBindings: ['autocorrect', 'autocapitalize', 'autofocus', 'maxLength'],
placeholder: function() { @computed("placeholderKey")
if (this.get('placeholderKey')) { placeholder(placeholderKey) {
return I18n.t(this.get('placeholderKey')); return placeholderKey ? I18n.t(placeholderKey) : "";
} else { }
return '';
}
}.property('placeholderKey')
}); });

View File

@ -1,3 +1,4 @@
import { observes } from "ember-addons/ember-computed-decorators";
import ModalFunctionality from 'discourse/mixins/modal-functionality'; import ModalFunctionality from 'discourse/mixins/modal-functionality';
// Modal related to auto closing of topics // Modal related to auto closing of topics
@ -5,31 +6,32 @@ export default Ember.Controller.extend(ModalFunctionality, {
auto_close_valid: true, auto_close_valid: true,
auto_close_invalid: Em.computed.not('auto_close_valid'), auto_close_invalid: Em.computed.not('auto_close_valid'),
setAutoCloseTime: function() { @observes("model.details.auto_close_at", "model.details.auto_close_hours")
var autoCloseTime = null; setAutoCloseTime() {
let autoCloseTime = null;
if (this.get("model.details.auto_close_based_on_last_post")) { if (this.get("model.details.auto_close_based_on_last_post")) {
autoCloseTime = this.get("model.details.auto_close_hours"); autoCloseTime = this.get("model.details.auto_close_hours");
} else if (this.get("model.details.auto_close_at")) { } else if (this.get("model.details.auto_close_at")) {
var closeTime = new Date(this.get("model.details.auto_close_at")); const closeTime = new Date(this.get("model.details.auto_close_at"));
if (closeTime > new Date()) { if (closeTime > new Date()) {
autoCloseTime = moment(closeTime).format("YYYY-MM-DD HH:mm"); autoCloseTime = moment(closeTime).format("YYYY-MM-DD HH:mm");
} }
} }
this.set("model.auto_close_time", autoCloseTime); this.set("model.auto_close_time", autoCloseTime);
}.observes("model.details.{auto_close_at,auto_close_hours}"),
actions: {
saveAutoClose: function() { this.setAutoClose(this.get("model.auto_close_time")); },
removeAutoClose: function() { this.setAutoClose(null); }
}, },
setAutoClose: function(time) { actions: {
var self = this; saveAutoClose() { this.setAutoClose(this.get("model.auto_close_time")); },
removeAutoClose() { this.setAutoClose(null); }
},
setAutoClose(time) {
const self = this;
this.send('hideModal'); this.send('hideModal');
Discourse.ajax({ Discourse.ajax({
url: '/t/' + this.get('model.id') + '/autoclose', url: `/t/${this.get('model.id')}/autoclose`,
type: 'PUT', type: 'PUT',
dataType: 'json', dataType: 'json',
data: { data: {
@ -37,15 +39,15 @@ export default Ember.Controller.extend(ModalFunctionality, {
auto_close_based_on_last_post: this.get("model.details.auto_close_based_on_last_post"), auto_close_based_on_last_post: this.get("model.details.auto_close_based_on_last_post"),
timezone_offset: (new Date().getTimezoneOffset()) timezone_offset: (new Date().getTimezoneOffset())
} }
}).then(function(result){ }).then(result => {
if (result.success) { if (result.success) {
self.send('closeModal'); this.send('closeModal');
self.set('model.details.auto_close_at', result.auto_close_at); this.set('model.details.auto_close_at', result.auto_close_at);
self.set('model.details.auto_close_hours', result.auto_close_hours); this.set('model.details.auto_close_hours', result.auto_close_hours);
} else { } else {
bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } ); bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } );
} }
}, function () { }).catch(() => {
bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } ); bootbox.alert(I18n.t('composer.auto_close.error'), function() { self.send('reopenModal'); } );
}); });
} }

View File

@ -3,7 +3,7 @@ export default Em.Mixin.create({
needs: ['modal'], needs: ['modal'],
flash: function(message, messageClass) { flash(message, messageClass) {
this.set('flashMessage', Em.Object.create({ message, messageClass })); this.set('flashMessage', Em.Object.create({ message, messageClass }));
} }
}); });

View File

@ -56,7 +56,7 @@ const TopicRoute = Discourse.Route.extend({
}, },
showAutoClose() { showAutoClose() {
showModal('edit-topic-auto-close', { model: this.modelFor('topic'), title: 'topic.auto_close_title' }); showModal('edit-topic-auto-close', { model: this.modelFor('topic') });
this.controllerFor('modal').set('modalClass', 'edit-auto-close-modal'); this.controllerFor('modal').set('modalClass', 'edit-auto-close-modal');
}, },

View File

@ -12,7 +12,7 @@
</div> </div>
<div> <div>
<label> <label>
{{input type="checkbox" name="autoCloseBasedOnLastPost" checked=autoCloseBasedOnLastPost}} {{input type="checkbox" checked=autoCloseBasedOnLastPost}}
{{i18n 'composer.auto_close.based_on_last_post'}} {{i18n 'composer.auto_close.based_on_last_post'}}
</label> </label>
</div> </div>

View File

@ -6,8 +6,8 @@
limited=model.details.auto_close_based_on_last_post }} limited=model.details.auto_close_based_on_last_post }}
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class='btn btn-primary' type='submit' {{bind-attr disabled="auto_close_invalid"}}>{{i18n 'topic.auto_close_save'}}</button> {{d-button class="btn-primary" disabled=auto_close_invalid label="topic.auto_close_save"}}
<a {{action "closeModal"}}>{{i18n 'cancel'}}</a> <a {{action "closeModal"}}>{{i18n 'cancel'}}</a>
<button class='btn pull-right' {{action "removeAutoClose"}}>{{i18n 'topic.auto_close_remove'}}</button> {{d-button class="pull-right" action="removeAutoClose" label="topic.auto_close_remove"}}
</div> </div>
</form> </form>

View File

@ -0,0 +1,7 @@
import ModalBodyView from "discourse/views/modal-body";
export default ModalBodyView.extend({
templateName: "modal/edit-topic-auto-close",
title: I18n.t("topic.auto_close_title"),
focusInput: false
});

View File

@ -1,7 +1,10 @@
import { observes, on } from "ember-addons/ember-computed-decorators";
export default Ember.View.extend({ export default Ember.View.extend({
focusInput: true, focusInput: true,
_setupModal: function() { @on("didInsertElement")
_setupModal() {
$('#modal-alert').hide(); $('#modal-alert').hide();
$('#discourse-modal').modal('show'); $('#discourse-modal').modal('show');
@ -14,9 +17,10 @@ export default Ember.View.extend({
if (title) { if (title) {
this.set('controller.controllers.modal.title', title); this.set('controller.controllers.modal.title', title);
} }
}.on('didInsertElement'), },
flashMessageChanged: function() { @observes("controller.flashMessage")
flashMessageChanged() {
const flashMessage = this.get('controller.flashMessage'); const flashMessage = this.get('controller.flashMessage');
if (flashMessage) { if (flashMessage) {
const messageClass = flashMessage.get('messageClass') || 'success'; const messageClass = flashMessage.get('messageClass') || 'success';
@ -25,6 +29,6 @@ export default Ember.View.extend({
.addClass("alert alert-" + messageClass).html(flashMessage.get('message')) .addClass("alert alert-" + messageClass).html(flashMessage.get('message'))
.fadeIn(); .fadeIn();
} }
}.observes('controller.flashMessage') }
}); });

View File

@ -1,3 +1,5 @@
import { on } from "ember-addons/ember-computed-decorators";
export default Ember.View.extend({ export default Ember.View.extend({
elementId: 'discourse-modal', elementId: 'discourse-modal',
templateName: 'modal/modal', templateName: 'modal/modal',
@ -7,17 +9,19 @@ export default Ember.View.extend({
// We handle ESC ourselves // We handle ESC ourselves
'data-keyboard': 'false', 'data-keyboard': 'false',
_bindOnInsert: function() { @on("didInsertElement")
setUp() {
$('html').on('keydown.discourse-modal', e => { $('html').on('keydown.discourse-modal', e => {
if (e.which === 27) { if (e.which === 27) {
Em.run.next(() => $('.modal-header a.close').click()); Em.run.next(() => $('.modal-header a.close').click());
} }
}); });
}.on('didInsertElement'), },
_bindOnDestroy: function() { @on("willDestroyElement")
cleanUp() {
$('html').off('keydown.discourse-modal'); $('html').off('keydown.discourse-modal');
}.on('willDestroyElement'), },
click(e) { click(e) {
const $target = $(e.target); const $target = $(e.target);

View File

@ -185,7 +185,6 @@ body {
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
border-radius: 3px; border-radius: 3px;
box-shadow: inset 0 1px 1px rgba(0,0,0, .3); box-shadow: inset 0 1px 1px rgba(0,0,0, .3);
transition: border linear 0.2s, box-shadow linear 0.2s;
} }
input { input {
&[type="text"], &[type="password"], &[type="datetime"], &[type="datetime-local"], &[type="date"], &[type="month"], &[type="time"], &[type="week"], &[type="number"], &[type="email"], &[type="url"], &[type="search"], &[type="tel"], &[type="color"] { &[type="text"], &[type="password"], &[type="datetime"], &[type="datetime-local"], &[type="date"], &[type="month"], &[type="time"], &[type="week"], &[type="number"], &[type="email"], &[type="url"], &[type="search"], &[type="tel"], &[type="color"] {
@ -193,7 +192,6 @@ body {
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
border-radius: 3px; border-radius: 3px;
box-shadow: inset 0 1px 1px rgba(0,0,0, .3); box-shadow: inset 0 1px 1px rgba(0,0,0, .3);
transition: border linear 0.2s, box-shadow linear 0.2s;
} }
} }
textarea:focus { textarea:focus {