npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dippen

v2.0.308

Published

A rich text editor based on Quill with some improved features.

Downloads

25

Readme

Dippen

Dippen is our modified version of the Quill editor specifically designed for the Decidim participation platform. The goal of this project is to provide a maintenance release of the updated Quill v2 editor that works within Decidim without having to maintain custom workarounds or other Quill hacks within the Decidim v0.27 maintenance version.

The editor works exactly as Quill and maintains Quill naming for all its APIs. The customized editor only adds specific extra functionality to the Quill editor. The editor differs from the original Quill v1 editor slightly and requires a maintenance version of Decidim to work properly (see the link below).

The desired functionality is to maintain as similar editor experience as in legacy Decidim v0.27 with the updated Quill v2 editor and some extra features. The custom functionality added to Quill is migrated to this repository instead of maintaining that functionality in the Decidim repository.

Changes implemented on top of the default Quill v2 implementation:

  • Soft breaks / line breaks (https://github.com/slab/quill/pull/4565)
    • Customizes also the Keyboard and Clipboard modules with soft break support.
  • Customized Clipboard module from the Quill editor with support for passing the pasted content to the Uploader module for uploading the pasted base64 encoded images (if the pasted content is HTML).
  • Customized Uploader module from the Quill editor with extra features:
    • Converting the pasted base64 encoded images to uploaded images.
    • Easier separation of the image pasting to allow more control over the image uploads to the server.
  • A new exported function createServerUploader for creating the image upload function based on the old image upload module.
  • Image resize module (https://github.com/mudoo/quill-resize-module, original version: https://github.com/kensnyder/quill-image-resize-module)
  • Image ALT module allowing to set ALT text to images by double clicking the image.
  • Customized Link format that allows formatting the class and target attributes for the <a> elements properly.
  • A dynamic toolbar module for displaying toolbar items dynamically and conditionally based on the current state of the editor. This provides extra dropdown controls on the toolbar that allow changing link attributes (target and class), originally based on DynamicQuillTools.
  • Bugfix for not wrapping <a> elements within <u> in case the <a> element has a style attribute with text-decoration: underline defined on it.
  • Bugfix for formatting the video <iframe> elements correctly through quill.getSemanticHTML().
  • Bugfix for converting the non-breaking spaces with quill.getSemanticHTML() as normal spaces (otherwise all spaces are represented as &nbsp;).

The Decidim maintenance version can be found from:

https://github.com/mainio/decidim/tree/release/0.27-stable-ruby3.4

Note that this editor should be only used within legacy version (v0.27) of Decidim. Newer versions of the platform have migrated over to TipTap (see https://github.com/decidim/decidim/pull/10196).

Building and testing

To build and test the editor, run the following commands:

$ npm run build
$ npm run dev

After that, browse to: http://localhost:8080/

Usage

To use this editor within the Decidim maintenance version (linked above), there is nothing you need to do.

In case you want to use this outside of that Decidim version, you need to override app/packs/src/decidim/editor.js with the following code:

import Quill, { dynamicToolbarItems, createServerUploader } from "dippen";

const quillFormats = [
  "bold",
  "italic",
  "link",
  "underline",
  "header",
  "list",
  "break",
  "soft-break",
  "code",
  "blockquote",
  "indent"
];

export default function createQuillEditor(container) {
  const toolbar = container.dataset.toolbar;
  const disabled = container.dataset.disabled === "true";

  const allowedEmptyContentSelector = "iframe";
  let quillToolbar = [
    ["bold", "italic", "underline", "soft-break"],
    [{ list: "ordered" }, { list: "bullet" }],
    ["link", "clean"],
    ["code", "blockquote"],
    [{ indent: "-1" }, { indent: "+1" }]
  ];

  let addImage = false;
  let addVideo = false;
  let addDynamicToolbar = false;

  /**
   * - basic = only basic controls without titles
   * - content = basic + headings
   * - full = basic + headings + image + video
   */
  if (toolbar === "content") {
    quillToolbar = [[{ header: [2, 3, 4, 5, 6, false] }], ...quillToolbar];
  } else if (toolbar === "full") {
    addImage = true;
    addVideo = true;
    addDynamicToolbar = true;
    quillToolbar = [
      [{ header: [2, 3, 4, 5, 6, false] }],
      ...quillToolbar,
      ["video"],
      ["image"]
    ];
  }

  let modules = {
    toolbar: {
      container: quillToolbar
    }
  };

  if (addVideo) {
    quillFormats.push("video");
  }

  if (addImage) {
    quillFormats.push("image");

    const uploadUrl = container.dataset.uploadImagesPath;
    const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
    const imageUploader = createServerUploader(uploadUrl, {
      headers: { "X-CSRF-Token": token }
    });

    modules.imageResize = {
      modules: ["Resize", "DisplaySize", "Keyboard"]
    };
    modules.imageAlt = true;
    modules.uploader = {
      async uploadHandler(file) {
        const response = await imageUploader(file);
        return response.url;
      }
    }

    const help = document.createElement("p");
    help.classList.add("help-text");
    help.style.marginTop = "-1.5rem";
    help.innerText = container.dataset.dragAndDropHelpText;
    container.after(help);
  }

  if (addDynamicToolbar) {
    modules.dynamicToolbar = {
      items: dynamicToolbarItems({
        target: {
          blot: "link",
          options: {
            "Link": "",
            "New tab": "_blank"
          }
        },
        style: {
          blot: "link",
          attribute: "class",
          options: {
            "Default": "",
            "Small button": "button primary small",
            "Small button (hollow)": "button primary hollow small",
            "Standard button": "button primary",
            "Standard button (hollow)": "button primary hollow",
            "Large button": "button primary large",
            "Large button (hollow)": "button primary hollow large"
          }
        }
      })
    };
  }

  const quill = new Quill(container, {
    readOnly: disabled,
    modules: modules,
    formats: quillFormats,
    theme: "snow"
  });

  quill.on("text-change", () => {
    const text = quill.getText();

    // Triggers CustomEvent with the cursor position
    // It is required in input_mentions.js
    let event = new CustomEvent("quill-position", {
      detail: quill.getSelection()
    });
    container.dispatchEvent(event);

    if (
      (text === "\n" || text === "\n\n") &&
      quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0
    ) {
      $input.val("");
    } else {
      const emptyParagraph = "<p><br></p>";
      const cleanHTML = quill.root.innerHTML.replace(
        new RegExp(`^${emptyParagraph}|${emptyParagraph}$`, "g"),
        ""
      );
      $input.val(cleanHTML);
    }
  });

  return quill;
}

Versioning

The version of this package matches the version of the Quill editor with the patch version multiplied by 100 and the version of this custom editor added to the patch version.

For example, version 1 of this editor that targets Quill v2.0.3 has the version number 2.0.301.

It is recommended to use the exact Quill version this custom version has been targeted for. The overrides are done in a way that should maintain compatibility with possible newer Quill versions but this is not guaranteed.

License

BSD 3-clause

Licenses for the dependencies (some of which are partly or fully contained within this repository):