Koenig reboot - rich text (#952)

refs https://github.com/TryGhost/Ghost/issues/9311

Koenig is being fully rebooted, first port of call is to focus on getting the rich-text only aspect of mobiledoc-kit working with our popup toolbar.

- renames old koenig implementation (used for reference, will eventually be deleted)
- new `{{koenig-editor}}` mobiledoc-kit component implementation based on ember-mobiledoc-editor
  - markdown text expansions
- new `{{gh-koenig-edtor}}` that wraps our title+editor and handles keyboard navigation between the two
  - clicks below content will focus the editor
- new `{{koenig-toolbar}}` component for the popup formatting toolbar with improved behaviour and simplified code
This commit is contained in:
Kevin Ansfield 2018-01-30 10:01:07 +00:00 committed by GitHub
parent 7013b269ce
commit 3d341e2dd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
114 changed files with 1308 additions and 166 deletions

View File

@ -0,0 +1,120 @@
import Component from '@ember/component';
export default Component.extend({
// public attrs
tagName: '',
title: '',
titlePlaceholder: '',
body: null,
bodyPlaceholder: '',
bodyAutofocus: false,
// internal properties
_title: null,
_editor: null,
// closure actions
onTitleChange() {},
onTitleBlur() {},
onBodyChange() {},
actions: {
// triggered when a click is registered on .gh-koenig-editor-pane
focusEditor(event) {
// if a click occurs on the editor canvas, focus the editor and put
// the cursor at the end of the document. Allows for a much larger
// hit area for focusing the editor when it has no or little content
if (event.target.tagName === 'ARTICLE' && event.target.classList.contains('koenig-editor')) {
let {post} = this._editor;
let range = post.toRange();
event.preventDefault();
this._editor.focus();
this._editor.run((postEditor) => {
postEditor.setRange(range.tail.section.tailPosition());
});
}
},
/* title related actions -------------------------------------------- */
onTitleCreated(titleElement) {
this._title = titleElement;
},
onTitleChange(newTitle) {
this.onTitleChange(newTitle);
},
onTitleFocusOut() {
this.onTitleBlur();
},
onTitleKeydown(event) {
let value = event.target.value;
let selectionStart = event.target.selectionStart;
// enter will always focus the editor
// down arrow will only focus the editor when the cursor is at the
// end of the input to preserve the default OS behaviour
if (
event.key === 'Enter' ||
event.key === 'Tab' ||
(event.key === 'ArrowDown' && (!value || selectionStart === value.length))
) {
event.preventDefault();
this._editor.focus();
}
},
/* body related actions --------------------------------------------- */
onEditorCreated(editor) {
this._setupEditor(editor);
},
onBodyChange(newMobiledoc) {
this.onBodyChange(newMobiledoc);
}
},
/* public methods ------------------------------------------------------- */
/* internal methods ----------------------------------------------------- */
_setupEditor(editor) {
let component = this;
this._editor = editor;
// focus the title when pressing UP if cursor is at the beginning of doc
editor.registerKeyCommand({
str: 'UP',
run(editor) {
let cursorHead = editor.cursor.offsets.head;
if (
editor.hasCursor()
&& cursorHead.offset === 0
&& (!cursorHead.section || !cursorHead.section.prev)
) {
component._title.focus();
return true;
}
return false;
}
});
// focus the title when pressing SHIFT+TAB
editor.registerKeyCommand({
str: 'SHIFT+TAB',
run() {
component._title.focus();
return true;
}
});
}
});

View File

@ -27,6 +27,10 @@ export default OneWayTextarea.extend(TextInputMixin, {
if (this.get('autoExpand')) {
run.scheduleOnce('afterRender', this, this._setupAutoExpand);
}
if (this.get('didCreateTextarea')) {
this.get('didCreateTextarea')(this.element);
}
},
willDestroyElement() {

View File

@ -5,7 +5,7 @@ import attr from 'ember-data/attr';
import boundOneWay from 'ghost-admin/utils/bound-one-way';
import moment from 'moment';
import {BLANK_DOC as BLANK_MARKDOWN} from 'ghost-admin/components/gh-markdown-editor';
import {BLANK_DOC as BLANK_MOBILEDOC} from 'gh-koenig/components/gh-koenig';
import {BLANK_DOC as BLANK_MOBILEDOC} from 'koenig-editor/components/koenig-editor';
import {belongsTo, hasMany} from 'ember-data/relationships';
import {compare} from '@ember/utils';
import {computed} from '@ember/object';
@ -344,8 +344,8 @@ export default Model.extend(Comparable, ValidationEngine, {
isCompatibleWithMarkdownEditor() {
let mobiledoc = this.get('mobiledoc');
if (
mobiledoc.markups.length === 0
if (mobiledoc
&& mobiledoc.markups.length === 0
&& mobiledoc.cards.length === 1
&& mobiledoc.cards[0][0] === 'card-markdown'
&& mobiledoc.sections.length === 1

View File

@ -34,6 +34,7 @@
@import "components/popovers.css";
@import "components/tour.css";
@import "components/unsplash.css";
@import "components/koenig";
/* Layouts: Groups of Components
@ -54,11 +55,6 @@
@import "layouts/subscribers.css";
/* Addons: gh-koenig
/* ---------------------------------------------------------- */
@import "addons/gh-koenig/gh-koenig.css";
:root {
--darkgrey: #e5eff5;
--midgrey: #738a94;

View File

@ -34,6 +34,7 @@
@import "components/popovers.css";
@import "components/tour.css";
@import "components/unsplash.css";
@import "components/koenig";
/* Layouts: Groups of Components
@ -54,11 +55,6 @@
@import "layouts/subscribers.css";
/* Addons: gh-koenig
/* ---------------------------------------------------------- */
@import "addons/gh-koenig/gh-koenig.css";
/* ---------------------------✈️----------------------------- */
/* I COMMITTED THIS COMMENT FROM A PLANE: http://bit.ly/2on5pmq
/* --------------------------------------------------------- */

View File

@ -0,0 +1,345 @@
/* TODO: move these back into the editor.css layout? */
/* scrollable container */
.gh-koenig-editor {
position: relative;
z-index: 0;
width: 100%;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}
/* padded container housing title + editor canvas, scrollable content */
.gh-koenig-editor-pane {
display: flex;
flex-direction: column;
min-height: 100%;
padding: 10vw 4vw;
}
@media (max-width: 500px) {
.gh-koenig-editor-pane {
padding: 15vw 4vw;
}
}
/* use flex-grow to fill the available vertical space so clicks outside the
editor content can trigger focus */
.gh-koenig-editor-pane .koenig-editor {
width: 100%;
flex-grow: 1;
cursor: text;
}
/* NOTE: everything from this point should be Koenig addon specific */
/* Editor canvas layout ----------------------------------------------------- */
.koenig-editor {
position: relative; /* necessary to position toolbar etc */
max-width: 760px;
margin: 0 auto;
}
/* Formatting Toolbar ------------------------------------------------------- */
.koenig-toolbar {
position: absolute;
display: flex;
align-items: center;
text-align: center;
user-select: none;
cursor: pointer;
color: color(var(--lightgrey) l(-10%));
background: linear-gradient(
color(var(--darkgrey) l(-3%)),
color(var(--darkgrey) l(-8%))
);
border-radius: 5px;
box-shadow: 0 0 0 1px color(var(--darkgrey) l(-10%)), 0 8px 16px rgba(26,39,49,0.16), rgba(255,255,255,0.09) 0 1px 0 0 inset;
z-index:110; /* places it above the title */
pointer-events: none !important; /* no interactivity when hidden */
opacity: 0;
transition-property: opacity;
transition-duration: 300ms;
}
.koenig-toolbar--visible {
pointer-events: auto !important; /* make sure the buttons work */
opacity: 1;
}
.koenig-toolbar:after {
display: block;
content: "";
position: absolute;
bottom: -8px;
left: 50%;
margin-left: -10px;
width: 0;
height: 0;
border-left: transparent 10px solid;
border-right: transparent 10px solid;
border-top: color(var(--darkgrey) l(-10%)) 8px solid;
transition-property: left;
transition-duration: 100ms;
}
.koenig-toolbar.tick-above:after {
border: none;
}
.koenig-toolbar.is-link {
width: 263px;
height: 40px;
}
.koenig-toolbar.is-link input {
width: 100%;
background-color: transparent;
outline: none;
border: none;
padding:5px;
}
.koenig-toolbar.is-touch {
position: fixed !important;
top: 70px;
right: 40px;
}
.koenig-toolbar.is-touch:after {
border: none;
}
.koenig-toolbar-btn {
display: flex;
justify-content: center;
align-items: center;
height: 40px;
width: 32px;
font-size: 1.6rem;
line-height: 40px;
transition: text-shadow 0.3s ease;
}
.koenig-toolbar-btn:first-child {
width: 43px;
padding-left: 8px;
}
.koenig-toolbar-btn:last-child {
width: 43px;
padding-right: 8px;
}
.koenig-toolbar-btn svg {
height: 1.4rem;
}
.koenig-toolbar-btn svg g {
stroke-width: 2px;
stroke: color(var(--lightgrey) l(-10%));
}
.koenig-toolbar-btn:hover,
.koenig-toolbar-btn.selected {
color: #fff;
cursor: pointer;
text-shadow: #000 0 1px 6px;
}
.koenig-toolbar-btn:hover svg g {
stroke: #fff;
}
.koenig-toolbar-btn-bold {
font-weight: 700;
}
.koenig-toolbar-btn-italic {
width: 31px;
font-size: 1.7rem;
text-indent: -1px;
font-style: italic;
font-family: Georgia, Times, serif;
font-weight: 500;
}
.koenig-toolbar-btn-strike {
text-decoration: line-through;
font-weight: 400;
-webkit-font-smoothing: antialiased;
}
.koenig-toolbar-btn-h1 {
font-variant: small-caps;
font-weight: 700;
-webkit-font-smoothing: antialiased;
}
.koenig-toolbar-btn-h2 {
font-weight: 700;
font-size: 0.9em;
font-variant: small-caps;
line-height: 42px;
-webkit-font-smoothing: antialiased;
}
.koenig-toolbar-btn-quote {
font-size: 4rem;
line-height: 62px;
font-family: Georgia, Times, serif;
-webkit-font-smoothing: antialiased;
}
.koenig-toolbar-divider {
height: 40px;
width: 1px;
margin: 0 9px 0 8px;
background: color(var(--darkgrey) l(-10%));
box-shadow: rgba(255,255,255,0.04) 1px 0 0 0;
}
/* ⨁ menu ------------------------------------------------------------------ */
/* Slash shortcut menu ------------------------------------------------------ */
/* Menu items --------------------------------------------------------------- */
/* mobiledoc-kit base styles ------------------------------------------------
* NOTE: adapted from https://github.com/bustle/mobiledoc-kit/blob/master/src/css/mobiledoc-kit.css
*/
/**
* Editor
*/
/* TODO: update to match Ghost styles */
.__mobiledoc-editor {
position: relative;
font-family: var(--font-family);
font-size: 1.7rem;
resize: none;
font-weight: 200;
letter-spacing: 0.1px;
min-height: 1em;
}
.__mobiledoc-editor:focus {
outline: none;
}
.__mobiledoc-editor > * {
position: relative;
}
.__mobiledoc-editor.__has-no-content:after {
content: attr(data-placeholder);
color: #bbb;
cursor: text;
position: absolute;
top: 0;
}
.__mobiledoc-editor a {
color: #0b8bff;
white-space: nowrap;
}
/* override of global.css block display */
.__mobiledoc-editor i {
display: inline;
}
.__mobiledoc-editor h1,
.__mobiledoc-editor h2,
.__mobiledoc-editor h3,
.__mobiledoc-editor h4,
.__mobiledoc-editor h5,
.__mobiledoc-editor h6 {
font-weight: 800;
letter-spacing: -0.02em;
}
.__mobiledoc-editor blockquote {
border-left: 4px solid #0b8bff;
margin: 1em 0 1em -1.2em;
padding-left: 1.05em;
color: #a0a0a0;
}
.__mobiledoc-editor img {
display: block;
max-width: 100%;
margin: 0 auto;
}
.__mobiledoc-editor div,
.__mobiledoc-editor iframe {
max-width: 100%;
}
/**
* Cards
*/
.__mobiledoc-card {
display: inline-block;
}
/**
* Tooltips
*/
@-webkit-keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
.__mobiledoc-tooltip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 0.7em;
white-space: nowrap;
position: absolute;
background-color: rgba(43,43,43,0.9);
border-radius: 3px;
line-height: 1em;
padding: 0.7em 0.9em;
color: #FFF;
-webkit-animation: fade-in 0.2s;
animation: fade-in 0.2s;
}
.__mobiledoc-tooltip:before {
content: '';
position: absolute;
left: 50%;
width: 0;
height: 0;
border-left: 0.4em solid transparent;
border-right: 0.4em solid transparent;
border-bottom: 0.4em solid rgba(43,43,43,0.9);
top: -0.4em;
margin-left: -0.4em;
}
/* help keeps mouseover state when moving from link to tooltip */
.__mobiledoc-tooltip:after {
content: '';
position: absolute;
left: 0;
right: 0;
top: -0.4em;
height: 0.4em;
}
.__mobiledoc-tooltip a {
color: #FFF;
text-decoration: none;
}
.__mobiledoc-tooltip a:hover {
text-decoration: underline;
}

View File

@ -0,0 +1,25 @@
{{!-- scrollable container --}}
<div class="gh-koenig-editor">
{{!-- full height content pane --}}
<div class="gh-koenig-editor-pane" onclick={{action "focusEditor"}}>
{{gh-textarea title
class="gh-editor-title"
placeholder=titlePlaceholder
tabindex="1"
autoExpand=".gh-koenig-editor"
update=(action "onTitleChange")
focusOut=(action "onTitleFocusOut")
keyDown=(action "onTitleKeydown")
didCreateTextarea=(action "onTitleCreated")
}}
{{koenig-editor
mobiledoc=body
placeholder=bodyPlaceholder
autofocus=bodyAutofocus
spellcheck=true
onChange=(action "onBodyChange")
didCreateEditor=(action "onEditorCreated")
}}
</div>
</div>

View File

@ -33,44 +33,20 @@
</header>
{{#if useKoenig}}
<div class="gh-editor-container needsclick">
<div class="gh-editor-inner">
{{!--
NOTE: the mobiledoc property is unbound so that the setting the
serialized version onChange doesn't cause a deserialization and
re-render of the editor on every key press / editor change
TODO: note above is no longer correct, changed to readonly to
fix a persistent editor content bug that occurred due to the
editor not being re-rendered on edit->new transition.
Needs perf investigation!
--}}
{{#gh-koenig
mobiledoc=(readonly model.scratch)
onChange=(action "updateScratch")
autofocus=shouldFocusEditor
tabindex="2"
titleSelector="#kg-title-input"
containerSelector=".gh-editor-container"
wordcountDidChange=(action "setWordcount")
as |koenig|
}}
{{koenig-title-input
id="koenig-title-input"
val=(readonly model.titleScratch)
onChange=(action "updateTitleScratch")
tabindex="1"
autofocus=shouldFocusTitle
focusOut=(action (perform saveTitle))
editor=(readonly koenig.editor)
editorHasRendered=koenig.hasRendered
editorMenuIsOpen=koenig.isMenuOpen
}}
{{/gh-koenig}}
</div>
</div>
<div class="gh-editor-wordcount">{{pluralize wordcount 'word'}}.</div>
{{!--
gh-koenig-editor acts as a wrapper around the title input and
koenig editor canvas to support Ghost-specific editor behaviour
--}}
{{gh-koenig-editor
title=(readonly post.titleScratch)
titlePlaceholder="Story Title"
onTitleChange=(action "updateTitleScratch")
onTitleBlur=(action (perform saveTitle))
body=(readonly post.scratch)
bodyPlaceholder="Begin writing your story..."
bodyAutofocus=shouldFocusEditor
onBodyChange=(action "updateScratch")
}}
{{else}}

View File

Before

Width:  |  Height:  |  Size: 447 B

After

Width:  |  Height:  |  Size: 447 B

View File

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 466 B

View File

Before

Width:  |  Height:  |  Size: 740 B

After

Width:  |  Height:  |  Size: 740 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 745 B

View File

Before

Width:  |  Height:  |  Size: 810 B

After

Width:  |  Height:  |  Size: 810 B

View File

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 364 B

View File

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 689 B

View File

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 696 B

View File

Before

Width:  |  Height:  |  Size: 675 B

After

Width:  |  Height:  |  Size: 675 B

View File

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 819 B

View File

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 820 B

View File

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 442 B

View File

@ -0,0 +1,270 @@
/*
* Based on ember-mobiledoc-editor
* https://github.com/bustle/ember-mobiledoc-editor
*/
import Component from '@ember/component';
import Editor from 'mobiledoc-kit/editor/editor';
import Ember from 'ember';
import layout from '../templates/components/koenig-editor';
import registerTextExpansions from '../options/text-expansions';
import {MOBILEDOC_VERSION} from 'mobiledoc-kit/renderers/mobiledoc';
import {assign} from '@ember/polyfills';
import {camelize, capitalize} from '@ember/string';
import {computed} from '@ember/object';
import {run} from '@ember/runloop';
// used in test helpers to grab a reference to the underlying mobiledoc editor
export const TESTING_EXPANDO_PROPERTY = '__mobiledoc_kit_editor';
// blank doc contains a single empty paragraph so that there's some content for
// the cursor to start in
export const BLANK_DOC = {
version: MOBILEDOC_VERSION,
markups: [],
atoms: [],
cards: [],
sections: [
[1, 'p', [
[0, [], 0, '']
]]
]
};
function arrayToMap(array) {
let map = Object.create(null);
array.forEach((key) => {
if (key) { // skip undefined/falsy key values
key = `is${capitalize(camelize(key))}`;
map[key] = true;
}
});
return map;
}
export default Component.extend({
layout,
tagName: 'article',
classNames: ['koenig-editor'],
// public attrs
mobiledoc: null,
placeholder: 'Write here...',
autofocus: false,
spellcheck: true,
options: null,
scrollContainer: '',
// internal properties
editor: null,
activeMarkupTagNames: null,
activeSectionTagNames: null,
selectedRange: null,
// private properties
_localMobiledoc: null,
_upstreamMobiledoc: null,
_startedRunLoop: false,
_lastIsEditingDisabled: false,
_isRenderingEditor: false,
// closure actions
willCreateEditor() {},
didCreateEditor() {},
onChange() {},
/* computed properties -------------------------------------------------- */
// merge in named options with the `options` property data-bag
editorOptions: computed(function () {
let options = this.get('options') || {};
return assign({
placeholder: this.get('placeholder'),
spellcheck: this.get('spellcheck'),
autofocus: this.get('autofocus')
}, options);
}),
/* lifecycle hooks ------------------------------------------------------ */
init() {
this._super(...arguments);
// set a blank mobiledoc if we didn't receive anything
let mobiledoc = this.get('mobiledoc');
if (!mobiledoc) {
mobiledoc = BLANK_DOC;
this.set('mobiledoc', mobiledoc);
}
this._startedRunLoop = false;
},
willRender() {
// use a default mobiledoc. If there are no changes then return early
let mobiledoc = this.get('mobiledoc') || BLANK_DOC;
let mobiledocIsSame =
(this._localMobiledoc && this._localMobiledoc === mobiledoc) ||
(this._upstreamMobiledoc && this._upstreamMobiledoc === mobiledoc);
let isEditingDisabledIsSame =
this._lastIsEditingDisabled === this.get('isEditingDisabled');
// no change to mobiledoc, no need to recreate the editor
if (mobiledocIsSame && isEditingDisabledIsSame) {
return;
}
// update our internal references
this._lastIsEditingDisabled = this.get('isEditingDisabled');
this._upstreamMobiledoc = mobiledoc;
this._localMobiledoc = null;
// trigger the willCreateEditor closure action
this.willCreateEditor();
// teardown any old editor that might be around
let editor = this.get('editor');
if (editor) {
editor.destroy();
}
// create a new editor
let editorOptions = this.get('editorOptions');
editorOptions.mobiledoc = mobiledoc;
editor = new Editor(editorOptions);
// set up key commands and text expansions (MD conversion)
registerTextExpansions(editor);
// set up editor hooks
editor.willRender(() => {
// The editor's render/rerender will happen after this `editor.willRender`,
// so we explicitly start a runloop here if there is none, so that the
// add/remove card hooks happen inside a runloop.
// When pasting text that gets turned into a card, for example,
// the add card hook would run outside the runloop if we didn't begin a new
// one now.
if (!run.currentRunLoop) {
this._startedRunLoop = true;
run.begin();
}
});
editor.didRender(() => {
// if we had explicitly started a runloop in `editor.willRender`,
// we must explicitly end it here
if (this._startedRunLoop) {
this._startedRunLoop = false;
run.end();
}
});
editor.postDidChange(() => {
run.join(() => {
this.postDidChange(editor);
});
});
editor.cursorDidChange(() => {
run.join(() => {
this.cursorDidChange(editor);
});
});
editor.inputModeDidChange(() => {
if (this.isDestroyed) {
return;
}
run.join(() => {
this.inputModeDidChange(editor);
});
});
if (this.get('isEditingDisabled')) {
editor.disableEditing();
}
this.set('editor', editor);
this.didCreateEditor(editor);
},
// our ember component has rendered, now we need to render the mobiledoc
// editor itself if necessary
didRender() {
this._super(...arguments);
let editor = this.get('editor');
if (!editor.hasRendered) {
let editorElement = this.element.querySelector('.koenig-editor__editor');
this._isRenderingEditor = true;
editor.render(editorElement);
this._isRenderingEditor = false;
}
},
willDestroyElement() {
let editor = this.get('editor');
editor.destroy();
this._super(...arguments);
},
actions: {
toggleMarkup(markupTagName) {
let editor = this.get('editor');
editor.toggleMarkup(markupTagName);
},
toggleSection(sectionTagName) {
let editor = this.get('editor');
editor.toggleSection(sectionTagName);
}
},
/* public methods ------------------------------------------------------- */
postDidChange(editor) {
let serializeVersion = this.get('serializeVersion');
let updatedMobiledoc = editor.serialize(serializeVersion);
this._localMobiledoc = updatedMobiledoc;
// trigger closure action
this.onChange(updatedMobiledoc);
},
cursorDidChange(editor) {
this.set('selectedRange', editor.range);
},
// fired when the active section(s) or markup(s) at the current cursor
// position or selection have changed. We use this event to update the
// activeMarkup/section tag lists which control button states in our popup
// toolbar
inputModeDidChange(editor) {
let markupTags = arrayToMap(editor.activeMarkups.map(m => m.tagName));
// editor.activeSections are leaf sections.
// Map parent section tag names (e.g. 'p', 'ul', 'ol') so that list buttons
// are updated.
// eslint-disable-next-line no-confusing-arrow
let sectionParentTagNames = editor.activeSections.map(s => s.isNested ? s.parent.tagName : s.tagName);
let sectionTags = arrayToMap(sectionParentTagNames);
// Avoid updating this component's properties synchronously while
// rendering the editor (after rendering the component) because it
// causes Ember to display deprecation warnings
if (this._isRenderingEditor) {
run.schedule('afterRender', () => {
this.set('activeMarkupTagNames', markupTags);
this.set('activeSectionTagNames', sectionTags);
});
} else {
this.set('activeMarkupTagNames', markupTags);
this.set('activeSectionTagNames', sectionTags);
}
},
/* internal methods ----------------------------------------------------- */
// store a reference to the editor for the acceptance test helpers
_setExpandoProperty(editor) {
if (this.element && Ember.testing) {
this.element[TESTING_EXPANDO_PROPERTY] = editor;
}
}
});

Some files were not shown because too many files have changed in this diff Show More