Ghost/ghost/admin/app/components/gh-cm-editor.js
Kevin Ansfield 2231dd84c2 Migrated to <AngleBracketSyntax /> (#1460)
no issue

Ember is migrating to `<AngleBracketSyntax />` for component invocation, see https://github.com/emberjs/rfcs/blob/master/text/0311-angle-bracket-invocation.md

We were in a half-way situation where some templates used angle bracket syntax in some places, this PR updates templates to use the syntax everywhere.

This simplifies the rules for what template code is referring to...

`<Component>` = a component
`{{helper}}` = a helper (or locally assigned handlebars variable)
`{{this.foo}}` = data on the template backing context (a component/controller)
`{{@foo}}` = a named argument passed into the component that the component backing class has not modified (note: this commit does not introduce any named arguments)

- ran codemod https://github.com/ember-codemods/ember-angle-brackets-codemod on the following directories:
  - `app/templates`
  - `lib/koenig-editor/addon/templates`
- removed positional params from components as angle bracket syntax does not support them
  - `gh-feature-flag`
  - `gh-tour-item`
  - `gh-cm-editor`
  - `gh-fullscreen-modal`
  - `gh-task-button`
- updates some code that was missed in 3c851293c1 to use explicit this
2020-01-16 15:14:03 +00:00

123 lines
3.5 KiB
JavaScript

/* global CodeMirror */
import Component from '@ember/component';
import boundOneWay from 'ghost-admin/utils/bound-one-way';
import {assign} from '@ember/polyfills';
import {bind, once, scheduleOnce} from '@ember/runloop';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
const CmEditorComponent = Component.extend({
lazyLoader: service(),
classNameBindings: ['isFocused:focus'],
textareaClass: '',
isFocused: false,
// options for the editor
autofocus: false,
indentUnit: 4,
lineNumbers: true,
lineWrapping: false,
mode: 'htmlmixed',
theme: 'xq-light',
_editor: null, // reference to CodeMirror editor
// Allowed actions
'focus-in': () => {},
update: () => {},
_value: boundOneWay('value'), // make sure a value exists
didReceiveAttrs() {
if (this._value === null || undefined) {
this.set('_value', '');
}
if (this.mode !== this._lastMode && this._editor) {
this._editor.setOption('mode', this.mode);
}
this._lastMode = this.mode;
},
didInsertElement() {
this._super(...arguments);
this.initCodeMirror.perform();
},
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;
}
},
actions: {
updateFromTextarea(value) {
this.update(value);
}
},
initCodeMirror: task(function* () {
let loader = this.lazyLoader;
yield loader.loadScript('codemirror', 'assets/codemirror/codemirror.js');
scheduleOnce('afterRender', this, this._initCodeMirror);
}),
_initCodeMirror() {
let options = this.getProperties('lineNumbers', 'lineWrapping', 'indentUnit', 'mode', 'theme', 'autofocus');
assign(options, {value: this._value});
let textarea = this.element.querySelector('textarea');
if (textarea && textarea === document.activeElement) {
options.autofocus = true;
}
this._editor = new CodeMirror.fromTextArea(textarea, options);
// by default CodeMirror will place the cursor at the beginning of the
// content, it makes more sense for the cursor to be at the end
if (options.autofocus) {
this._editor.setCursor(this._editor.lineCount(), 0);
}
// events
this._setupCodeMirrorEventHandler('focus', this, this._focus);
this._setupCodeMirrorEventHandler('blur', this, this._blur);
this._setupCodeMirrorEventHandler('change', this, this._update);
},
_setupCodeMirrorEventHandler(event, target, method) {
let callback = bind(target, method);
this._editor.on(event, callback);
this.one('willDestroyElement', this, function () {
this._editor.off(event, callback);
});
},
_update(codeMirror, changeObj) {
once(this, this.update, codeMirror.getValue(), codeMirror, changeObj);
},
_focus(codeMirror, event) {
this.set('isFocused', true);
once(this, this['focus-in'], codeMirror.getValue(), codeMirror, event);
},
_blur(/* codeMirror, event */) {
this.set('isFocused', false);
}
});
export default CmEditorComponent;