- {{!--
- 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}}
-
-
-
{{pluralize wordcount 'word'}}.
+ {{!--
+ 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}}
diff --git a/ghost/admin/lib/gh-koenig/.gitignore b/ghost/admin/lib/gh-koenig--old/.gitignore
similarity index 100%
rename from ghost/admin/lib/gh-koenig/.gitignore
rename to ghost/admin/lib/gh-koenig--old/.gitignore
diff --git a/ghost/admin/lib/gh-koenig/README.md b/ghost/admin/lib/gh-koenig--old/README.md
similarity index 100%
rename from ghost/admin/lib/gh-koenig/README.md
rename to ghost/admin/lib/gh-koenig--old/README.md
diff --git a/ghost/admin/lib/gh-koenig/addon/.gitkeep b/ghost/admin/lib/gh-koenig--old/addon/.gitkeep
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/.gitkeep
rename to ghost/admin/lib/gh-koenig--old/addon/.gitkeep
diff --git a/ghost/admin/lib/gh-koenig/addon/cards/card-hr_dom.js b/ghost/admin/lib/gh-koenig--old/addon/cards/card-hr_dom.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/cards/card-hr_dom.js
rename to ghost/admin/lib/gh-koenig--old/addon/cards/card-hr_dom.js
diff --git a/ghost/admin/lib/gh-koenig/addon/cards/card-html_dom.js b/ghost/admin/lib/gh-koenig--old/addon/cards/card-html_dom.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/cards/card-html_dom.js
rename to ghost/admin/lib/gh-koenig--old/addon/cards/card-html_dom.js
diff --git a/ghost/admin/lib/gh-koenig/addon/cards/card-image_dom.js b/ghost/admin/lib/gh-koenig--old/addon/cards/card-image_dom.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/cards/card-image_dom.js
rename to ghost/admin/lib/gh-koenig--old/addon/cards/card-image_dom.js
diff --git a/ghost/admin/lib/gh-koenig/addon/cards/card-markdown_dom.js b/ghost/admin/lib/gh-koenig--old/addon/cards/card-markdown_dom.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/cards/card-markdown_dom.js
rename to ghost/admin/lib/gh-koenig--old/addon/cards/card-markdown_dom.js
diff --git a/ghost/admin/lib/gh-koenig/addon/cards/index.js b/ghost/admin/lib/gh-koenig--old/addon/cards/index.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/cards/index.js
rename to ghost/admin/lib/gh-koenig--old/addon/cards/index.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/cards/card-hr.js b/ghost/admin/lib/gh-koenig--old/addon/components/cards/card-hr.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/cards/card-hr.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/cards/card-hr.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/cards/card-html.js b/ghost/admin/lib/gh-koenig--old/addon/components/cards/card-html.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/cards/card-html.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/cards/card-html.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/cards/card-image.js b/ghost/admin/lib/gh-koenig--old/addon/components/cards/card-image.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/cards/card-image.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/cards/card-image.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/cards/card-markdown.js b/ghost/admin/lib/gh-koenig--old/addon/components/cards/card-markdown.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/cards/card-markdown.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/cards/card-markdown.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/gh-koenig.js b/ghost/admin/lib/gh-koenig--old/addon/components/gh-koenig.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/gh-koenig.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/gh-koenig.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-card.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-card.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-card.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-card.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-menu-item.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-menu-item.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-menu-item.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-menu-item.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-plus-menu.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-plus-menu.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-plus-menu.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-plus-menu.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-slash-menu.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-slash-menu.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-slash-menu.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-slash-menu.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-title-input.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-title-input.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-title-input.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-title-input.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-blockitem.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-blockitem.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-blockitem.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-blockitem.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-button.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-button.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-button.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-button.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-newitem.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-newitem.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar-newitem.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar-newitem.js
diff --git a/ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar.js b/ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/components/koenig-toolbar.js
rename to ghost/admin/lib/gh-koenig--old/addon/components/koenig-toolbar.js
diff --git a/ghost/admin/lib/gh-koenig/addon/lib/caja-sanitizers.js b/ghost/admin/lib/gh-koenig--old/addon/lib/caja-sanitizers.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/lib/caja-sanitizers.js
rename to ghost/admin/lib/gh-koenig--old/addon/lib/caja-sanitizers.js
diff --git a/ghost/admin/lib/gh-koenig/addon/lib/card-factory.js b/ghost/admin/lib/gh-koenig--old/addon/lib/card-factory.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/lib/card-factory.js
rename to ghost/admin/lib/gh-koenig--old/addon/lib/card-factory.js
diff --git a/ghost/admin/lib/gh-koenig/addon/lib/utils.js b/ghost/admin/lib/gh-koenig--old/addon/lib/utils.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/lib/utils.js
rename to ghost/admin/lib/gh-koenig--old/addon/lib/utils.js
diff --git a/ghost/admin/lib/gh-koenig/addon/options/default-tools.js b/ghost/admin/lib/gh-koenig--old/addon/options/default-tools.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/options/default-tools.js
rename to ghost/admin/lib/gh-koenig--old/addon/options/default-tools.js
diff --git a/ghost/admin/lib/gh-koenig/addon/options/key-commands.js b/ghost/admin/lib/gh-koenig--old/addon/options/key-commands.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/options/key-commands.js
rename to ghost/admin/lib/gh-koenig--old/addon/options/key-commands.js
diff --git a/ghost/admin/lib/gh-koenig/addon/options/text-expansions.js b/ghost/admin/lib/gh-koenig--old/addon/options/text-expansions.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/options/text-expansions.js
rename to ghost/admin/lib/gh-koenig--old/addon/options/text-expansions.js
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/card-hr.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/card-hr.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/card-hr.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/card-hr.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/card-html.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/card-html.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/card-html.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/card-html.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/card-image.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/card-image.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/card-image.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/card-image.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/card-markdown.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/card-markdown.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/card-markdown.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/card-markdown.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/gh-koenig.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/gh-koenig.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/gh-koenig.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/gh-koenig.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-card.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-card.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-card.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-card.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-menu-item.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-menu-item.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-menu-item.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-menu-item.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-plus-menu.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-plus-menu.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-plus-menu.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-plus-menu.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-slash-menu.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-slash-menu.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-slash-menu.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-slash-menu.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-title-input.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-title-input.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-title-input.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-title-input.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-blockitem.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-blockitem.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-blockitem.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-blockitem.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-button.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-button.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-button.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-button.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-newitem.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-newitem.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar-newitem.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar-newitem.hbs
diff --git a/ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar.hbs b/ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar.hbs
similarity index 100%
rename from ghost/admin/lib/gh-koenig/addon/templates/components/koenig-toolbar.hbs
rename to ghost/admin/lib/gh-koenig--old/addon/templates/components/koenig-toolbar.hbs
diff --git a/ghost/admin/lib/gh-koenig/app/.gitkeep b/ghost/admin/lib/gh-koenig--old/app/.gitkeep
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/.gitkeep
rename to ghost/admin/lib/gh-koenig--old/app/.gitkeep
diff --git a/ghost/admin/lib/gh-koenig/app/components/card-hr.js b/ghost/admin/lib/gh-koenig--old/app/components/card-hr.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/card-hr.js
rename to ghost/admin/lib/gh-koenig--old/app/components/card-hr.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/card-html.js b/ghost/admin/lib/gh-koenig--old/app/components/card-html.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/card-html.js
rename to ghost/admin/lib/gh-koenig--old/app/components/card-html.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/card-image.js b/ghost/admin/lib/gh-koenig--old/app/components/card-image.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/card-image.js
rename to ghost/admin/lib/gh-koenig--old/app/components/card-image.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/card-markdown.js b/ghost/admin/lib/gh-koenig--old/app/components/card-markdown.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/card-markdown.js
rename to ghost/admin/lib/gh-koenig--old/app/components/card-markdown.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/gh-koenig.js b/ghost/admin/lib/gh-koenig--old/app/components/gh-koenig.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/gh-koenig.js
rename to ghost/admin/lib/gh-koenig--old/app/components/gh-koenig.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-card.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-card.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-card.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-card.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-menu-item.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-menu-item.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-menu-item.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-menu-item.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-plus-menu.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-plus-menu.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-plus-menu.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-plus-menu.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-slash-menu.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-slash-menu.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-slash-menu.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-slash-menu.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-title-input.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-title-input.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-title-input.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-title-input.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-blockitem.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-blockitem.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-blockitem.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-blockitem.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-button.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-button.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-button.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-button.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-newitem.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-newitem.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-toolbar-newitem.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar-newitem.js
diff --git a/ghost/admin/lib/gh-koenig/app/components/koenig-toolbar.js b/ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/components/koenig-toolbar.js
rename to ghost/admin/lib/gh-koenig--old/app/components/koenig-toolbar.js
diff --git a/ghost/admin/lib/gh-koenig/app/renderer.js b/ghost/admin/lib/gh-koenig--old/app/renderer.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/app/renderer.js
rename to ghost/admin/lib/gh-koenig--old/app/renderer.js
diff --git a/ghost/admin/lib/gh-koenig/index.js b/ghost/admin/lib/gh-koenig--old/index.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/index.js
rename to ghost/admin/lib/gh-koenig--old/index.js
diff --git a/ghost/admin/lib/gh-koenig/package.json b/ghost/admin/lib/gh-koenig--old/package.json
similarity index 100%
rename from ghost/admin/lib/gh-koenig/package.json
rename to ghost/admin/lib/gh-koenig--old/package.json
diff --git a/ghost/admin/lib/gh-koenig/public/tools/bold.svg b/ghost/admin/lib/gh-koenig--old/public/tools/bold.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/bold.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/bold.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/close.svg b/ghost/admin/lib/gh-koenig--old/public/tools/close.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/close.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/close.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/file-code-1.svg b/ghost/admin/lib/gh-koenig--old/public/tools/file-code-1.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/file-code-1.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/file-code-1.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/file-code-edit.svg b/ghost/admin/lib/gh-koenig--old/public/tools/file-code-edit.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/file-code-edit.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/file-code-edit.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/file-picture-add.svg b/ghost/admin/lib/gh-koenig--old/public/tools/file-picture-add.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/file-picture-add.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/file-picture-add.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/font-size.svg b/ghost/admin/lib/gh-koenig--old/public/tools/font-size.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/font-size.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/font-size.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/html-five.svg b/ghost/admin/lib/gh-koenig--old/public/tools/html-five.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/html-five.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/html-five.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/italic.svg b/ghost/admin/lib/gh-koenig--old/public/tools/italic.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/italic.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/italic.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/link-broken.svg b/ghost/admin/lib/gh-koenig--old/public/tools/link-broken.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/link-broken.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/link-broken.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/link.svg b/ghost/admin/lib/gh-koenig--old/public/tools/link.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/link.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/link.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/list-bullets.svg b/ghost/admin/lib/gh-koenig--old/public/tools/list-bullets.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/list-bullets.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/list-bullets.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/list-number.svg b/ghost/admin/lib/gh-koenig--old/public/tools/list-number.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/list-number.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/list-number.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/paragraph.svg b/ghost/admin/lib/gh-koenig--old/public/tools/paragraph.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/paragraph.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/paragraph.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/pullquote.svg b/ghost/admin/lib/gh-koenig--old/public/tools/pullquote.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/pullquote.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/pullquote.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/quote.svg b/ghost/admin/lib/gh-koenig--old/public/tools/quote.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/quote.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/quote.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/strikethrough.svg b/ghost/admin/lib/gh-koenig--old/public/tools/strikethrough.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/strikethrough.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/strikethrough.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/subscript.svg b/ghost/admin/lib/gh-koenig--old/public/tools/subscript.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/subscript.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/subscript.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/superscript.svg b/ghost/admin/lib/gh-koenig--old/public/tools/superscript.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/superscript.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/superscript.svg
diff --git a/ghost/admin/lib/gh-koenig/public/tools/underline.svg b/ghost/admin/lib/gh-koenig--old/public/tools/underline.svg
similarity index 100%
rename from ghost/admin/lib/gh-koenig/public/tools/underline.svg
rename to ghost/admin/lib/gh-koenig--old/public/tools/underline.svg
diff --git a/ghost/admin/lib/gh-koenig/test-support/.eslintrc.js b/ghost/admin/lib/gh-koenig--old/test-support/.eslintrc.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/.eslintrc.js
rename to ghost/admin/lib/gh-koenig--old/test-support/.eslintrc.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/integration/components/gh-koenig-slashmenu-test.js b/ghost/admin/lib/gh-koenig--old/test-support/integration/components/gh-koenig-slashmenu-test.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/integration/components/gh-koenig-slashmenu-test.js
rename to ghost/admin/lib/gh-koenig--old/test-support/integration/components/gh-koenig-slashmenu-test.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/integration/components/gh-koenig-test.js b/ghost/admin/lib/gh-koenig--old/test-support/integration/components/gh-koenig-test.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/integration/components/gh-koenig-test.js
rename to ghost/admin/lib/gh-koenig--old/test-support/integration/components/gh-koenig-test.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-button-test.js b/ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-button-test.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-button-test.js
rename to ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-button-test.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-newitem-test.js b/ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-newitem-test.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-newitem-test.js
rename to ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-newitem-test.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-test.js b/ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-test.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/unit/components/koenig-toolbar-test.js
rename to ghost/admin/lib/gh-koenig--old/test-support/unit/components/koenig-toolbar-test.js
diff --git a/ghost/admin/lib/gh-koenig/test-support/utils.js b/ghost/admin/lib/gh-koenig--old/test-support/utils.js
similarity index 100%
rename from ghost/admin/lib/gh-koenig/test-support/utils.js
rename to ghost/admin/lib/gh-koenig--old/test-support/utils.js
diff --git a/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js b/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js
new file mode 100644
index 0000000000..556cc24a30
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/addon/components/koenig-editor.js
@@ -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;
+ }
+ }
+});
diff --git a/ghost/admin/lib/koenig-editor/addon/components/koenig-toolbar.js b/ghost/admin/lib/koenig-editor/addon/components/koenig-toolbar.js
new file mode 100644
index 0000000000..3aa29e805c
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/addon/components/koenig-toolbar.js
@@ -0,0 +1,184 @@
+import Component from '@ember/component';
+import layout from '../templates/components/koenig-toolbar';
+import {computed} from '@ember/object';
+import {htmlSafe} from '@ember/string';
+import {task, timeout} from 'ember-concurrency';
+
+// initially rendered offscreen with opacity 0 so that sizing is available
+// shown when passed in an uncollapsed selected range
+// display is delayed until the mouse button is lifted
+// positioned so that it's always fully within the editor container
+// animation occurs via CSS transitions
+// position is kept after hiding, it's made inoperable by CSS pointer-events
+
+const TOOLBAR_TOP_MARGIN = 15;
+
+export default Component.extend({
+ layout,
+
+ attributeBindings: ['style'],
+
+ // public attrs
+ classNames: ['koenig-toolbar'],
+ classNameBindings: ['showToolbar:koenig-toolbar--visible'],
+ selectedRange: null,
+
+ // internal properties
+ showToolbar: false,
+ top: null,
+ left: -1000,
+ right: null,
+
+ // private properties
+ _isMouseDown: false,
+ _onMousedownHandler: false,
+ _onMouseupHandler: false,
+ _hasSelectedRange: false,
+
+ /* computed properties -------------------------------------------------- */
+
+ style: computed('top', 'left', 'right', function () {
+ let position = this.getProperties('top', 'left', 'right');
+ let styles = Object.keys(position).map((style) => {
+ if (position[style] !== null) {
+ return `${style}: ${position[style]}px`;
+ }
+ });
+
+ return htmlSafe(styles.compact().join('; '));
+ }),
+
+ /* lifecycle hooks ------------------------------------------------------ */
+
+ init() {
+ this._super(...arguments);
+
+ // track mousedown/mouseup on the window so that we're sure to get the
+ // events even when they start outside of this component or end outside
+ // the window
+ this._onMousedownHandler = (event) => {
+ // we only care about the left mouse button
+ if (event.which === 1) {
+ this._isMouseDown = true;
+ }
+ };
+ this._onMouseupHandler = (event) => {
+ if (event.which === 1) {
+ this._isMouseDown = false;
+ this.get('_toggleVisibility').perform();
+ }
+ };
+ window.addEventListener('mousedown', this._onMousedownHandler);
+ window.addEventListener('mouseup', this._onMouseupHandler);
+ },
+
+ didReceiveAttrs() {
+ this._super(...arguments);
+ let range = this.get('editorRange');
+
+ if (range && !range.isCollapsed) {
+ this._hasSelectedRange = true;
+ } else {
+ this._hasSelectedRange = false;
+ }
+
+ this.get('_toggleVisibility').perform();
+ },
+
+ willDestroyElement() {
+ this._super(...arguments);
+ this._removeStyleElement();
+ window.removeEventListener('mousedown', this._onMousedownHandler);
+ window.removeEventListener('mouseup', this._onMouseupHandler);
+ },
+
+ _toggleVisibility: task(function* () {
+ // debounce for 100ms to account for "click to deselect" otherwise we
+ // run twice and the fade out animation jumps position
+ yield timeout(50);
+
+ // return early if the editorRange hasn't changed, this prevents
+ // re-rendering unnecessarily which can cause minor position jumps when
+ // styles are toggled because getBoundingClientRect on getSelection
+ // changes slightly depending on the style of selected text
+ if (this.get('editorRange') === this._lastRange) {
+ return;
+ }
+
+ // if we have a range, show the toolbnar once the mouse is lifted
+ if (this._hasSelectedRange && !this._isMouseDown) {
+ let containerRect = this.element.parentNode.getBoundingClientRect();
+ let range = window.getSelection().getRangeAt(0);
+ let rangeRect = range.getBoundingClientRect();
+ let {width, height} = this.element.getBoundingClientRect();
+ let newPosition = {};
+
+ // rangeRect is relative to the viewport so we need to subtract the
+ // container measurements to get a position relative to the container
+ newPosition = {
+ top: rangeRect.top - containerRect.top - height - TOOLBAR_TOP_MARGIN,
+ left: rangeRect.left - containerRect.left + rangeRect.width / 2 - width / 2,
+ right: null
+ };
+
+ let tickPosition = 50;
+ // don't overflow left boundary
+ if (newPosition.left < 0) {
+ newPosition.left = 0;
+
+ // calculate the tick percentage position
+ let absTickPosition = rangeRect.left - containerRect.left + rangeRect.width / 2;
+ tickPosition = absTickPosition / width * 100;
+ if (tickPosition < 5) {
+ tickPosition = 5;
+ }
+ }
+ // same for right boundary
+ if (newPosition.left + width > containerRect.width) {
+ newPosition.left = null;
+ newPosition.right = 0;
+
+ // calculate the tick percentage position
+ let absTickPosition = rangeRect.right - containerRect.right - rangeRect.width / 2;
+ tickPosition = 100 + absTickPosition / width * 100;
+ if (tickPosition > 95) {
+ tickPosition = 95;
+ }
+ }
+
+ // the tick is a pseudo-element so we the only way we can affect it's
+ // style is by adding a style element to the head
+ this._removeStyleElement(); // reset to base styles
+ if (tickPosition !== 50) {
+ this._addStyleElement(`left: ${tickPosition}%`);
+ }
+
+ // update the toolbar position and show it
+ this.setProperties(newPosition);
+
+ // show the toolbar
+ this.set('showToolbar', true);
+
+ // track displayed range so that we don't re-position unnecessarily
+ this._lastRange = this.get('editorRange');
+ } else {
+ // hide the toolbar
+ this.set('showToolbar', false);
+ this._lastRange = null;
+ }
+ }).restartable(),
+
+ _addStyleElement(styles) {
+ let styleElement = document.createElement('style');
+ styleElement.id = `${this.elementId}-style`;
+ styleElement.innerHTML = `#${this.elementId}:after { ${styles} }`;
+ document.head.appendChild(styleElement);
+ },
+
+ _removeStyleElement() {
+ let styleElement = document.querySelector(`#${this.elementId}-style`);
+ if (styleElement) {
+ styleElement.remove();
+ }
+ }
+});
diff --git a/ghost/admin/lib/koenig-editor/addon/options/text-expansions.js b/ghost/admin/lib/koenig-editor/addon/options/text-expansions.js
new file mode 100644
index 0000000000..4849bdc292
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/addon/options/text-expansions.js
@@ -0,0 +1,171 @@
+import {
+ replaceWithHeaderSection,
+ replaceWithListSection
+} from 'mobiledoc-kit/editor/text-input-handlers';
+
+// Text expansions watch text entry events and will look for matches, replacing
+// the matches with additional markup, atoms, or cards
+// https://github.com/bustlelabs/mobiledoc-kit#responding-to-text-input
+
+// TODO: this was copied from our old Koenig editor, it could do with some
+// comments, cleanup, and refactoring
+
+export default function (editor) {
+ // We don't want to run all our content rules on every text entry event,
+ // instead we check to see if this text entry event could match a content
+ // rule, and only then run the rules. Right now we only want to match
+ // content ending with *, _, ), ~, and `. This could increase as we support
+ // more markdown.
+
+ editor.onTextInput({
+ name: 'inline_markdown',
+ match: /[*_)~`]$/,
+ run(postEditor, matches) {
+ let text = postEditor.range.head.section.textUntil(postEditor.range.head);
+
+ switch (matches[0]) {
+ case '*':
+ matchStrongStar(postEditor, text);
+ matchEmStar(postEditor, text);
+ break;
+ case '_':
+ matchStrongUnderscore(postEditor, text);
+ matchEmUnderscore(postEditor, text);
+ break;
+ case ')':
+ matchLink(postEditor, text);
+ break;
+ case '~':
+ matchStrikethrough(postEditor, text);
+ break;
+ case '`':
+ matchCode(postEditor, text);
+ break;
+ }
+ }
+ });
+
+ /* block level markdown ------------------------------------------------- */
+
+ // mobiledoc-kit has `* ` already built-in so we only need to add `- `
+ editor.onTextInput({
+ name: 'md_ul',
+ match: /^- $/,
+ run(editor) {
+ replaceWithListSection(editor, 'ul');
+ }
+ });
+
+ editor.onTextInput({
+ name: 'md_blockquote',
+ match: /^> $/,
+ run(editor) {
+ replaceWithHeaderSection(editor, 'blockquote');
+ }
+ });
+
+ /* inline markdown ------------------------------------------------------ */
+
+ function matchStrongStar(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/\*\*(.+?)\*\*$/);
+ if (matches) {
+ range = range.extend(-(matches[0].length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let bold = postEditor.builder.createMarkup('strong');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [bold]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []);
+ });
+ }
+ }
+
+ function matchStrongUnderscore(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/__(.+?)__$/);
+ if (matches) {
+ range = range.extend(-(matches[0].length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let bold = postEditor.builder.createMarkup('strong');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [bold]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []);
+ });
+ }
+ }
+
+ function matchEmStar(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/(^|[^*])\*([^*].*?)\*$/);
+ if (matches) {
+ let match = matches[0][0] === '*' ? matches[0] : matches[0].substr(1);
+ range = range.extend(-(match.length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let em = postEditor.builder.createMarkup('em');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []);
+ });
+ }
+ }
+
+ function matchEmUnderscore(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/(^|[^_])_([^_].+?)_$/);
+ if (matches) {
+ let match = matches[0][0] === '_' ? matches[0] : matches[0].substr(1);
+ range = range.extend(-(match.length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let em = postEditor.builder.createMarkup('em');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[2], [em]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []);
+ });
+ }
+ }
+
+ function matchLink(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/(^|[^!])\[(.*?)\]\((.*?)\)$/);
+ if (matches) {
+ let url = matches[3];
+ let text = matches[2];
+ let match = matches[0][0] === '[' ? matches[0] : matches[0].substr(1);
+ range = range.extend(-match.length);
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let a = postEditor.builder.createMarkup('a', {href: url});
+ let nextPosition = postEditor.insertTextWithMarkup(position, text, [a]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
+ });
+ }
+ }
+
+ function matchStrikethrough(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/~(.+?)~$/);
+ if (matches) {
+ range = range.extend(-(matches[0].length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let s = postEditor.builder.createMarkup('s');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [s]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
+ });
+ }
+ }
+
+ function matchCode(editor, text) {
+ let {range} = editor;
+ let matches = text.match(/`(.+?)`/);
+ if (matches) {
+ range = range.extend(-(matches[0].length));
+ editor.run((postEditor) => {
+ let position = postEditor.deleteRange(range);
+ let code = postEditor.builder.createMarkup('code');
+ let nextPosition = postEditor.insertTextWithMarkup(position, matches[1], [code]);
+ postEditor.insertTextWithMarkup(nextPosition, ' ', []); // insert the un-marked-up space
+ });
+ }
+ }
+}
diff --git a/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-editor.hbs b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-editor.hbs
new file mode 100644
index 0000000000..5aaa05d415
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-editor.hbs
@@ -0,0 +1,67 @@
+
+
+
+
+{{!-- pop-up markup toolbar is shown when there's a selection --}}
+{{#koenig-toolbar editorRange=selectedRange}}
+ {{!-- markup buttons --}}
+
+
+
+
+
+
+
+ {{!-- block buttons --}}
+
+
+
+{{/koenig-toolbar}}
diff --git a/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-toolbar.hbs b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-toolbar.hbs
new file mode 100644
index 0000000000..fb5c4b157d
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/addon/templates/components/koenig-toolbar.hbs
@@ -0,0 +1 @@
+{{yield}}
\ No newline at end of file
diff --git a/ghost/admin/lib/koenig-editor/app/components/koenig-editor.js b/ghost/admin/lib/koenig-editor/app/components/koenig-editor.js
new file mode 100644
index 0000000000..7ca98ddbc4
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/app/components/koenig-editor.js
@@ -0,0 +1 @@
+export {default} from 'koenig-editor/components/koenig-editor';
diff --git a/ghost/admin/lib/koenig-editor/app/components/koenig-toolbar.js b/ghost/admin/lib/koenig-editor/app/components/koenig-toolbar.js
new file mode 100644
index 0000000000..560ad9e4b3
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/app/components/koenig-toolbar.js
@@ -0,0 +1 @@
+export {default} from 'koenig-editor/components/koenig-toolbar';
diff --git a/ghost/admin/lib/koenig-editor/docs/specs/popup-toolbar.md b/ghost/admin/lib/koenig-editor/docs/specs/popup-toolbar.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ghost/admin/lib/koenig-editor/index.js b/ghost/admin/lib/koenig-editor/index.js
new file mode 100644
index 0000000000..14305a239d
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/index.js
@@ -0,0 +1,10 @@
+/* eslint-env node */
+'use strict';
+
+module.exports = {
+ name: 'koenig-editor',
+
+ isDevelopingAddon() {
+ return true;
+ }
+};
diff --git a/ghost/admin/lib/koenig-editor/package.json b/ghost/admin/lib/koenig-editor/package.json
new file mode 100644
index 0000000000..153febaeb0
--- /dev/null
+++ b/ghost/admin/lib/koenig-editor/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "koenig-editor",
+ "version": "0.0.1",
+ "description": "A mobiledoc-kit based editor for Ghost.",
+ "author": "Ghost Foundation",
+ "homepage": "http://ghost.org",
+ "bugs": "https://github.com/TryGhost/Ghost/issues",
+ "license": "MIT",
+ "private": true,
+ "keywords": [
+ "ember-addon"
+ ],
+ "dependencies": {
+ "ember-cli-babel": "^6.11.0",
+ "ember-cli-htmlbars": "^2.0.3"
+ }
+}
diff --git a/ghost/admin/package.json b/ghost/admin/package.json
index c861592751..aa0c0432e8 100644
--- a/ghost/admin/package.json
+++ b/ghost/admin/package.json
@@ -123,7 +123,7 @@
"ember-addon": {
"paths": [
"lib/asset-delivery",
- "lib/gh-koenig"
+ "lib/koenig-editor"
]
}
}
diff --git a/ghost/admin/tests/helpers/editor-helpers.js b/ghost/admin/tests/helpers/editor-helpers.js
deleted file mode 100644
index 75349e281d..0000000000
--- a/ghost/admin/tests/helpers/editor-helpers.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import $ from 'jquery';
-import Ember from 'ember';
-import wait from 'ember-test-helpers/wait';
-import {MOBILEDOC_VERSION} from 'mobiledoc-kit/renderers/mobiledoc';
-import {TESTING_EXPANDO_PROPERTY} from 'gh-koenig/components/gh-koenig';
-import {find, findWithAssert, waitUntil} from 'ember-native-dom-helpers';
-import {run} from '@ember/runloop';
-
-export const EMPTY_DOC = {
- version: MOBILEDOC_VERSION,
- markups: [],
- atoms: [],
- cards: [],
- sections: []
-};
-
-// traverse up the node tree looking for an editor instance
-export function findEditor(element) {
- if (!element) {
- // TODO: get the selector from the editor component
- element = findWithAssert('.gh-koenig-container');
- }
-
- if (typeof element === 'string') {
- element = findWithAssert(element);
- }
-
- do {
- if (element[TESTING_EXPANDO_PROPERTY]) {
- return element[TESTING_EXPANDO_PROPERTY];
- }
- element = element.parentNode;
- } while (!!element); // eslint-disable-line
-
- throw new Error('Unable to find gh-koenig editor from element');
-}
-
-export function focusEditor(element) {
- let editor = findEditor(element);
- run(() => editor.element.focus());
- return (window.wait || wait);
-}
-
-// polls the title until it's started.
-export function titleRendered() {
- return Ember.Test.promise(function (resolve) { // eslint-disable-line
- function checkTitle() {
- let title = $('#koenig-title-input div');
- if (title[0]) {
- return resolve();
- } else {
- window.requestAnimationFrame(checkTitle);
- }
- }
- checkTitle();
- });
-}
-
-// replaces the title text content with HTML and returns once the HTML has been placed.
-// takes into account converting to plaintext.
-export function replaceTitleHTML(HTML) {
- let el = findWithAssert('#koenig-title-input div');
- run(() => el.innerHTML = HTML);
- return (window.wait || wait)();
-}
-
-// simulates text inputs into the editor, unfortunately the Ember helper functions
-// don't work on content editable so we have to manipuate the text input event manager
-// in mobiledoc-kit directly. This is a private API.
-export function inputText(editor, text) {
- run(() => {
- editor._eventManager._textInputHandler.handle(text);
- });
-}
-
-// inputs text and waits for the editor to modify the dom with the desired result or timesout.
-export function testEditorInput(input, output, expect) {
- let editor = findEditor();
- editor.element.focus(); // for some reason the editor doesn't work until it's focused when run in ghost-admin.
- return Ember.Test.promise(function (resolve, reject) { // eslint-disable-line
- let lastRender = '';
- let isRejected = false;
- let rejectTimeout = window.setTimeout(() => {
- expect(lastRender).to.equal(output); // we know this is false but include it for the output.
- reject(lastRender);
- isRejected = true;
- }, 500);
- editor.didRender(() => {
- lastRender = editor.element.innerHTML;
- if (editor.element.innerHTML === output && !isRejected) {
- window.clearTimeout(rejectTimeout);
- expect(lastRender).to.equal(output); // we know this is true but include it for the output.
- return resolve(lastRender);
- }
- });
- inputText(editor, input);
- });
-}
-
-export function testEditorInputTimeout(input) {
- let editor = findEditor();
- editor.element.focus();
- return Ember.Test.promise(function (resolve, reject) { // eslint-disable-line
- window.setTimeout(() => {
- resolve(editor.element.innerHTML);
- }, 300);
-
- inputText(editor, input);
- });
-}
-
-export function waitForRender(selector) {
- return waitUntil(() => find(selector));
-}
diff --git a/ghost/admin/tests/integration/components/gh-koenig-editor-test.js b/ghost/admin/tests/integration/components/gh-koenig-editor-test.js
new file mode 100644
index 0000000000..9b2c55a82d
--- /dev/null
+++ b/ghost/admin/tests/integration/components/gh-koenig-editor-test.js
@@ -0,0 +1,24 @@
+import hbs from 'htmlbars-inline-precompile';
+import {describe, it} from 'mocha';
+import {expect} from 'chai';
+import {setupComponentTest} from 'ember-mocha';
+
+describe('Integration: Component: gh-koenig-editor', function () {
+ setupComponentTest('gh-koenig-editor', {
+ integration: true
+ });
+
+ it('renders', function () {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+ // Template block usage:
+ // this.render(hbs`
+ // {{#gh-koenig-editor}}
+ // template content
+ // {{/gh-koenig-editor}}
+ // `);
+
+ this.render(hbs`{{gh-koenig-editor}}`);
+ expect(this.$()).to.have.length(1);
+ });
+});
diff --git a/ghost/admin/tests/integration/components/koenig-editor-test.js b/ghost/admin/tests/integration/components/koenig-editor-test.js
new file mode 100644
index 0000000000..5cd46293e8
--- /dev/null
+++ b/ghost/admin/tests/integration/components/koenig-editor-test.js
@@ -0,0 +1,24 @@
+import hbs from 'htmlbars-inline-precompile';
+import {describe, it} from 'mocha';
+import {expect} from 'chai';
+import {setupComponentTest} from 'ember-mocha';
+
+describe('Integration: Component: koenig-editor', function () {
+ setupComponentTest('koenig-editor', {
+ integration: true
+ });
+
+ it('renders', function () {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+ // Template block usage:
+ // this.render(hbs`
+ // {{#koenig-editor}}
+ // template content
+ // {{/koenig-editor}}
+ // `);
+
+ this.render(hbs`{{koenig-editor}}`);
+ expect(this.$()).to.have.length(1);
+ });
+});
diff --git a/ghost/admin/tests/integration/components/koenig-toolbar-test.js b/ghost/admin/tests/integration/components/koenig-toolbar-test.js
new file mode 100644
index 0000000000..97e74e4cb5
--- /dev/null
+++ b/ghost/admin/tests/integration/components/koenig-toolbar-test.js
@@ -0,0 +1,24 @@
+import hbs from 'htmlbars-inline-precompile';
+import {describe, it} from 'mocha';
+import {expect} from 'chai';
+import {setupComponentTest} from 'ember-mocha';
+
+describe('Integration: Component: koenig-toolbar', function () {
+ setupComponentTest('koenig-toolbar', {
+ integration: true
+ });
+
+ it('renders', function () {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+ // Template block usage:
+ // this.render(hbs`
+ // {{#koenig-toolbar}}
+ // template content
+ // {{/koenig-toolbar}}
+ // `);
+
+ this.render(hbs`{{koenig-toolbar}}`);
+ expect(this.$()).to.have.length(1);
+ });
+});