Giter VIP home page Giter VIP logo

quill-delta-parser's Introduction

Quill Delta to HTML Parser

A PHP library to parse Quill WYSIWYG editor deltas into HTML - flexible and extendable for custom elements. Every element is parsed by the same mechanism, making it easy to extend and understand. It also sanitizes the output value, making it more secure, especially when using user-generated text.

Tests Maintainability Test Coverage Latest Stable Version Total Downloads License

What is Quill? Quill is a free, open source WYSIWYG editor built for the modern web. With its modular architecture and expressive API, it is completely customizable to fit any need.

Installation

The package is available only through Composer:

composer require nadar/quill-delta-parser

Usage

// Ensure to load the autoload file from Composer somewhere in your application.
require __DIR__ . '/vendor/autoload.php';

// Create the lexer object with your given Quill JSON delta code (either PHP array or JSON string).
$lexer = new \nadar\quill\Lexer($json);

// Echo the HTML for the given JSON ops.
echo $lexer->render();

Where $json is the ops JSON array from Quill, for example:

{
  "ops": [
    {
      "insert": "Hello"
    },
    {
      "attributes": {
        "header": 1
      },
      "insert": "\n"
    },
    {
      "insert": "\nThis is the PHP Quill "
    },
    {
      "attributes": {
        "bold": true
      },
      "insert": "parser"
    },
    {
      "insert": "!\n"
    }
  ]
}

This would render the following HTML:

<h1>Hello</h1>
<p><br></p>
<p>This is the PHP Quill <strong>parser</strong>!</p>

Extend the Parser

To extend the Parser by adding your own listeners (this can be the case if you are using Quill plugins which generate custom delta code), you have to decide whether it's an:

  • Inline element: Replaces content with new parsed content, mostly the case when working with Quill extensions.
  • Block element: Encloses the whole input with a tag, for example, a heading.

An example for a mention plugin that generates the following delta {"insert":{"mention":{"id":"1","value":"Basil","denotationChar":"@"}}}; an inline plugin could look like this:

class Mention extends InlineListener
{
    /**
     * {@inheritDoc}
     */
    public function process(Line $line)
    {
        // Check if input is JSON, decodes to an array, and checks if the key "mention" 
        // exists. If yes, return the value for this key.
        $mention = $line->insertJsonKey('mention');
        if ($mention) {
            // Apply the inline behavior, updates the content and append to the next "block" element.
            // The value in this example would be "<strong>Basil</strong>".
            $this->updateInput($line, '<strong>'.$mention['value'].'</strong>');
        }
    }
}

Now register the listener:

$lexer = new Lexer($json);
$lexer->registerListener(new Mention());
echo $lexer->render();

Override Built-in Listeners

Certain listeners (image, video, color) produce an HTML output which may not suit your use case, so you have the option to override the properties of those plugins and re-register the Listener. Here's an example with the image tag:

$image = new Image();


$image->wrapper = '<img src="{src}" class="my-image" />';

// Override the default listener behavior for image color:
$lexer = new Lexer($json);
$lexer->registerListener($image);
echo $lexer->render();

If you want to replace a class with your own image class, use overwriteListener to achieve the same result, but with your totally custom class. The reason is that listeners are registered by their class names.

$mySuperClass = new class() extends Image {
  // Here is the custom class code ...
};

$lexer->overwriteListener(new Image(), $mySuperClass);

Or, of course, when you have a separate file for your class:

class MySuperDuperImageClass extends Image
{
    // Here is the custom class code ...
}

$lexer->overwriteListener(new Image(), new MySuperDuperImageClass());

Debugging

Sometimes, understanding how delta is handled and parsed can be challenging to debug. Therefore, you can use the debugger class, which will print a table with information about how the data is parsed.

$lexer = new Lexer($json);
$lexer->render(); // Make sure to run the render before calling debugPrint().
 
$debug = new Debug($lexer);
echo $debug->debugPrint();

There is also a built-in Docker Compose file which provides access to the output.php file. The output.php helps to directly write content with the Quill editor while displaying what is rendered, including all debug information. To run this Docker webserver, execute the following command in the root directory of your Git repository clone:

docker-compose up

and visit http://localhost:5555/ in your browser.

Credits

quill-delta-parser's People

Contributors

bartgloudemans avatar blitheness avatar florisluiten avatar gfaugere avatar imabot2 avatar jwissels avatar leonelngande avatar lode avatar nadar avatar shuedo avatar stijnster avatar tetreum avatar vanoop729 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

quill-delta-parser's Issues

License information

Hello nadar and lode,
I'm interested in using this package but there is no license information so I can't use it until I know what the license terms are. Can you please provide a license?
Thanks for writing this!

Image wrapped in italics renders as text instead of showing the image

Describe the bug

Insert an image to quilljs editor.
Select all (ctrl + a).
Click "italic" icon from quill toolbar.
(my users do this often to italicise their text but inadvertently wrap the image also)

The delta code which generates the Problem

Example:

{"ops":[{"attributes":{"italic":true},"insert":{"image":"https://d3i7mhpybxyfiq.cloudfront.net/original/3xqr7oi10dt67v6zc1e2lv.jpg"}},{"insert":"\n"}]}

The expected html output the delta should produce

anything that creates the img object rather than rendering as text. don't mind where the italic <em> tags end up though they should probably logically wrap the img in this example delta.

Example:

<p><em><img src="https://d3i7mhpybxyfiq.cloudfront.net/original/3xqr7oi10dt67v6zc1e2lv.jpg"></em></p>

What html output the delta is producing instead

Example:

<p><em>{"image":"https:\/\/d3i7mhpybxyfiq.cloudfront.net\/original\/3xqr7oi10dt67v6zc1e2lv.jpg"}</em></p>

Nested lists are not rendered as nested

Describe the bug
Nested lists are not rendered as nested.

The delta code which generates the Problem

{"ops":[{"insert":"Level 1A"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"Level 2A"},{"attributes":{"indent":1,"list":"bullet"},"insert":"\n"},{"insert":"Level 2B"},{"attributes":{"indent":1,"list":"bullet"},"insert":"\n"},{"insert":"Level 1B"},{"attributes":{"list":"bullet"},"insert":"\n"}]}

The expected html output the delta should produce

<ul><li>Level 1A<ul><li>Level 2A</li><li>Level 2B</li></ul></li><li>Level 1B</li></ul>

Expected behavior
The expected behavior is to render nested lists

Screenshots
Editor: Screen Shot 2022-10-31 at 3 18 45 PM

Rendered with nadar: Screen Shot 2022-10-31 at 3 18 53 PM

Additional context
DBlackborough sent me to this QuillJS render library because I needed support for nested lists and his didn't support it. I thought he was implying this library did support them.

Object of class PhpParser\Lexer could not be converted to string

Hello,
I am getting undefined method when I am trying to call render:

    $lexer = new Lexer(json_decode($delta, true));
    echo $lexer->render();
    return;

The delta code which generates the Problem

Example:

{"ops":[{"insert":"this is a test\n"}]}

The expected html output the delta should produce

Example:

<p>This is a test</p>

Expected behavior
It should simply render

Parse Quill 2 tables

Do you plan to add the ability to parse tables from Quill version 2?

Basic example of table from Quill version 2:
[{"insert":"1111"},{"attributes":{"table":"row-nffr"},"insert":"\n"},{"insert":"2222"},{"attributes":{"table":"row-nffr"},"insert":"\n"},{"insert":"3333"},{"attributes":{"table":"row-nffr"},"insert":"\n"},{"insert":"4444"},{"attributes":{"table":"row-nffr"},"insert":"\n"},{"insert":"5555"},{"attributes":{"table":"row-nffr"},"insert":"\n"},{"attributes":{"table":"row-3or1"},"insert":"\n\n\n\n\n"},{"attributes":{"table":"true"},"insert":"\n\n\n\n\n"},{"insert":"\nThis text is outside the table.\n"}]

Center and Header

Describe the bug
When i change Header and set it center, the header will not set. (<h1*></h1*> => <p*></p*>)

The delta code which generates the Problem

{"ops":[{"insert":"test"},{"attributes":{"align":"center","header":1},"insert":"\n"}]}

The expected html output the delta should produce

<p class="ql-align-center">test</p>

Having an empty list breaks the rendering

Ty for creating this delta parser!!!

Describe the bug
Having an empty list breaks the rendering.

The delta code which generates the Problem

[
  {
    "insert": "HI THERE",
    "attributes": {
      "bold": true,
      "color": "#000000",
      "background": "transparent"
    }
  },
  {
    "insert": "\n",
    "attributes": {
      "align": "center"
    }
  },
  {
    "insert": "\nIn publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy. "
  },
  {
    "insert": "\n",
    "attributes": {
      "align": "justify"
    }
  },
  {
    "insert": "\n"
  },
  {
    "insert": "JUST A LIST",
    "attributes": {
      "bold": true,
      "color": "#000000",
      "background": "transparent"
    }
  },
  {
    "insert": "\n",
    "attributes": {
      "align": "center"
    }
  },
  {
    "insert": "\n\n",
    "attributes": {
      "list": "ordered"
    }
  },
  {
    "insert": "\n"
  },
  {
    "insert": "New title",
    "attributes": {
      "bold": true,
      "color": "#000000",
      "background": "transparent"
    }
  },
  {
    "insert": "\nIn publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available."
  },
  {
    "insert": "\n",
    "attributes": {
      "align": "justify"
    }
  },
  {
    "insert": "\n\n"
  }
]

Current behavior
Goes crazy and duplicates the text for each available point.

Screenshot from 2023-03-23 09-26-57

Expected behavior
Should look like in the editor.

Screenshot from 2023-03-23 09-26-49

Empty lines with the 'align' attribute aren't properly rendered

Describe the bug

When the text is aligned to the center and two new lines are inserted before proceeding to write text, the generated output doesn't include the <br> tag on the middle line.

It instead adds an empty paragraph between the two lines of text, which doesn't match the Quill output.

The delta code which generates the problem

{"ops":[{"insert":"Centered text"},{"attributes":{"align":"center"},"insert":"\n\n"},{"insert":"Line three?"},{"attributes":{"align":"center"},"insert":"\n"}]}

This generates the following output:

<p style="text-align: center;">Centered text</p><p style="text-align: center;"></p><p style="text-align: center;">Line three?</p>

The expected HTML output the delta should produce

<p style="text-align: center;">Centered text</p><p style="text-align: center;"><br></p><p style="text-align: center;">Line three?</p>

Expected behavior

The second line, even though it doesn't contain any text, should still render in order to space out the two lines of text correctly.

Additional context

I managed to pinpoint the issue to the align implementation, given that if I remove the {"align":"center"} from the empty line, it renders correctly as <p><br><p>.

I believe the <br> tag might be escaped within the wrapElement call that is made from the Align listener.

allows 8 digit hex color code support

Describe the bug
currently if quill delta contains color with alpha than htm rendering is not well

The delta code which generates the Problem

Example:

[{"insert":"Hello "},{"insert":"Orange","attributes":{"color":"#FFFFA726"}},{"insert":"\n"}]

Expected behavior
in html file 8 digit hex is not support so we need to convert in rgba.

Additional context
we can edit color file and add some extra code:
File : https://github.com/nadar/quill-delta-parser/blob/master/src/listener/Color.php

Code:

public function process(Line $line)
{
    if (($color = $line->getAttribute('color'))) {

        // Check for valid hex code format (including #)
        if (preg_match('/^#[0-9a-f]{8}$/i', $color)) {
            $rgbaColor = $this->hexToRgba($color);
        } else {
            $rgbaColor = $color; // Use original color if not valid format
        }

        $this->updateInput($line, $this->ignore ? $line->getInput() : '<span style="color:'.$line->getLexer()->escape($rgbaColor).'">'.$line->getInput().'</span>');
    }
}

// Helper function to convert 8-digit hex code to RGBA
private function hexToRgba($hexColor)
{
    $hexColor = ltrim($hexColor, '#'); // Remove leading # if present
    if (strlen($hexColor) === 8) {
          $r = hexdec(substr($hexColor, 1, 2));
        $g = hexdec(substr($hexColor, 3, 2));
        $b = hexdec(substr($hexColor, 5, 2));
        $a = hexdec(substr($hexColor, 7, 2)) / 255; // Convert alpha to decimal
        return "rgba($r, $g, $b, $a)";
    } else {
        return $hexColor; // Return original color if not 8-digit
    }
}

Behavior of inserts with unknown attributes

Describe the bug
When attributes are unknown to the renderer it does not render the text, just a newline

The delta code which generates the Problem

{"ops":[{"insert":"1"},{"attributes":{"unknownAttribute":{"id": 123}},"insert":"2"},{"insert":"3"},{"insert":"\n"}]}
Expected :'<p>123</p>'
Actual   :'<p>1</p><p>3</p><p><br></p>'

Another example :
Lexer without registering Bold listener (HeadingContentTest.php):

{"ops":[
  {"insert":"xyz","attributes":{"bold":true}},
  {"insert":"\n"},
  {"insert":"regular"},
  {"insert":"bold","attributes":{"bold":true}},
  {"insert":"italic", "attributes":{"italic":true}},
  {"insert":"\n","attributes":{"header":1}},
  {"insert":"xyz\n"}
]}

Expected :'<p>xyz</p><h1>regularbold<em>italic</em></h1><p>xyz</p>'
Actual   :'<p><br></p><h1>regularbold<em>italic</em></h1><p>xyz</p>'

Here you see that de garbage-cleaning kinda works sometimes

Expected behavior
Expected behavior is to just render the text as a regular insert. This is - as far as i understand it - how quilljs behaves.

What do you think?

Inserting an empty line in header 2 format creates strange html

Hi there,

thanks for your work on this parser, I've started to use it a few weeks ago and extended it with success!

However, we noticed one thing when parsing the delta to HTML.

For this ticket I'll add some simplified content.

Screenshot 2019-08-28 at 19 01 31

This gets converted into the following delta;

{"ops":[{"insert":"Here is a title"},{"attributes":{"header":2},"insert":"\n"},{"insert":"Here is some content\n"}]}

And generates just fine.

However, when we hit enter just before "Here is a Title" in the quill.js editor, an empty h2 line is inserted which generates the following delta;

{"ops":[{"attributes":{"header":2},"insert":"\n"},{"insert":"Here is a title"},{"attributes":{"header":2},"insert":"\n"},{"insert":"Here is some content\n"}]}

This should generate something like the following (we can debate wether the
should be there or not, or find another solution);

<h2><br>Title</h2>
<p>Here is some content</p>

Instead it generates something like;

<h2>Here is a titleHere is some content</h2><h2>Here is a title</h2>

At first, this example might seem far fetched. But in the editor it is easy to do and easy to overlook the fact that the empty line is still in "header2";

Screenshot 2019-08-28 at 19 01 39

Thanks for taking the time to have a look a this issue!

Kind regards,

Stijn

Bug with EOL processing

Bug description
Accordingly to deltas description the EOL character can be only \n, but in Windows PHP_EOL is equal to \r\n. Due to this issue the method replaceNewlineWithExpression of the Lexer class will not work correctly.

protected function replaceNewlineWithExpression($string)
{
   return str_replace(PHP_EOL, self::NEWLINE_EXPRESSION, $string);
}

Example of a delta-object

{
  "ops": [
    {
      "insert": "Header 1"
    },
    {
      "attributes": {
        "header": 5
      },
      "insert": "\n"
    },
    {
      "insert": "Some cool stuff\nHeader 2"
    },
    {
      "attributes": {
        "header": 3
      },
      "insert": "\n"
    }
  ]
}

Produced HTML (incorrect)

<h5>Header 1</h5><h3>Some cool stuff Header 2</h3>

The expected html output the delta should produce

<h5>Header 1</h5><p>Some cool stuff</p><h3>Header 2</h3>

Expected behavior (Bugfix sugestion)

class Lexer
{
    const EOL = "\n";
    ...

    protected function replaceNewlineWithExpression($string)
    {
        return str_replace(self::EOL, self::NEWLINE_EXPRESSION, $string);
    }
...

Additional context
Thanks a lot for your work :)

Link with partially styled text breaks up in parts

Description
I would like to render an anchor-tag with part of its contents wrapped in <em>.
Instead I get multiple anchor-tags, each representing the different stylings, separately..

The delta code which generates the Problem

Example:

[
	{"insert":"Hello ","attributes":{"link":"https://example.com"}},
	{"insert":"world", "attributes":{"link":"https://example.com","italic":true}},
	{"insert":"\n"}
],

The expected html output the delta should produce

Example:

<p><a href="https://example.com">Hello <em>world</em></a></p>

The observed html output the delta produces

Example:

<p><a href="https://example.com">Hello </a><a href="https://example.com"><em>world</em></a></p>

Expected behavior
As output I expect a single anchor tag, with part of its contents wrapped in an em-tag.

Observed behavior
Multiple anchor-tags with the different stylings in each separate anchor-tag.

Additional context
My listener setup

use nadar\quill\Lexer;
use nadar\quill\listener\Italic as ItalicListener;
use nadar\quill\listener\Link as LinkListener;
use nadar\quill\listener\Text as TextListener;

$lexer              = new Lexer($contents);
$lexer->escapeInput = true;

$lexer->registerListener(new ItalicListener());
$lexer->registerListener(new LinkListener());
$lexer->registerListener(new TextListener());

$html = $lexer->render();

Exception: An unknown alignment "left" has been detected.

Bug Description
When i try to convert quill delta to html its throw Exception

Exception: An unknown alignment "left" has been detected.

Bug reproduce
its happening only when data is empty with left alignment ex:
[{"insert":"\n", "attributes":{"align": "left"}},{"insert":" \n"}]

Image height and width is not getting rendered

Describe the bug

When the height and width attributes appear in an image, they do not get rendered in the HTML.

The delta code which generates the Problem

Example:

{"ops":[{"attributes":{"height":"141","width":"210","color":"#000000","background":"transparent"},"insert":{"image":"https://lh6.googleusercontent.com/XhTtDRQlxIzcbEk-lQ38XDV0p4Gg7A0vYrP-r6huUZXyoGDMdKcb7jkl5i31BfQPGAhK3Yk_AEUrw1e8fEdCxWLVCl2UCzPHoAXDg4HqK_KlUGH4IdnZKyPqVLkyCm5PFFJ-AAEEclxnQX7jvnxm7aw"}},{"insert":"\n"}]}

The expected html output the delta should produce

Example (Expected)

<p><span style="color:#000000"><img src="https://lh6.googleusercontent.com/XhTtDRQlxIzcbEk-lQ38XDV0p4Gg7A0vYrP-r6huUZXyoGDMdKcb7jkl5i31BfQPGAhK3Yk_AEUrw1e8fEdCxWLVCl2UCzPHoAXDg4HqK_KlUGH4IdnZKyPqVLkyCm5PFFJ-AAEEclxnQX7jvnxm7aw" height="141px" width="210px" alt="" class="img-responsive img-fluid" /></span></p>

Actual:

<p><span style="color:#000000"><img src="https://lh6.googleusercontent.com/XhTtDRQlxIzcbEk-lQ38XDV0p4Gg7A0vYrP-r6huUZXyoGDMdKcb7jkl5i31BfQPGAhK3Yk_AEUrw1e8fEdCxWLVCl2UCzPHoAXDg4HqK_KlUGH4IdnZKyPqVLkyCm5PFFJ-AAEEclxnQX7jvnxm7aw" alt="" class="img-responsive img-fluid" /></span></p>

Expected behavior
height="141px" width="210px" should appear when "height":"141","width":"210" appears in the attributes.

Screenshots
Actual:
image
Expected:
image

Additional context
These attributes appear in quill after pasting from a Google doc with a resized image.

Heading level nested in attributes results in fatal error

I'm parsing a delta from Vanilla Forums (also referenced in #53). Some posts contain this (or similar) Delta entry for a heading:

{"attributes":{"header":{"level":1,"ref":""}},"insert":"\n"}

This results in the errors:

Warning: Array to string conversion in /Users/linc/code/porter/vendor/nadar/quill-delta-parser/src/listener/Heading.php on line 46

Fatal error: Uncaught Exception: An unknown heading level "Array" has been detected. in /Users/linc/code/porter/vendor/nadar/quill-delta-parser/src/listener/Heading.php:46

In the Quill JS docs, I only see header used like this:

{ insert: '\n', attributes: { header: 1 } },

This appears to be what line 46 in Heading.php is expecting β€”Β an integer value to insert, not an array with a level element inside it.

I do not know if this is something Vanilla Forums customized or is now part of the official Quill Delta format, but I thought I'd report it in case it's something you want to support.

Process

  1. priority first element (inline) foreach trough deltas and manipulate the insert() value.
  2. priority second elements (block elements: list, heading, ...) foreach trough deltas and process them, which includes removing delta elements and replace the last item with new content with collected data.
  3. priority "garbage collector" is reserved for the newline and text element which creates the

    and replaces the \n\n's.

Codeblocks doesn't render

Data before rendering

{"ops": [{"insert": "for (int i = 7000000; i < 7999999; i++) { Console.WriteLine(\"Number: +960 \" + i); StringBuilder sb = new StringBuilder(); sb.AppendFormat(\"\\n{0},{1}\", \"Name\", i); File.AppendAllText(\"Dhiraagu.csv\", sb.ToString()); }"}, {"insert": "\n", "attributes": {"code-block": true}}]}

Data after rendering

<p> for (int i = 7000000; i &lt; 7999999; i++) {</p><p>      DisplayName = String.valueOf(i);</p><p>      MobileNumber = &quot;960&quot;+String.valueOf(i);</p><p>      ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;ContentProviderOperation&gt;();</p><p>      ops.add(ContentProviderOperation.newInsert(</p><p>          ContactsContract.RawContacts.CONTENT_URI)</p><p>          .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)</p><p>          .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)</p><p>          .build());</p><p>      //------------------------------------------------------ Names</p><p>      if (DisplayName != null) {</p>

Code blocks not rendering correctly. <p> tag is being used to render it

Best practice for overriding Link class

I am looking for a way to customise link behaviour:

external links:
rel = "nofollow"
target = "_blank"

internal links:
rel = ""
target = ""

I'm just wondering what is the best way to override the existing Link class behaviour?

I see in the docs how to override the wrapper property, but is there a way to override the process method?

If not and I need to create another class CustomLink and register it, will both Link and CustomLink be run?

Am I maybe better off just doing a composer override of the Link.php file completely and change the process method this way?

Thanks for your help and for creating this package.

Font attribute causes insert to be skipped

Insert with "font" attribute appear to be skipped when rendering.
This is probably related to #20 but font being a native Quill feature, I did not expect this.

Delta:

{"ops":[{"insert":"Lorem "},{"attributes":{"font":"serif"},"insert":"Ipsum"},{"insert":" Dolor. "},{"attributes":{"font":"monospace"},"insert":"Sit"},{"insert":" Amet.\n"}]}

Expected output (not sure how the span should be styled):

<p>Lorem <span style="font-family: serif;">Ipsum</span> Dolor. <span style="font-family: monospace;">Sit</span> Amet.</p>

Output received:

<p>Lorem </p><p> Dolor. </p><p> Amet.</p>

Issue with multiple ul-li lists where ul-li list contains only one item

Hi there,

we found a new issue when using the quill-delta-parser;

Screenshot 2019-10-23 at 15 15 23

Here is the initial delta;

{"ops":[{"insert":"line 1\nbullet 1 - 1"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"line 2\nbullet 2 - 1"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"line 3\nbullet 3 - 1"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"line 4\nbullet 4 - 1"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"bullet 4 - 2"},{"attributes":{"list":"bullet"},"insert":"\n"},{"insert":"line 5\n"}]}

And here is the current output;

<p>line 1</p><ul><li>bullet 1 - 1</li></ul><p>line 2</p><li>bullet 2 - 1</li><p>line 3</p><li>bullet 3 - 1</li><p>line 4</p><ul><li>bullet 4 - 1</li><li>bullet 4 - 2</li></ul><p>line 5</p>

However, this is the expected output;

<p>line 1</p><ul><li>bullet 1 - 1</li></ul><p>line 2</p><ul><li>bullet 2 - 1</li></ul><p>line 3</p><ul><li>bullet 3 - 1</li></ul><p>line 4</p><ul><li>bullet 4 - 1</li><li>bullet 4 - 2</li></ul><p>line 5</p>

The ul-li lists with only one item are missing the wrapping ul element, except for the very first one (bullet 1 - 1). Strangely enough, the last bullet list (with more than one item) is created as expected.

I've started looking into the listsener\Lists class to see if I could fix the problem. But it turns out to be quite an adventure :)

Enable escapeInput by default

Encoding input value should be done by default, therefore enable escapeInput by default.


Security

Currently html escaping is not turned on by default. This means that a delta where the insert or attributes contain user supplied data can cause XSS.

To use html escaping always set $lexer->escapeInput to true:

use nadar\quill\Lexer;	
$lexer = new Lexer($json);	
$lexer->escapeInput = true;	

Multiple Attributes can not be distinguished

Bug Description
When Header attribute is accompanied by other attributes, it can not be parsed as Heading.

Bug reproduce

Example:

     {
         "insert":"Header"
      },
      {
         "attributes":{
            "align":"right",
            "direction":"rtl",
            "header":2
         },
         "insert":"\n"
      },

The expected html output the delta should produce

Example:

<h2 style="direction:rtl; align: right">Header</h2>

list with fomated items produces invalid html

Describe the bug

an list with formatted items misses the <ol></ol> tags in html output

The delta code which generates the Problem

{"ops":[{"attributes":{"bold":true},"insert":"bold"},{"attributes":{"list":"ordered"},"insert":"\n"},{"attributes":{"italic":true},"insert":"italic"},{"attributes":{"list":"ordered"},"insert":"\n"},{"attributes":{"underline":true},"insert":"underline"},{"attributes":{"list":"ordered"},"insert":"\n"},{"attributes":{"strike":true},"insert":"strike"},{"attributes":{"list":"ordered"},"insert":"\n"},{"insert":"\nnormal Text\n"}]}

The expected html output the delta should produce

<ol><li><strong>bold</strong></li><li><em>italic</em></li><li><u>underline</u></li><li><s>strike</s></li></ol><p><br></p><p>normal Text</p>

background color removed from html result

Describe the bug
The option for background color does not get processed.

The delta code which generates the Problem
Example:

 10 => array:1 [
      "insert" => """
        color.
        This has a 
        """
    ]
    11 => array:2 [
      "attributes" => array:1 [
        "background" => "#a10000"
      ]
      "insert" => "background "
    ]
    12 => array:1 [
      "insert" => """
        color.
        This is a list item
        """
    ]

The expected html output the delta should produce

Example:

This line has <span style="background-color: #0047b2">background</span>color.

Expected behavior
I expect the text to have a colored background instead of being removed from the result.

Screenshots
image

Additional context

quill = new Quill('#editor', {
                        placeholder: 'Compose an epic...',
                        modules: {
                            toolbar: [
                                ['bold', 'italic', 'underline', 'link'],
                                [
                                    { color: [ "#000000", "#e60000", "#ff9900", "#ffff00", "#008a00", "#0066cc", "#9933ff", "#ffffff", "#facccc", "#ffebcc", "#ffffcc", "#cce8cc", "#cce0f5", "#ebd6ff", "#bbbbbb", "#f06666", "#ffc266", "#ffff66", "#66b966", "#66a3e0", "#c285ff", "#888888", "#a10000", "#b26b00", "#b2b200", "#006100", "#0047b2", "#6b24b2", "#444444", "#5c0000", "#663d00", "#666600", "#003700", "#002966", "#3d1466", ] },
                                    { background: [ "#000000", "#e60000", "#ff9900", "#ffff00", "#008a00", "#0066cc", "#9933ff", "#ffffff", "#facccc", "#ffebcc", "#ffffcc", "#cce8cc", "#cce0f5", "#ebd6ff", "#bbbbbb", "#f06666", "#ffc266", "#ffff66", "#66b966", "#66a3e0", "#c285ff", "#888888", "#a10000", "#b26b00", "#b2b200", "#006100", "#0047b2", "#6b24b2", "#444444", "#5c0000", "#663d00", "#666600", "#003700", "#002966", "#3d1466", ] }
                                ],
                                [{ list: 'ordered' }, { list: 'bullet' }],
                                ['clean']
                            ]
                        },
                        theme: 'snow'
                    });

missing image property

Describe the bug
A clear and concise description of what the bug is.

The delta code which generates the Problem

Example:

{"image":"https:\/\/www.image.com"}

The expected html output the delta should produce

Example:

<img src="https:/image.com">

insertJsonKey not working

Describe the bug
I'm using this plugin to resize images: https://github.com/kensnyder/quill-image-resize-module
and this one to upload images on the server: https://github.com/NoelOConnell/quill-image-uploader

These two generates the following:

Screen Shot 2022-02-22 at 4 24 23 PM

Now I'm trying to extend this library to allow me to display the image in its custom size:

<?php
namespace App\Library;

use nadar\quill\Line;
use nadar\quill\InlineListener;

class ImageSizeListener extends InlineListener {

    public function process(Line $line)
    {
        $image_styles = $line->getAttribute('style');
        $image = $line->insertJsonKey('image');
        if ($line->isJsonInsert()) {
            info('JSON insert');
        }

        if ($image_styles) {
            $this->updateInput($line, '<img src="' . $image . '" style="' . $image_styles . '" alt="" class="img-responsive img-fluid">');
        }
    }

}

I then call it this way:

use App\Library\ImageSizeListener;

$lexer = new Lexer($town->about_page_html);
$lexer->registerListener(new ImageSizeListener);
$html = $lexer->render();

The delta code which generates the Problem

{"attributes":{"style":"width: 136px;","data-size":"200,200"},"insert":{"image":"/about_images/UITBM"}}

The expected html output the delta should produce

Example:

<img src="/about_images/UITBM" style="width: 136px;" alt="" class="img-responsive img-fluid">

Expected behavior

I'm expecting to get the image source when this line gets called:

$image = $line->insertJsonKey('image');

Nothing gets called though. Because when I tried it this way, nothing is logged:

if ($line->isJsonInsert()) {
  info('JSON insert');
}

Screenshots

Screen Shot 2022-02-22 at 4 31 22 PM

video listener bug

Describe the bug
Video tag output is not good, it prints the delta code instead of the html.

The delta code which generates the Problem

Example:

{"insert":{"video":"test.webm"}},

The expected html output the delta should produce

Example:

<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" src="test.webm" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>

Expected behavior
The html output should bethe one above, instead the delta is the output:

<p style="text-align: center;">{"video":"\/assets\/others\/SvHwb6TvSF1X8Obtq0rcKTk0f7frenDLbQgBRLoV.webm"}</p>

Screenshots
If applicable, add screenshots to help explain your problem.
image

Using "use nadar\quill\listener\Video;" for Video.

<p> without close tag is added when list has bold text and a previous linebreak

Describe the bug
When a list that contains text with attribute bold (it may happen with other kind of inline attributes) has a previous linebreak, the next paragraph after the list breaks.

The delta code which generates the Problem

This is the delta code that fails:

[
  {
    "insert": "This is begin text:\n\n"
  },
  {
    "attributes": {
      "bold": true
    },
    "insert": "Bold text"
  },
  {
    "insert": " and regular text"
  },
  {
    "attributes": {
      "list": "bullet"
    },
    "insert": "\n"
  },
  {
    "insert": "Another bullet"
  },
  {
    "attributes": {
      "list": "bullet"
    },
    "insert": "\n"
  },
  {
    "insert": "Another text after list"
  }
]

The expected html output the delta should produce

It should produce this:

<p>This is begin text:</p><p><br></p><ul><li><strong>Bold text</strong> and regular text</li><li>Another bullet</li></ul><p>Another text after list</p>

But the result is this:

<p>This is begin text:</p><p><br></p><p><ul><li><strong>Bold text</strong> and regular text</li><li>Another bullet</li></ul>Another text after list</p>

Notice the additional <p> tag before the <ul>, which breaks the HTML structure.

Additional context
Upon investigating the Text.render function, it appears that the issue stems from this conditional statement:

} elseif ($pick->line->isEmpty() && $next) {
     $isOpen = $this->output($output, self::CLOSEP.self::OPENP, true);
}

In cases where there is a line break, the variable $next contains the line text <strong>Bold text</strong>, which is inline but also marked as "Done." Consequently, an opening <p> tag is generated due to the fulfillment of the if condition, but it fails to close properly because the line is marked as "Done."

Proposed solution:

Updating the condition to the following resolves the issue:

elseif ($pick->line->isEmpty() && $next && !$next->isDone()) {

This adjustment ensures that the <p> tag is only opened when the next line is not marked as "Done," effectively resolving the problem.

Can I use delta coming from quill to update contents (delta object) with this library?

Hello, sorry for opening an issue about this question, but from the documentation alone I cannot figure it out. And maybe you'll be better at helping me towards the right direction - I would very much appreciate it!

The discussion started here: quilljs/quill#4026

In summary, I'm saving Quill content in my SQL database as a delta object. And when changes are made on the website, I want to send only the changed text (using delta from text-change event), because it's not ideal to keep sending the whole editor contents for simple changes/updates in the document.

As far as I can tell, there's nothing mentioned about this in the documentation or under quill-awesome repo that can do this. But I'm a bit stunned because how is everyone else doing it then? Send the whole getContents each time (currently I'm doing this)? Can you help me sum up this question please?

If I can use this library or contribute in some way here so that we can achieve this goal it would be great!

Thanks in advance

Problem with attributes key?

{
  "ops": [
    {
      "attributes": {
        "color": "#000000"
      },
      "insert": "xyz"
    },
    {
      "insert": "\n\n"
    },
    {
      "attributes": {
        "color": "#000000"
      },
      "insert": "xyz"
    },
    {
      "insert": "\n\n"
    },
    {
      "insert": " \n\n"
    }
  ]
}

Wrong parsing

Describe the bug

Code generated bu Quill and understaded by quill is totaly broken using this library.

Easily reproductible by using multiple headers in same editor.

The delta code which generates the Problem

Example:

{"ops":[{"insert":"title 1"},{"attributes":{"header":1},"insert":"\n"},{"insert":"\nhelllooook\n\nthe title two"},{"attributes":{"header":2},"insert":"\n"},{"insert":"\nok ok\n"}]}

The expected html output the delta should produce

<h1>title 1</h1>
<p>helllooook</p>
<h2>the title two</h2>
<p>ok ok</p>

image

Rendering inline listeners priority

Describe the bug
When rendering inline items the priority messes with the content, sometimes even deleting content

The delta code which generates the Problem

{"ops": [
  {"attributes": {"italic": true},"insert": "italic text"},
  {"attributes": {"link": "https://www.test.com/","bold": true},"insert": "link"},
  {"insert": "\n"}
]}

The expected html output the delta should produce

<p><em>italic text</em><a href="https://www.test.com/" target="_blank"><strong>link</strong></a></p>

Expected behavior
I expect the order of the inserts to be honored

Additional context
This bug also happens with other inline items;
I would like to help fix it but am unsure of the desired direction; It feels like we need to revisit the entire order of how inline things are rendered at the moment. Did you notice this before? Do you have a desired direction? Or do you consider this behavior as intended?

If you update output.php on line 40 & 41

<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>

link will work on the demo page

Random line breaks

I am using this package after using @deanblackborough's first, because I needed the ability to extend.

The only problem I am having is that the line breaks are 3 lines. Whenever I have a break in my delta, it shows as <p><br></p>. I wasn't having this issue with the other package. Do you have any idea what causes this?

thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.