mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 22:43:30 +03:00
2f8de51d67
closes #4368, fixes #1240 (spellcheck), fixes #4974 & fixes #4983 (caret positioning bugs) - Drop CodeMirror in favour of a plain text area - Use rangyinputs to handle selections cross-browser - Create an API for interacting with the textarea - Replace marker manager with a much simpler image manager - Reimplement shortcuts, including some bug fixes
95 lines
3.0 KiB
JavaScript
95 lines
3.0 KiB
JavaScript
import Ember from 'ember';
|
|
|
|
import setScrollClassName from 'ghost/utils/set-scroll-classname';
|
|
|
|
var EditorScroll = Ember.Mixin.create({
|
|
/**
|
|
* Determine if the cursor is at the end of the textarea
|
|
*/
|
|
isCursorAtEnd: function () {
|
|
var selection = this.$().getSelection(),
|
|
value = this.getValue(),
|
|
linesAtEnd = 3,
|
|
stringAfterCursor,
|
|
match;
|
|
|
|
stringAfterCursor = value.substring(selection.end);
|
|
/* jscs: disable */
|
|
match = stringAfterCursor.match(/\n/g);
|
|
/* jscs: enable */
|
|
|
|
if (!match || match.length < linesAtEnd) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Build an object that represents the scroll state
|
|
*/
|
|
getScrollInfo: function () {
|
|
var scroller = this.get('element'),
|
|
scrollInfo = {
|
|
top: scroller.scrollTop,
|
|
height: scroller.scrollHeight,
|
|
clientHeight: scroller.clientHeight,
|
|
diff: scroller.scrollHeight - scroller.clientHeight,
|
|
padding: 50,
|
|
isCursorAtEnd: this.isCursorAtEnd()
|
|
};
|
|
|
|
return scrollInfo;
|
|
},
|
|
|
|
/**
|
|
* Calculate if we're within scrollInfo.padding of the end of the document, and scroll the rest of the way
|
|
*/
|
|
adjustScrollPosition: function () {
|
|
// If we're receiving change events from the end of the document, i.e the user is typing-at-the-end, update the
|
|
// scroll position to ensure both panels stay in view and in sync
|
|
var scrollInfo = this.getScrollInfo();
|
|
if (scrollInfo.isCursorAtEnd && (scrollInfo.diff >= scrollInfo.top) &&
|
|
(scrollInfo.diff < scrollInfo.top + scrollInfo.padding)) {
|
|
scrollInfo.top += scrollInfo.padding;
|
|
// Scroll the left pane
|
|
this.$().scrollTop(scrollInfo.top);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Send the scrollInfo for scrollEvents to the view so that the preview pane can be synced
|
|
*/
|
|
scrollHandler: function () {
|
|
this.set('scrollThrottle', Ember.run.throttle(this, function () {
|
|
this.set('scrollInfo', this.getScrollInfo());
|
|
}, 10));
|
|
},
|
|
|
|
/**
|
|
* once the element is in the DOM bind to the events which control scroll behaviour
|
|
*/
|
|
attachScrollHandlers: function () {
|
|
var $el = this.$();
|
|
|
|
$el.on('keypress', Ember.run.bind(this, this.adjustScrollPosition));
|
|
|
|
$el.on('scroll', Ember.run.bind(this, this.scrollHandler));
|
|
$el.on('scroll', Ember.run.bind($el, setScrollClassName, {
|
|
target: Ember.$('.js-entry-markdown'),
|
|
offset: 10
|
|
}));
|
|
}.on('didInsertElement'),
|
|
|
|
/**
|
|
* once the element is in the DOM unbind from the events which control scroll behaviour
|
|
*/
|
|
detachScrollHandlers: function () {
|
|
this.$().off('keypress');
|
|
this.$().off('scroll');
|
|
Ember.run.cancel(this.get('scrollThrottle'));
|
|
}.on('willDestroyElement')
|
|
});
|
|
|
|
export default EditorScroll;
|