Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
✨ auto-expanding editor title input (#699)
Browse files Browse the repository at this point in the history
closes TryGhost/Ghost#8463
- move generic text input handling into `text-input` mixin so it applies to text inputs and textareas
- adds `autoExpand` property to `gh-textarea` that accepts a selector to watch for resize changes, if the property is set then auto-expanding behaviour is triggered any time the textarea value is changed or when the selector element is resized (this prevents change in textarea width from toggling nav or split screen mode resulting in textarea content being hidden or the textarea being taller than it's contents)
- adds `ember-element-resize-detector` addon to allow watching of element resizes rather than window resizes (this was already included as a sub-dependency via `ember-light-table`->`ember-scrollable`->`ember-element-resize-detector`)
  • Loading branch information
kevinansfield authored and aileen committed May 18, 2017
1 parent c00af25 commit d49484a
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 44 deletions.
11 changes: 1 addition & 10 deletions app/components/gh-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,5 @@ import OneWayInput from 'ember-one-way-controls/components/one-way-input';
import TextInputMixin from 'ghost-admin/mixins/text-input';

export default OneWayInput.extend(TextInputMixin, {
classNames: 'gh-input',

// prevent default TAB behaviour if we have a keyEvent for it
keyDown(event) {
if (event.keyCode === 9 && this.get('keyEvents.9')) {
event.preventDefault();
}

this._super(...arguments);
}
classNames: 'gh-input'
});
64 changes: 63 additions & 1 deletion app/components/gh-textarea.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,68 @@
import OneWayTextarea from 'ember-one-way-controls/components/one-way-textarea';
import TextInputMixin from 'ghost-admin/mixins/text-input';
import run from 'ember-runloop';
import injectService from 'ember-service/inject';

export default OneWayTextarea.extend(TextInputMixin, {
classNames: 'gh-input'
resizeDetector: injectService(),

classNames: 'gh-input',

autoExpand: false,

willInsertElement() {
this._super(...arguments);

// disable the draggable resize element that browsers add to textareas
if (this.get('autoExpand')) {
this.element.style.resize = 'none';
}
},

didInsertElement() {
this._super(...arguments);

// set up resize handler on element insert so that we can autoexpand
// when the element container changes size
if (this.get('autoExpand')) {
run.scheduleOnce('afterRender', this, this._setupAutoExpand);
}
},

didReceiveAttrs() {
this._super(...arguments);

// trigger auto-expand any time the value changes
if (this.get('autoExpand')) {
run.scheduleOnce('afterRender', this, this._autoExpand);
}
},

willDestroyElement() {
this._teardownAutoExpand();
this._super(...arguments);
},

_autoExpand() {
let el = this.element;

// collapse the element first so that we can shrink as well as expand
// then set the height to match the text height
el.style.height = 0;
el.style.height = `${el.scrollHeight}px`;
},

_setupAutoExpand() {
this._resizeCallback = run.bind(this, this._onResize);
this.get('resizeDetector').setup(this.get('autoExpand'), this._resizeCallback);
this._autoExpand();
},

_onResize() {
this._autoExpand();
},

_teardownAutoExpand() {
this.get('resizeDetector').teardown(this.get('autoExpand'), this._resizeCallback);
}
});
29 changes: 0 additions & 29 deletions app/components/gh-trim-focus-input.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* global device */
import computed from 'ember-computed';
import GhostInput from 'ghost-admin/components/gh-input';

/**
Expand All @@ -12,25 +10,6 @@ const TrimFocusInputComponent = GhostInput.extend({

shouldFocus: true,

attributeBindings: ['autofocus'],

autofocus: computed(function () {
if (this.get('shouldFocus')) {
return (device.ios()) ? false : 'autofocus';
}

return false;
}),

init() {
this._super(...arguments);
},

didInsertElement() {
this._super(...arguments);
this._focus();
},

focusOut(event) {
this._trimInput(event.target.value);
},
Expand All @@ -41,14 +20,6 @@ const TrimFocusInputComponent = GhostInput.extend({
}

this._processNewValue(value);
},

_focus() {
// Until mobile safari has better support
// for focusing, we just ignore it
if (this.get('shouldFocus') && !device.ios()) {
this.element.focus();
}
}
});

Expand Down
46 changes: 44 additions & 2 deletions app/mixins/text-input.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
/* global device */
import Mixin from 'ember-metal/mixin';
import computed from 'ember-computed';

export default Mixin.create({
attributeBindings: ['autofocus'],

selectOnClick: false,
shouldFocus: false,
stopEnterKeyDownPropagation: false,

autofocus: computed(function () {
if (this.get('shouldFocus')) {
return (device.ios()) ? false : 'autofocus';
}

return false;
}),

didInsertElement() {
this._super(...arguments);
this._focus();
},

click(event) {
if (this.get('selectOnClick')) {
event.currentTarget.select();
Expand All @@ -12,12 +30,36 @@ export default Mixin.create({

keyDown(event) {
// stop event propagation when pressing "enter"
// most useful in the case when undesired (global) keyboard shortcuts are getting triggered while interacting
// with this particular input element.
// most useful in the case when undesired (global) keyboard shortcuts
// are getting triggered while interacting with this particular input element.
if (this.get('stopEnterKeyDownPropagation') && event.keyCode === 13) {
event.stopPropagation();

return true;
}

// prevent default TAB behaviour if we have a keyEvent for it
if (event.keyCode === 9 && this.get('keyEvents.9')) {
event.preventDefault();
}

this._super(...arguments);
},

keyPress(event) {
// prevent default ENTER behaviour if we have a keyEvent for it
if (event.keyCode === 13 && this.get('keyEvents.13')) {
event.preventDefault();
}

this._super(...arguments);
},

_focus() {
// Until mobile safari has better support
// for focusing, we just ignore it
if (this.get('shouldFocus') && !device.ios()) {
this.element.focus();
}
}
});
4 changes: 2 additions & 2 deletions app/templates/editor/edit.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@
as |markdown|
}}
<div class="gh-markdown-editor-pane">
{{gh-trim-focus-input model.titleScratch
type="text"
{{gh-textarea model.titleScratch
class="gh-editor-title"
placeholder="Your Post Title"
tabindex="1"
shouldFocus=shouldFocusTitle
autoExpand=".gh-markdown-editor-pane"
focus-out="updateTitle"
update=(action (perform updateTitle))
keyEvents=(hash
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"ember-concurrency": "0.8.3",
"ember-data": "2.13.1",
"ember-data-filter": "1.13.0",
"ember-element-resize-detector": "0.1.5",
"ember-export-application-global": "2.0.0",
"ember-infinity": "0.2.8",
"ember-inline-svg": "0.1.11",
Expand Down

0 comments on commit d49484a

Please sign in to comment.