mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 22:02:11 +03:00
5724a94fbc
Refs: https://github.com/TryGhost/Ghost/issues/8191 Refs: https://github.com/TryGhost/Ghost/issues/8194 Changes the selection behaviour of mobiledoc-cards: If you navigate to a card with a keyboard or click on the new editor toolbar it "hard selects". If you click into the body of a card to edit it it "soft selects". When a card is "hard selected" you can navigate out of the card and to the previous or following blocks within the mobiledoc with the keyboard, you can delete the current card with the backspace or delete button, and you can create a new block following the card with the enter key. When a card is soft selected it is simply displayed as selected and allows the user to edit content within the card. New card toolbar: Allows a user to delete the card, save the card, and "hard select" a card. New title behaviour: Pressing the enter key within the title "splits" the title at the cursor point, if multiple characters are selected they are first deleted, and creates a new paragraph at the top of the document with the trailing characters after the split. gh-cm-editor updates: Adds an on-focus event to gh-cm-editor
84 lines
2.4 KiB
JavaScript
84 lines
2.4 KiB
JavaScript
/* global CodeMirror */
|
|
import Component from 'ember-component';
|
|
import run, {bind, scheduleOnce} from 'ember-runloop';
|
|
import injectService from 'ember-service/inject';
|
|
import RSVP from 'rsvp';
|
|
|
|
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
|
import {InvokeActionMixin} from 'ember-invoke-action';
|
|
|
|
const CmEditorComponent = Component.extend(InvokeActionMixin, {
|
|
classNameBindings: ['isFocused:focused'],
|
|
|
|
_value: boundOneWay('value'), // make sure a value exists
|
|
isFocused: false,
|
|
|
|
// options for the editor
|
|
lineNumbers: true,
|
|
indentUnit: 4,
|
|
mode: 'htmlmixed',
|
|
theme: 'xq-light',
|
|
|
|
_editor: null, // reference to CodeMirror editor
|
|
|
|
lazyLoader: injectService(),
|
|
|
|
didInsertElement() {
|
|
this._super(...arguments);
|
|
|
|
let loader = this.get('lazyLoader');
|
|
|
|
RSVP.all([
|
|
loader.loadStyle('codemirror', 'assets/codemirror/codemirror.css'),
|
|
loader.loadScript('codemirror', 'assets/codemirror/codemirror.js')
|
|
]).then(() => {
|
|
scheduleOnce('afterRender', this, function () {
|
|
this._initCodeMirror();
|
|
});
|
|
});
|
|
},
|
|
|
|
_initCodeMirror() {
|
|
let options = this.getProperties('lineNumbers', 'indentUnit', 'mode', 'theme');
|
|
let editor = new CodeMirror(this.element, options);
|
|
|
|
editor.getDoc().setValue(this.get('_value'));
|
|
|
|
// events
|
|
editor.on('focus', () => {
|
|
|
|
run(this, function() {
|
|
this.set('isFocused', true);
|
|
this.invokeAction('focus-in', editor.getDoc().getValue());
|
|
});
|
|
});
|
|
editor.on('blur', bind(this, 'set', 'isFocused', false));
|
|
editor.on('change', () => {
|
|
run(this, function () {
|
|
this.invokeAction('update', editor.getDoc().getValue());
|
|
});
|
|
});
|
|
|
|
this._editor = editor;
|
|
},
|
|
|
|
willDestroyElement() {
|
|
this._super(...arguments);
|
|
|
|
// Ensure the editor exists before trying to destroy it. This fixes
|
|
// an error that occurs if codemirror hasn't finished loading before
|
|
// the component is destroyed.
|
|
if (this._editor) {
|
|
let editor = this._editor.getWrapperElement();
|
|
editor.parentNode.removeChild(editor);
|
|
this._editor = null;
|
|
}
|
|
}
|
|
});
|
|
|
|
CmEditorComponent.reopenClass({
|
|
positionalParams: ['value']
|
|
});
|
|
|
|
export default CmEditorComponent;
|