Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions src/rich-text/plugins/link-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class LinkEditor extends PluginInterfaceView<
<label for="link-editor-href-input-${randomId}" class="s-label mb4">${_t(
"link_editor.href_label"
)}</label>
<input id="link-editor-href-input-${randomId}" class="s-input js-link-editor-href" type="text" name="href" aria-describedby="link-editor-href-error-${randomId}" />
<input id="link-editor-href-input-${randomId}" class="s-input js-link-editor-href" type="text" name="href" aria-describedby="link-editor-href-error-${randomId}" placeholder="https://"/>
<p id="link-editor-href-error-${randomId}" class="s-input-message mt4 d-none js-link-editor-href-error"></p>
</div>

Expand Down Expand Up @@ -100,7 +100,8 @@ export class LinkEditor extends PluginInterfaceView<
this.viewContainer.addEventListener("reset", (e) => {
e.preventDefault();
e.stopPropagation();
const tr = this.tryHideInterfaceTr(view.state);
let tr = this.tryHideInterfaceTr(view.state);
tr = LINK_EDITOR_KEY.updateVisibility(false, tr);
if (tr) {
view.dispatch(tr);
}
Expand Down Expand Up @@ -164,6 +165,8 @@ export class LinkEditor extends PluginInterfaceView<
text: null,
}) || view.state.tr;

tr = LINK_EDITOR_KEY.updateVisibility(false, tr);

// set the text first, inheriting all marks
tr = tr.replaceSelectionWith(node, true);

Expand Down Expand Up @@ -195,9 +198,9 @@ export class LinkEditor extends PluginInterfaceView<

update(view: EditorView): void {
super.update(view);
const state = LINK_EDITOR_KEY.getState(view.state);

if (this.isShown) {
const state = LINK_EDITOR_KEY.getState(view.state);
if (state?.url) {
this.hrefInput.value = state.url;
this.validate(state.url);
Expand All @@ -215,8 +218,9 @@ export class LinkEditor extends PluginInterfaceView<
this.hrefInput.focus();
} else {
this.resetEditor();
const tr = this.tryHideInterfaceTr(view.state);
let tr = this.tryHideInterfaceTr(view.state);
if (tr) {
tr = LINK_EDITOR_KEY.updateVisibility(false, tr);
view.dispatch(tr);
}
}
Expand Down Expand Up @@ -274,6 +278,11 @@ class LinkEditorPluginKey extends ManagedInterfaceKey<LinkEditorPluginState> {
meta.forceHideTooltip = true;
return this.setMeta(state.tr, meta);
}
updateVisibility(visibility: boolean, trans: Transaction): Transaction {
const meta = trans.getMeta(LINK_EDITOR_KEY) as LinkEditorPluginState;
meta.visible = visibility;
return this.setMeta(trans, meta);
}
}

/** The plugin key the image uploader plugin is tied to */
Expand Down Expand Up @@ -628,19 +637,32 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) =>
shouldShow: false,
};
},
apply(tr, value, _, newState): LinkEditorPluginState {
apply(tr, value, state, newState): LinkEditorPluginState {
// check if force hide was set and add to value for getDecorations to use
const meta = this.getMeta(tr) || value;
if ("forceHideTooltip" in meta) {
value.forceHideTooltip = meta.forceHideTooltip;
}

// update the linkTooltip and get the decorations
const decorations = value.linkTooltip.getDecorations(
let decorations = value.linkTooltip.getDecorations(
value,
newState
);

//get decoration for current selection
const sel = state.selection;
let selectionDecoration = null;

if (meta.visible && sel && sel.from !== sel.to) {
selectionDecoration = Decoration.inline(sel.from, sel.to, {
class: "bg-black-225",
});
decorations = decorations.add(newState.doc, [
selectionDecoration,
]);
}

return {
...meta,
forceHideTooltip:
Expand Down Expand Up @@ -713,11 +735,13 @@ export function showLinkEditor(
url?: string,
text?: string
): void {
const tr = LINK_EDITOR_KEY.showInterfaceTr(view.state, {
let tr = LINK_EDITOR_KEY.showInterfaceTr(view.state, {
url,
text,
});

tr = LINK_EDITOR_KEY.updateVisibility(true, tr);

if (tr) {
view.dispatch(tr);
}
Expand All @@ -728,11 +752,13 @@ export function showLinkEditor(
* @param view The current editor view
*/
export function hideLinkEditor(view: EditorView): void {
const tr = LINK_EDITOR_KEY.hideInterfaceTr(view.state, {
let tr = LINK_EDITOR_KEY.hideInterfaceTr(view.state, {
url: null,
text: null,
});

tr = LINK_EDITOR_KEY.updateVisibility(false, tr);

if (tr) {
view.dispatch(tr);
}
Expand Down
29 changes: 29 additions & 0 deletions test/rich-text/plugins/link-editor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,35 @@ describe("link-editor", () => {
expect(inputContainer.classList).not.toContain("has-error");
});

it("should highlight selected text in grey when link editor is open", () => {
view = richTextView(
"highlight this text",
() => pluginContainer,
() => menuContainer
);

// Select the text we want to highlight
view.editorView.updateState(
applySelection(view.editorView.state, 0, 19) // Select "highlight this text"
);

showLinkEditor(view.editorView);
editor.update(view.editorView);

const decorations = getDecorations(view.editorView.state);
const decoration = decorations.find(0, 19)[0];

expect(decoration).toBeDefined(); // The highlight should exist

// Verify the selection is styled with a decoration containing the correct class
const editorContent = view.editorView.dom;
const highlightedText =
editorContent.querySelector(".bg-black-225");

expect(highlightedText).toBeTruthy();
expect(highlightedText.textContent).toBe("highlight this text");
});

it("should prefill fields when a link is edited via the tooltip", async () => {
view = richTextView(
"[link text](https://www.example.com)",
Expand Down
Loading