verbb / vizy

A flexible visual editor for Craft CMS
Other
43 stars 8 forks source link

Trying to add a character count to a Vizy Field #294

Closed mattbloomfield closed 2 months ago

mattbloomfield commented 3 months ago

Question

Hey Josh,

Trying to add a character counter to a vizy field and really struggling to figure out how to do it. Admittedly this is my first time attempting to interact with the tiptap API so I may be misguided.

What works so far is that I have created a Vizy plugin, it gets added to the config and picked up such that a console.log from the plugin runs when my Vizy field is on the page.

From there though, I can't figure out a reliable way to hook into the tiptap events. If I do a do/while loop in JS I can wait for the Vizy text to be on the page, then get the number of characters using vanilla js. However, I cannot seem to add an event listener for changes to the text. Could you give me a few tips?

I see that I can access tiptap's core via something like const {Editor} = Craft.Vizy.Config.tiptap.core; but even with that, I can't tell if that's connected into the Vizy Editor on the page. It also doesn't seem to quite match the API found here: https://tiptap.dev/docs/editor/api/editor. Am I looking in the right place?

Additional context

No response

engram-design commented 2 months ago

So if we're going by the Creating a custom Node from scratch user guide, that's a good start. From this you can add your own Node or Mark to Tiptap.

Extensions are also supported, which something like a character counter is - not a Node or a Mark, but "something" attached to Tiptap for all sorts of things.

In your own JS file, you can access Tiptap core functions, but those are really for extending or creating with their things. For example:

// modules/vizymodule/src/assets/js/emoji.js

document.addEventListener('onVizyConfigReady', (e) => {
    const { Node } = Craft.Vizy.Config.tiptap.core;

    const Emoji = Node.create({
        name: 'emoji',

Otherwise, you'd have to install Tiptap yourself in your own dependencies to access Node, which is a waste of time with Tiptap already being loaded. In fact, you can see that we're using registerExtensions which is what you'll likely do.

What this doesn't cover is access to Vizy's instance of the Tiptap editor. That's all just providing access to the JS classes, and nothing about the instance of the Vizy field or Tiptap editor.

Getting the const {Editor} = Craft.Vizy.Config.tiptap.core; isn't going to be useful here.

What I would highly recommend is to use Tiptap's own CharacterCount extension, which will make things easier!

import CharacterCount from '@tiptap/extension-character-count';

document.addEventListener('onVizyConfigReady', (e) => {
    Craft.Vizy.Config.registerExtensions((extensions) => {
        return [
            CharacterCount.configure({
                limit: 240,
            }),
        ];
    });
});

You'll need to run npm install @tiptap/extension-character-count according to the TipTap docs in your own JS.

Then you might want to go about rendering the character counts in the field. Now that is an interesting idea, and I'm not quite sure how to go about that. If this were a case of you writing the Vue template yourself, you could just output it like their docs state:

<template>
  <div>
    <editor-content :editor="editor" />

    <div class="character-count" v-if="editor">
      {{ editor.storage.characterCount.characters() }}/{{ limit }} characters
      <br>
      {{ editor.storage.characterCount.words() }} words
    </div>
  </div>
</template>

But that's not going to work, as Vizy is the one to output the <editor-content> element. We would need a method of hooking into template rendering, but I'm not sure how we can make that flexible on where you want to put the template content in the Vizy field.

engram-design commented 2 months ago

Okay, so I've added the ability to insert Vue template alongside the editor, which I think will help in your instance. You can use the below code in your JS.

import CharacterCount from '@tiptap/extension-character-count';

document.addEventListener('onVizyConfigReady', (e) => {
    Craft.Vizy.Config.registerExtensions((extensions) => {
        return [
            CharacterCount.configure({
                limit: 240,
            }),
        ];
    });

    Craft.Vizy.Config.registerTemplates(() => {
        return {
            position: 'afterEditor',
            template: `<div class="character-count" v-if="editor">
                {{ editor.storage.characterCount.characters() }}/240 characters
                <br>
                {{ editor.storage.characterCount.words() }} words
            </div>`,
        };
    });
});

Which will now all the template code into the editor.

Added for the next release. To get this early, run composer require verbb/vizy:"dev-craft-4 as 2.1.17".

mattbloomfield commented 2 months ago

Dude unreal. I’ll check it out and let you know how it works.

Matt Bloomfield

On Sat, Apr 6, 2024 at 04:40 Josh Crawford @.***> wrote:

Okay, so I've added the ability to insert Vue template alongside the editor, which I think will help in your instance. You can use the below code in your JS.

import CharacterCount from @.***/extension-character-count'; document.addEventListener('onVizyConfigReady', (e) => { Craft.Vizy.Config.registerExtensions((extensions) => { return [ CharacterCount.configure({ limit: 240, }), ]; });

Craft.Vizy.Config.registerTemplates(() => {
    return {
        position: 'afterEditor',
        template: `<div class="character-count" v-if="editor">                {{ editor.storage.characterCount.characters() }}/280 characters                <br>                {{ editor.storage.characterCount.words() }} words            </div>`,
    };
});});

Which will now all the template code into the editor.

Added for the next release. To get this early, run composer require verbb/vizy:"dev-craft-4 as 2.1.17".

— Reply to this email directly, view it on GitHub https://github.com/verbb/vizy/issues/294#issuecomment-2041056382, or unsubscribe https://github.com/notifications/unsubscribe-auth/AI6XNVQRYFRYZMDJMF5O6DTY37NJRAVCNFSM6AAAAABFWAAPRWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGA2TMMZYGI . You are receiving this because you authored the thread.Message ID: @.***>

engram-design commented 2 months ago

Added in 2.1.18