Added TK support to subtitle
closes https://linear.app/tryghost/issue/MOM-176 - display TK next to subtitle field as per the title field - include subtitle TK in the pre-publish TK check
This commit is contained in:
parent
1d4fedf4f2
commit
d94a4c581f
@ -58,23 +58,34 @@
|
||||
/>
|
||||
|
||||
{{#if (feature 'editorSubtitle')}}
|
||||
<GhTextarea
|
||||
@class={{concat "gh-editor-subtitle " (if @excerptErrorMessage "red")}}
|
||||
@placeholder="Add a subtitle..."
|
||||
@shouldFocus={{false}}
|
||||
@tabindex="1"
|
||||
@autoExpand=".gh-koenig-editor"
|
||||
@value={{readonly this.excerpt}}
|
||||
@input={{this.onExcerptInput}}
|
||||
@keyDown={{this.onExcerptKeydown}}
|
||||
@didCreateTextarea={{this.registerSubtitleElement}}
|
||||
data-test-textarea="subtitle"
|
||||
/>
|
||||
{{#if @excerptErrorMessage}}
|
||||
<div class="gh-editor-subtitle-error" data-test-error="subtitle">
|
||||
{{@excerptErrorMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="relative">
|
||||
<GhTextarea
|
||||
@class={{concat "gh-editor-subtitle " (if @excerptErrorMessage "red")}}
|
||||
@placeholder="Add a subtitle..."
|
||||
@shouldFocus={{false}}
|
||||
@tabindex="1"
|
||||
@autoExpand=".gh-koenig-editor"
|
||||
@value={{readonly this.excerpt}}
|
||||
@input={{this.onExcerptInput}}
|
||||
@keyDown={{this.onExcerptKeydown}}
|
||||
@didCreateTextarea={{this.registerSubtitleElement}}
|
||||
data-test-textarea="subtitle"
|
||||
/>
|
||||
{{#if @excerptErrorMessage}}
|
||||
<div class="gh-editor-subtitle-error" data-test-error="subtitle">
|
||||
{{@excerptErrorMessage}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if @excerptHasTk}}
|
||||
<div
|
||||
class="tk-indicator tk-indicator-subtitle"
|
||||
data-testid="tk-indicator-subtitle"
|
||||
{{on "click" this.focusSubtitle}}
|
||||
>
|
||||
TK
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<hr class="gh-editor-title-divider {{if @excerptErrorMessage "gh-editor-title-divider-error" ""}}">
|
||||
{{/if}}
|
||||
</div>
|
||||
|
@ -102,6 +102,45 @@ const messageMap = {
|
||||
}
|
||||
};
|
||||
|
||||
function textHasTk(text) {
|
||||
let matchArr = TK_REGEX.exec(text);
|
||||
|
||||
if (matchArr === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isValidMatch(match) {
|
||||
// negative lookbehind isn't supported before Safari 16.4
|
||||
// so we capture the preceding char and test it here
|
||||
if (match[1] && match[1].trim() && WORD_CHAR_REGEX.test(match[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we also check any following char in code to avoid an overly
|
||||
// complex regex when looking for word-chars following the optional
|
||||
// trailing symbol char
|
||||
if (match[4] && match[4].trim() && WORD_CHAR_REGEX.test(match[4])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// our regex will match invalid TKs because we can't use negative lookbehind
|
||||
// so we need to loop through the matches discarding any that are invalid
|
||||
// and moving on to any subsequent matches
|
||||
while (matchArr !== null && !isValidMatch(matchArr)) {
|
||||
text = text.slice(matchArr.index + matchArr[0].length - 1);
|
||||
matchArr = TK_REGEX.exec(text);
|
||||
}
|
||||
|
||||
if (matchArr === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@classic
|
||||
export default class LexicalEditorController extends Controller {
|
||||
@controller application;
|
||||
@ -225,48 +264,23 @@ export default class LexicalEditorController extends Controller {
|
||||
|
||||
@computed('post.titleScratch')
|
||||
get titleHasTk() {
|
||||
let text = this.post.titleScratch;
|
||||
let matchArr = TK_REGEX.exec(text);
|
||||
|
||||
if (matchArr === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isValidMatch(match) {
|
||||
// negative lookbehind isn't supported before Safari 16.4
|
||||
// so we capture the preceding char and test it here
|
||||
if (match[1] && match[1].trim() && WORD_CHAR_REGEX.test(match[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we also check any following char in code to avoid an overly
|
||||
// complex regex when looking for word-chars following the optional
|
||||
// trailing symbol char
|
||||
if (match[4] && match[4].trim() && WORD_CHAR_REGEX.test(match[4])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// our regex will match invalid TKs because we can't use negative lookbehind
|
||||
// so we need to loop through the matches discarding any that are invalid
|
||||
// and moving on to any subsequent matches
|
||||
while (matchArr !== null && !isValidMatch(matchArr)) {
|
||||
text = text.slice(matchArr.index + matchArr[0].length - 1);
|
||||
matchArr = TK_REGEX.exec(text);
|
||||
}
|
||||
|
||||
if (matchArr === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return textHasTk(this.post.titleScratch);
|
||||
}
|
||||
|
||||
@computed('titleHasTk', 'postTkCount', 'featureImageTkCount')
|
||||
@computed('post.customExcerpt')
|
||||
get excerptHasTk() {
|
||||
if (!this.feature.editorSubtitle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return textHasTk(this.post.customExcerpt || '');
|
||||
}
|
||||
|
||||
@computed('titleHasTk', 'excerptHasTk', 'postTkCount', 'featureImageTkCount')
|
||||
get tkCount() {
|
||||
return (this.titleHasTk ? 1 : 0) + this.postTkCount + this.featureImageTkCount;
|
||||
const titleTk = this.titleHasTk ? 1 : 0;
|
||||
const excerptTk = (this.feature.editorSubtitle && this.excerptHasTk) ? 1 : 0;
|
||||
return titleTk + excerptTk + this.postTkCount + this.featureImageTkCount;
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -839,6 +839,10 @@ body[data-user-is-dragging] .gh-editor-feature-image-dropzone {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.gh-editor .tk-indicator-subtitle {
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.gh-editor-feature-image-container .tk-indicator {
|
||||
top: 0;
|
||||
padding: 0 .4rem;
|
||||
|
@ -61,14 +61,15 @@
|
||||
--}}
|
||||
<GhKoenigEditorLexical
|
||||
@title={{readonly this.post.titleScratch}}
|
||||
@excerpt={{readonly this.post.customExcerpt}}
|
||||
@setExcerpt={{this.updateExcerpt}}
|
||||
@excerptErrorMessage={{this.excerptErrorMessage}}
|
||||
@titleAutofocus={{this.shouldFocusTitle}}
|
||||
@titlePlaceholder={{concat (capitalize this.post.displayName) " title"}}
|
||||
@titleAutofocus={{this.shouldFocusTitle}}
|
||||
@titleHasTk={{this.titleHasTk}}
|
||||
@onTitleChange={{this.updateTitleScratch}}
|
||||
@onTitleBlur={{perform this.saveTitleTask}}
|
||||
@excerpt={{readonly this.post.customExcerpt}}
|
||||
@excerptHasTk={{this.excerptHasTk}}
|
||||
@setExcerpt={{this.updateExcerpt}}
|
||||
@excerptErrorMessage={{this.excerptErrorMessage}}
|
||||
@body={{readonly this.post.lexicalScratch}}
|
||||
@bodyPlaceholder={{concat "Begin writing your " this.post.displayName "..."}}
|
||||
@onBodyChange={{this.updateScratch}}
|
||||
|
@ -635,5 +635,39 @@ describe('Acceptance: Editor', function () {
|
||||
'TK reminder modal'
|
||||
).to.exist;
|
||||
});
|
||||
|
||||
it('handles TKs in subtitle', async function () {
|
||||
enableLabsFlag(this.server, 'editorSubtitle');
|
||||
|
||||
const post = this.server.create('post', {authors: [author]});
|
||||
|
||||
await visit(`/editor/post/${post.id}`);
|
||||
|
||||
expect(
|
||||
find('[data-test-textarea="subtitle"]').value,
|
||||
'initial subtitle'
|
||||
).to.equal('');
|
||||
|
||||
await fillIn('[data-test-textarea="subtitle"]', 'Test TK subtitle');
|
||||
|
||||
expect(
|
||||
find('[data-test-textarea="subtitle"]').value,
|
||||
'subtitle after typing'
|
||||
).to.equal('Test TK subtitle');
|
||||
|
||||
// check for TK indicator
|
||||
expect(
|
||||
find('[data-testid="tk-indicator-subtitle"]'),
|
||||
'TK indicator text'
|
||||
).to.exist;
|
||||
|
||||
// click publish to see if confirmation comes up
|
||||
await click('[data-test-button="publish-flow"]');
|
||||
|
||||
expect(
|
||||
find('[data-test-modal="tk-reminder"]'),
|
||||
'TK reminder modal'
|
||||
).to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user