Ghost/core/client/app/mixins/ed-editor-scroll.js
Hannah Wolfe 5db6fc4f18 No more CodeMirror
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
2015-03-17 14:32:55 +00:00

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;