Skip to content

Commit

Permalink
add defer-initialize attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
KonnorRogers committed Oct 17, 2024
1 parent 726b746 commit 19b56ad
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 21 deletions.
23 changes: 23 additions & 0 deletions docs/src/_documentation/references/04-modifying-the-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ There are 3 general ways to wait for RhinoEditor to connect to the DOM and then
- `rhino-initialize` - `<rhino-editor>` after the TipTap instance is created
- `customElements.whenDefined("rhino-editor").then(() => { document.querySelectorAll("rhino-editor") })` This is a general purpose callback you can use. The TipTap instance more or may not created when this is called.

<%= render Alert.new(type: :info) do %>
If you are having trouble catching the `rhino-initialize` or the `rhino-before-initialize` events read the section on [Delaying Initialization](#delaying-initialization)
<% end %>

You can use any of these events to modify the editor options. Heres an example for each one to add
additional heading levels.

Expand Down Expand Up @@ -42,3 +46,22 @@ customElements.whenDefined("rhino-editor").then(() => {
})
```

## Delaying Initialization

Sometimes it can be quite challenging to catch either the `rhino-initialize` or `rhino-before-initialize` events due to load order of your JavaScript.

If you add the `defer-initialization` attribute to your editor, the editor will not start until you remove that attribute.

Like so:

```html
<rhino-editor defer-initialize></rhino-editor>

<script type="module">
// Setup your event listeners to modify the editor *before* removing the `defer-initialize` attribute.
document.addEventListener("rhino-before-initialize", () => {})
// The editor will initialize and start the TipTap instance.
document.querySelectorAll("rhino-editor").forEach((el) => el.removeAttribute("defer-initialize"))
</script>
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@esm-bundle/chai": "4.3.4-fix.0",
"@open-wc/testing": "^3.2.2",
"@playwright/test": "^1.48.0",
"@types/mocha": "^10.0.9",
"@types/rails__activestorage": "^7.1.1",
"@typescript-eslint/parser": "^6.21.0",
"@web/dev-server": "^0.3.7",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions src/exports/elements/tip-tap-editor-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class TipTapEditorBase extends BaseElement {
class: { reflect: true },
accept: { reflect: true },
serializer: { reflect: true },
deferInitialize: { type: Boolean, attribute: "defer-initialize", reflect: true },

// Properties
editor: { state: true },
Expand Down Expand Up @@ -126,6 +127,12 @@ export class TipTapEditorBase extends BaseElement {
*/
extensions: EditorOptions["extensions"] = [];

/**
* When the `defer-initialize` attribute is present, it will wait to start the TipTap editor until the attribute has been removed.
*/
deferInitialize = false


/**
* @internal
*/
Expand Down Expand Up @@ -315,6 +322,10 @@ export class TipTapEditorBase extends BaseElement {
protected willUpdate(
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,
): void {
if (changedProperties.has("deferInitialize") && !this.deferInitialize) {
this.startEditor()
}

if (changedProperties.has("class")) {
this.classList.add("rhino-editor");
}
Expand Down Expand Up @@ -387,6 +398,12 @@ export class TipTapEditorBase extends BaseElement {

this.classList.add("rhino-editor");

if (!this.deferInitialize) {
this.startEditor()
}
}

async startEditor () {
await this.updateComplete;

setTimeout(() => {
Expand Down
47 changes: 27 additions & 20 deletions src/exports/elements/tip-tap-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,18 @@ export class TipTapEditor extends TipTapEditorBase {
},
}) as typeof this.starterKitOptions;

document.addEventListener("click", this.__handleLinkDialogClick);
}

/**
* @override
*/
async startEditor () {
await super.startEditor()

if (this.editor) {
this.editor.on("focus", this.closeLinkDialog);
}

document.addEventListener("click", this.__handleLinkDialogClick);
}

disconnectedCallback() {
Expand Down Expand Up @@ -330,7 +337,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderBoldButton(prefix = "") {
const boldEnabled = Boolean(this.editor?.commands.toggleBold);
const boldEnabled = this.starterKitOptions.bold !== false || Boolean(this.editor?.commands.toggleBold);

if (!boldEnabled) return html``;

Expand Down Expand Up @@ -382,7 +389,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderItalicButton(prefix = "") {
const italicEnabled = Boolean(this.editor?.commands.toggleItalic);
const italicEnabled = this.starterKitOptions.italic !== false || Boolean(this.editor?.commands.toggleItalic);

if (!italicEnabled) return html``;

Expand Down Expand Up @@ -438,7 +445,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderStrikeButton(prefix = "") {
const strikeEnabled = Boolean(this.editor?.commands.toggleStrike);
const strikeEnabled = this.starterKitOptions.rhinoStrike !== false || Boolean(this.editor?.commands.toggleStrike);

if (!strikeEnabled) return html``;

Expand Down Expand Up @@ -493,7 +500,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderLinkButton(prefix = "") {
const linkEnabled = Boolean(this.editor?.commands.setLink);
const linkEnabled = this.starterKitOptions.rhinoLink !== false || Boolean(this.editor?.commands.setLink);

if (!linkEnabled) return html``;

Expand Down Expand Up @@ -551,7 +558,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderHeadingButton(prefix = "") {
const headingEnabled = Boolean(this.editor?.commands.toggleHeading);
const headingEnabled = this.starterKitOptions.heading !== false || Boolean(this.editor?.commands.toggleHeading);

if (!headingEnabled) return html``;

Expand Down Expand Up @@ -608,7 +615,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderBlockquoteButton(prefix = "") {
const blockQuoteEnabled = Boolean(this.editor?.commands.toggleBlockquote);
const blockQuoteEnabled = this.starterKitOptions.blockquote !== false || Boolean(this.editor?.commands.toggleBlockquote);

if (!blockQuoteEnabled) return html``;

Expand Down Expand Up @@ -665,7 +672,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderCodeBlockButton(prefix = "") {
const codeBlockEnabled = Boolean(this.editor?.commands.toggleCodeBlock);
const codeBlockEnabled = this.starterKitOptions.codeBlock !== false || Boolean(this.editor?.commands.toggleCodeBlock);

if (!codeBlockEnabled) return html``;

Expand Down Expand Up @@ -721,7 +728,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderBulletListButton(prefix = "") {
const bulletListEnabled = Boolean(this.editor?.commands.toggleBulletList);
const bulletListEnabled = this.starterKitOptions.bulletList !== false || Boolean(this.editor?.commands.toggleBulletList);

if (!bulletListEnabled) return html``;

Expand Down Expand Up @@ -784,7 +791,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderOrderedListButton(prefix = "") {
const orderedListEnabled = Boolean(this.editor?.commands.toggleOrderedList);
const orderedListEnabled = this.starterKitOptions.orderedList !== false || Boolean(this.editor?.commands.toggleOrderedList);

if (!orderedListEnabled) return html``;

Expand Down Expand Up @@ -849,7 +856,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderAttachmentButton(prefix = "") {
const attachmentEnabled = Boolean(this.editor?.commands.setAttachment);
const attachmentEnabled = this.starterKitOptions.rhinoAttachment !== false || Boolean(this.editor?.commands.setAttachment);

if (!attachmentEnabled) return html``;

Expand Down Expand Up @@ -910,7 +917,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderUndoButton(prefix = "") {
const undoEnabled = Boolean(this.editor?.commands.undo);
const undoEnabled = this.starterKitOptions.history !== false || Boolean(this.editor?.commands.undo);

if (!undoEnabled) return html``;

Expand Down Expand Up @@ -964,10 +971,9 @@ export class TipTapEditor extends TipTapEditorBase {
renderDecreaseIndentation(prefix = "") {
// Decrease / increase indentation are special cases in that they rely on built-in editor
// commands and not commands added by extensions.
const decreaseIndentationNotEnabled =
this.starterKitOptions.decreaseIndentation == false;
const decreaseIndentationEnabled = this.starterKitOptions.decreaseIndentation !== false // || Boolean(this.editor?.commands.liftListItem);

if (decreaseIndentationNotEnabled) return html``;
if (!decreaseIndentationEnabled) return html``;

const isDisabled =
this.editor == null || !this.editor.can().liftListItem("listItem");
Expand Down Expand Up @@ -1019,10 +1025,11 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderIncreaseIndentation(prefix = "") {
const increaseIndentationNotEnabled =
this.starterKitOptions.increaseIndentation == false;
// Decrease / increase indentation are special cases in that they rely on built-in editor
// commands and not commands added by extensions.
const increaseIndentationEnabled = this.starterKitOptions.increaseIndentation !== false // || Boolean(this.editor?.commands.sinkListItem);

if (increaseIndentationNotEnabled) return html``;
if (!increaseIndentationEnabled) return html``;

const isDisabled =
this.editor == null || !this.editor.can().sinkListItem("listItem");
Expand Down Expand Up @@ -1074,7 +1081,7 @@ export class TipTapEditor extends TipTapEditorBase {
}

renderRedoButton(prefix = "") {
const redoEnabled = Boolean(this.editor?.commands.redo);
const redoEnabled = this.starterKitOptions.history !== false || Boolean(this.editor?.commands.redo);

if (!redoEnabled) return html``;

Expand Down
30 changes: 29 additions & 1 deletion tests/unit/events.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-check
import "rhino-editor"
import { assert, aTimeout, waitUntil } from "@open-wc/testing"
import { assert, aTimeout, fixture, waitUntil } from "@open-wc/testing"
import { html } from "lit"
import { readFile, sendKeys } from '@web/test-runner-commands';
import sinon from "sinon"
Expand Down Expand Up @@ -256,3 +256,31 @@ test("rhino-paste", async () => {
document.removeEventListener("rhino-paste", handleEvent)
})

test("Should not fire initialize and before-initialize events until after defer-initialize is removed", async () => {
const beforeInitializeSpy = sinon.spy()
const initializeSpy = sinon.spy()

function handleBeforeInitialize () { beforeInitializeSpy() }
function handleInitialize () { initializeSpy() }

document.addEventListener("rhino-before-initialize", handleBeforeInitialize)
document.addEventListener("rhino-initialize", handleInitialize)

const rhinoEditor = await fixture(html`<rhino-editor defer-initialize></rhino-editor>`)

await rhinoEditor.updateComplete
await aTimeout(10)

assert.isTrue(beforeInitializeSpy.notCalled)
assert.isTrue(initializeSpy.notCalled)

rhinoEditor.removeAttribute("defer-initialize")
await rhinoEditor.updateComplete
await aTimeout(10)

assert.isTrue(beforeInitializeSpy.calledOnce)
assert.isTrue(initializeSpy.calledOnce)

document.removeEventListener("rhino-before-initialize", handleBeforeInitialize)
document.removeEventListener("rhino-initialize", handleInitialize)
})

0 comments on commit 19b56ad

Please sign in to comment.