mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Made Koenig the default editor, removed Koenig labs flag
This commit is contained in:
parent
7ee7c3a9f8
commit
3d0091c9f5
8 changed files with 40 additions and 270 deletions
|
@ -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'));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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 <a href="https://ghost.org/downloads/" target="_blank" rel="noopener">Ghost Desktop</a> 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 <a href="https://ghost.org/downloads/" target="_blank" rel="noopener">Ghost Desktop</a> 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 <a href="https://ghost.org/downloads/" target="_blank" rel="noopener">Ghost Desktop</a> 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 <a href="https://ghost.org/downloads/" target="_blank" rel="noopener">Ghost Desktop</a>.'),
|
||||
{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 <a href="https://ghost.org/downloads/" target="_blank" rel="noopener">Ghost Desktop</a>.'),
|
||||
{type: 'info', key: 'koenig.browserSupport'}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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'}),
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
focus-out=(action "onTitleFocusOut")
|
||||
keyDown=(action "onTitleKeydown")
|
||||
didCreateTextarea=(action "onTitleCreated")
|
||||
data-test-editor-title-input=true
|
||||
}}
|
||||
|
||||
{{koenig-editor
|
||||
|
|
|
@ -66,134 +66,33 @@
|
|||
</section>
|
||||
</header>
|
||||
|
||||
{{#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")
|
||||
}}
|
||||
|
||||
<div class="absolute flex items-center br3 bg-white {{if editor.headerClass "right-4 bottom-4" "right-6 bottom-6"}}">
|
||||
<div class="midgrey-l2 {{if editor.headerClass "f-supersmall pl2 pr2" "f8 pl4 pr3"}} fw3">
|
||||
{{pluralize wordCount.wordCount "word"}}
|
||||
</div>
|
||||
<a href="https://help.ghost.org/article/29-ghost-editor-overview" class="flex {{if editor.headerClass "pa2" "pa3"}}" target="_blank">{{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}}</a>
|
||||
<div class="absolute flex items-center br3 bg-white {{if editor.headerClass "right-4 bottom-4" "right-6 bottom-6"}}">
|
||||
<div class="midgrey-l2 {{if editor.headerClass "f-supersmall pl2 pr2" "f8 pl4 pr3"}} fw3">
|
||||
{{pluralize wordCount.wordCount "word"}}
|
||||
</div>
|
||||
|
||||
{{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|
|
||||
}}
|
||||
<div class="gh-markdown-editor-pane">
|
||||
{{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}}
|
||||
</div>
|
||||
|
||||
{{#if markdown.isSplitScreen}}
|
||||
<div class="gh-markdown-editor-preview">
|
||||
<h1 class="gh-markdown-editor-preview-title">{{post.titleScratch}}</h1>
|
||||
<div class="gh-markdown-editor-preview-content"></div>
|
||||
</div>
|
||||
{{/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 --}}
|
||||
<footer class="gh-editor-footer"></footer>
|
||||
|
||||
{{!-- files are dragged over editor pane --}}
|
||||
{{#if editor.isDraggedOver}}
|
||||
<div class="drop-target gh-editor-drop-target">
|
||||
<div class="drop-target-message">
|
||||
<h3>Drop image(s) here to upload</h3>
|
||||
</div>
|
||||
</div>
|
||||
{{/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|
|
||||
}}
|
||||
<div class="gh-editor-image-upload {{if upload.errors "-error"}}">
|
||||
<div class="gh-editor-image-upload-content">
|
||||
{{#if upload.errors}}
|
||||
<h3>Upload failed</h3>
|
||||
|
||||
{{#each upload.errors as |error|}}
|
||||
<div class="failed">{{error.fileName}} - {{error.message}}</div>
|
||||
{{/each}}
|
||||
|
||||
<button class="gh-btn gh-btn-grey gh-btn-icon" {{action upload.cancel}}>
|
||||
<span>{{svg-jar "close"}} Close</span>
|
||||
</button>
|
||||
{{else}}
|
||||
|
||||
<h3>Uploading {{pluralize upload.files.length "image"}}...</h3>
|
||||
{{upload.progressBar}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/gh-uploader}}
|
||||
{{/if}}
|
||||
|
||||
{{/if}} {{!-- end Koenig conditional --}}
|
||||
<a href="https://help.ghost.org/article/29-ghost-editor-overview" class="flex {{if editor.headerClass "pa2" "pa3"}}" target="_blank">{{svg-jar "help" class="w4 h4 stroke-midgrey-l2"}}</a>
|
||||
</div>
|
||||
|
||||
{{/gh-editor}}
|
||||
|
||||
|
|
|
@ -82,15 +82,6 @@
|
|||
</div>
|
||||
|
||||
<div class="gh-setting-header">Beta features</div>
|
||||
<div class="gh-setting">
|
||||
<div class="gh-setting-content">
|
||||
<div class="gh-setting-title flex items-center">Koenig editor <span class="gh-badge gh-badge-green ml1">New</span></div>
|
||||
<div class="gh-setting-desc">Participate in our new rich text editor beta! We’d love <a href="https://forum.ghost.org/t/koenig-beta-release/1284" target="_blank" rel="noopener">your feedback</a></div>
|
||||
</div>
|
||||
<div class="gh-setting-action">
|
||||
<div class="for-checkbox">{{gh-feature-flag "koenigEditor"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gh-setting">
|
||||
<div class="gh-setting-content">
|
||||
<div class="gh-setting-title">Public API</div>
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue