diff --git a/ghost/admin/app/controllers/editor.js b/ghost/admin/app/controllers/editor.js index 1bca60e262..d1bd459feb 100644 --- a/ghost/admin/app/controllers/editor.js +++ b/ghost/admin/app/controllers/editor.js @@ -3,7 +3,6 @@ import PostModel from 'ghost-admin/models/post'; import boundOneWay from 'ghost-admin/utils/bound-one-way'; import config from 'ghost-admin/config/environment'; import isNumber from 'ghost-admin/utils/isNumber'; -import {BLANK_MARKDOWN} from 'ghost-admin/models/post'; import {alias, mapBy, reads} from '@ember/object/computed'; import {computed} from '@ember/object'; import {inject as controller} from '@ember/controller'; @@ -100,7 +99,6 @@ export default Controller.extend({ showDeletePostModal: false, showLeaveEditorModal: false, showReAuthenticateModal: false, - useKoenig: false, // koenig related properties wordcount: null, @@ -131,14 +129,6 @@ export default Controller.extend({ _tagNames: mapBy('post.tags', 'name'), - markdown: computed('post.mobiledoc', function () { - if (this.get('post').isCompatibleWithMarkdownEditor()) { - let mobiledoc = this.get('post.mobiledoc'); - let markdown = mobiledoc.cards[0][1].markdown; - return markdown; - } - }), - hasDirtyAttributes: computed(...watchedProps, { get() { return this._hasDirtyAttributes(); @@ -170,15 +160,6 @@ export default Controller.extend({ // force save at 60 seconds this.get('_timedSave').perform(); }, - - // TODO: Only used by the markdown editor, ensure it's removed when - // we switch to Koenig - updateMarkdown(markdown) { - let mobiledoc = copy(BLANK_MARKDOWN, true); - mobiledoc.cards[0][1].markdown = markdown; - this.send('updateScratch', mobiledoc); - }, - updateTitleScratch(title) { this.set('post.titleScratch', title); }, @@ -526,16 +507,6 @@ export default Controller.extend({ // called by the new/edit routes to change the post model setPost(post) { - // switch between markdown/koenig depending on feature flag and post - // compatibility - let koenigEnabled = this.get('feature.koenigEditor'); - let postIsMarkdownCompatible = post.isCompatibleWithMarkdownEditor(); - if (koenigEnabled || !postIsMarkdownCompatible) { - this.set('useKoenig', true); - } else { - this.set('useKoenig', false); - } - // don't do anything else if we're setting the same post if (post === this.get('post')) { // set autofocus as change signal to the persistent editor on new->edit @@ -548,12 +519,6 @@ export default Controller.extend({ this.set('post', post); - // display an info message if Koenig is disabled by we had to use it - // for post compatibility - if (!koenigEnabled && this.useKoenig) { - // this.set('infoMessage', 'This post can only be edited with the Koenig editor.'); - } - // autofocus the editor if we have a new post this.set('shouldFocusEditor', post.get('isNew')); diff --git a/ghost/admin/app/models/post.js b/ghost/admin/app/models/post.js index d24ac4a2a9..50f3b9b94a 100644 --- a/ghost/admin/app/models/post.js +++ b/ghost/admin/app/models/post.js @@ -4,11 +4,9 @@ import ValidationEngine from 'ghost-admin/mixins/validation-engine'; import attr from 'ember-data/attr'; import boundOneWay from 'ghost-admin/utils/bound-one-way'; import moment from 'moment'; -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, observer} from '@ember/object'; -import {copy} from '@ember/object/internals'; import {equal, filterBy} from '@ember/object/computed'; import {isBlank} from '@ember/utils'; import {inject as service} from '@ember/service'; @@ -16,21 +14,6 @@ import {inject as service} from '@ember/service'; // ember-cli-shims doesn't export these so we must get them manually const {Comparable} = Ember; -// for our markdown-only editor we need to build a blank mobiledoc -const MOBILEDOC_VERSION = '0.3.1'; -export const BLANK_MARKDOWN = { - version: MOBILEDOC_VERSION, - markups: [], - atoms: [], - cards: [ - ['card-markdown', { - cardName: 'card-markdown', - markdown: '' - }] - ], - sections: [[10, 0]] -}; - function statusCompare(postA, postB) { let status1 = postA.get('status'); let status2 = postB.get('status'); @@ -135,30 +118,6 @@ export default Model.extend(Comparable, ValidationEngine, { return this.get('authors.firstObject'); }), - init() { - // HACK: we can't use the defaultValue property on the mobiledoc attr - // because it won't have access to `this` for the feature check so we do - // it manually here instead - if (!this.get('mobiledoc')) { - let defaultValue; - - if (this.get('feature.koenigEditor')) { - defaultValue = copy(BLANK_MOBILEDOC, true); - } else { - defaultValue = copy(BLANK_MARKDOWN, true); - } - - // using this.set() adds the property to the changedAttributes list - // which means the editor always sees new posts as dirty. By setting - // the internal model data property first it's not seen as having - // changed so the changedAttributes key is removed - this._internalModel._data.mobiledoc = defaultValue; - this.set('mobiledoc', defaultValue); - } - - this._super(...arguments); - }, - scratch: null, titleScratch: null, @@ -360,25 +319,5 @@ export default Model.extend(Comparable, ValidationEngine, { let publishedAtBlogTZ = this.get('publishedAtBlogTZ'); let publishedAtUTC = publishedAtBlogTZ ? publishedAtBlogTZ.utc() : null; this.set('publishedAtUTC', publishedAtUTC); - }, - - // the markdown editor expects a very specific mobiledoc format, if it - // doesn't match then we'll need to handle it by forcing Koenig - isCompatibleWithMarkdownEditor() { - let mobiledoc = this.get('mobiledoc'); - - if (mobiledoc - && mobiledoc.markups.length === 0 - && mobiledoc.cards.length === 1 - && mobiledoc.cards[0][0] === 'card-markdown' - && mobiledoc.sections.length === 1 - && mobiledoc.sections[0].length === 2 - && mobiledoc.sections[0][0] === 10 - && mobiledoc.sections[0][1] === 0 - ) { - return true; - } - - return false; } }); diff --git a/ghost/admin/app/routes/editor.js b/ghost/admin/app/routes/editor.js index f5aec1e426..20312d7f4d 100644 --- a/ghost/admin/app/routes/editor.js +++ b/ghost/admin/app/routes/editor.js @@ -21,39 +21,26 @@ export default AuthenticatedRoute.extend(ShortcutsRoute, { activate() { this._super(...arguments); - if (this.feature.koenigEditor) { - this.ui.set('isFullScreen', true); - } + this.ui.set('isFullScreen', true); }, setupController() { this._super(...arguments); - // display a warning if we detect an unsupported browser - if (this.feature.koenigEditor) { - // IE is definitely not supported and will not work at all in Ghost 2.0 - if (this.userAgent.browser.isIE) { - this.notifications.showAlert( - htmlSafe('Internet Explorer is not supported in Koenig and will no longer work in Ghost 2.0. Please switch to Ghost Desktop or a recent version of Chrome/Firefox/Safari.'), - {type: 'info', key: 'koenig.browserSupport'} - ); - } + // edge has known issues + if (this.userAgent.browser.isEdge) { + this.notifications.showAlert( + htmlSafe('Microsoft Edge is not currently supported in Koenig. Please switch to Ghost Desktop or a recent version of Chrome/Firefox/Safari.'), + {type: 'info', key: 'koenig.browserSupport'} + ); + } - // edge has known issues - if (this.userAgent.browser.isEdge) { - this.notifications.showAlert( - htmlSafe('Microsoft Edge is not currently supported in Koenig. Please switch to Ghost Desktop or a recent version of Chrome/Firefox/Safari.'), - {type: 'info', key: 'koenig.browserSupport'} - ); - } - - // mobile browsers are not currently supported - if (this.userAgent.device.isMobile || this.userAgent.device.isTablet) { - this.notifications.showAlert( - htmlSafe('Mobile editing is not currently supported in Koenig. Please use a desktop browser or Ghost Desktop.'), - {type: 'info', key: 'koenig.browserSupport'} - ); - } + // mobile browsers are not currently supported + if (this.userAgent.device.isMobile || this.userAgent.device.isTablet) { + this.notifications.showAlert( + htmlSafe('Mobile editing is not currently supported in Koenig. Please use a desktop browser or Ghost Desktop.'), + {type: 'info', key: 'koenig.browserSupport'} + ); } }, diff --git a/ghost/admin/app/services/feature.js b/ghost/admin/app/services/feature.js index f964f7c2be..fc3f8223a9 100644 --- a/ghost/admin/app/services/feature.js +++ b/ghost/admin/app/services/feature.js @@ -50,7 +50,6 @@ export default Service.extend({ notifications: service(), lazyLoader: service(), - koenigEditor: feature('koenigEditor'), publicAPI: feature('publicAPI'), subscribers: feature('subscribers'), nightShift: feature('nightShift', {user: true, onChange: '_setAdminTheme'}), diff --git a/ghost/admin/app/templates/components/gh-koenig-editor.hbs b/ghost/admin/app/templates/components/gh-koenig-editor.hbs index d54b037538..a0906af0d7 100644 --- a/ghost/admin/app/templates/components/gh-koenig-editor.hbs +++ b/ghost/admin/app/templates/components/gh-koenig-editor.hbs @@ -14,6 +14,7 @@ focus-out=(action "onTitleFocusOut") keyDown=(action "onTitleKeydown") didCreateTextarea=(action "onTitleCreated") + data-test-editor-title-input=true }} {{koenig-editor diff --git a/ghost/admin/app/templates/editor.hbs b/ghost/admin/app/templates/editor.hbs index ecd8f7a496..22a39d23b4 100644 --- a/ghost/admin/app/templates/editor.hbs +++ b/ghost/admin/app/templates/editor.hbs @@ -66,134 +66,33 @@ - {{#if useKoenig}} - {{!-- - 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") - headerOffset=editor.headerHeight - scrollContainerSelector=".gh-koenig-editor" - scrollOffsetTopSelector=".gh-editor-header-small" - scrollOffsetBottomSelector=".gh-mobile-nav-bar" - onEditorCreated=(action "setKoenigEditor") - onWordCountChange=(action "updateWordCount") - }} + {{!-- + 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") + headerOffset=editor.headerHeight + scrollContainerSelector=".gh-koenig-editor" + scrollOffsetTopSelector=".gh-editor-header-small" + scrollOffsetBottomSelector=".gh-mobile-nav-bar" + onEditorCreated=(action "setKoenigEditor") + onWordCountChange=(action "updateWordCount") + }} -
-
- {{pluralize wordCount.wordCount "word"}} -
- {{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}} +
+
+ {{pluralize wordCount.wordCount "word"}}
- - {{else}} - - {{!-- - NOTE: title is part of the markdown editor container so that it has - access to the markdown editor's "focus" action - --}} - {{#gh-markdown-editor - tabindex="2" - placeholder="Begin writing your story..." - autofocus=shouldFocusEditor - uploadedImageUrls=editor.uploadedImageUrls - markdown=(readonly markdown) - isFullScreen=editor.isFullScreen - onChange=(action "updateMarkdown") - onFullScreenToggle=(action editor.toggleFullScreen) - onPreviewToggle=(action editor.togglePreview) - onSplitScreenToggle=(action editor.toggleSplitScreen) - onImageFilesSelected=(action editor.uploadImages) - imageMimeTypes=editor.imageMimeTypes - as |markdown| - }} -
- {{gh-textarea - class="gh-editor-title" - placeholder="Post Title" - tabindex="1" - autoExpand=".gh-markdown-editor-pane" - value=(readonly post.titleScratch) - input=(action "updateTitleScratch" value="target.value") - focus-out=(action (perform saveTitle)) - keyEvents=(hash - Tab=(action markdown.focus 'bottom') - Enter=(action markdown.focus 'top') - ) - data-test-editor-title-input=true - }} - {{markdown.editor}} -
- - {{#if markdown.isSplitScreen}} -
-

{{post.titleScratch}}

-
-
- {{/if}} - - {{gh-tour-item "using-the-editor" - target=".gh-editor-footer" - throbberAttachment="top left" - throbberOffset="0 20%" - popoverTriangleClass="bottom" - }} - {{/gh-markdown-editor}} - - {{!-- TODO: put tool/status bar in here so that scroll area can be fixed --}} -
- - {{!-- files are dragged over editor pane --}} - {{#if editor.isDraggedOver}} -
-
-

Drop image(s) here to upload

-
-
- {{/if}} - - {{!-- files have been dropped ready to be uploaded --}} - {{#if editor.droppedFiles}} - {{#gh-uploader - files=editor.droppedFiles - accept=editor.imageMimeTypes - extensions=editor.imageExtensions - onComplete=(action editor.uploadComplete) - onCancel=(action editor.uploadCancelled) - as |upload| - }} -
-
- {{#if upload.errors}} -

Upload failed

- - {{#each upload.errors as |error|}} -
{{error.fileName}} - {{error.message}}
- {{/each}} - - - {{else}} - -

Uploading {{pluralize upload.files.length "image"}}...

- {{upload.progressBar}} - {{/if}} -
-
- {{/gh-uploader}} - {{/if}} - - {{/if}} {{!-- end Koenig conditional --}} + {{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}} +
{{/gh-editor}} diff --git a/ghost/admin/app/templates/settings/labs.hbs b/ghost/admin/app/templates/settings/labs.hbs index b9a83f4ef4..acc6e11c92 100644 --- a/ghost/admin/app/templates/settings/labs.hbs +++ b/ghost/admin/app/templates/settings/labs.hbs @@ -82,15 +82,6 @@
Beta features
-
-
-
Koenig editor New
-
Participate in our new rich text editor beta! We’d love your feedback
-
-
-
{{gh-feature-flag "koenigEditor"}}
-
-
Public API
diff --git a/ghost/admin/tests/acceptance/editor-test.js b/ghost/admin/tests/acceptance/editor-test.js index 0b1ba2ce33..1630ff9e4f 100644 --- a/ghost/admin/tests/acceptance/editor-test.js +++ b/ghost/admin/tests/acceptance/editor-test.js @@ -817,16 +817,5 @@ describe('Acceptance: Editor', function () { 'facebook title not present after closing subview' ).to.equal(0); }); - - it('has unsplash icon when server doesn\'t return unsplash settings key', async function () { - server.createList('post', 1, {authors: [author]}); - - await visit('/editor/1'); - - expect( - find('.editor-toolbar .fa-camera'), - 'unsplash toolbar button' - ).to.exist; - }); }); });