├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── php.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── Tests ├── Api │ ├── BugTest.php │ ├── MultipleTest.php │ └── StockTest.php ├── Attributes │ ├── GitHubMarkdown │ │ ├── HeaderTest.php │ │ ├── HrefTest.php │ │ ├── ImageTest.php │ │ ├── ListTest.php │ │ ├── TypographyTest.php │ │ └── VideoTest.php │ ├── Html │ │ ├── HeaderTest.php │ │ ├── HrefTest.php │ │ ├── ImageTest.php │ │ ├── ListTest.php │ │ ├── TypographyTest.php │ │ └── VideoTest.php │ └── Markdown │ │ ├── HeaderTest.php │ │ ├── HrefTest.php │ │ ├── ImageTest.php │ │ ├── ListTest.php │ │ ├── TypographyTest.php │ │ └── VideoTest.php └── Combined │ ├── GitHubMarkdown │ ├── BreaksTest.php │ ├── HeaderTest.php │ └── ListTest.php │ ├── Html │ ├── BoldColorTest.php │ ├── BreaksTest.php │ ├── HeaderTest.php │ ├── ListTest.php │ └── MixTest.php │ └── Markdown │ ├── BreaksTest.php │ ├── HeaderTest.php │ └── ListTest.php ├── composer.json ├── composer.lock ├── phpunit.xml └── src ├── Delta ├── Delta.php ├── GithubMarkdown │ ├── Delta.php │ └── Strike.php ├── Html │ ├── Bold.php │ ├── Color.php │ ├── Compound.php │ ├── CompoundImage.php │ ├── CompoundVideo.php │ ├── Delta.php │ ├── Header.php │ ├── Image.php │ ├── Insert.php │ ├── Italic.php │ ├── Link.php │ ├── ListItem.php │ ├── Strike.php │ ├── SubScript.php │ ├── SuperScript.php │ ├── Underline.php │ └── Video.php └── Markdown │ ├── Bold.php │ ├── Compound.php │ ├── Delta.php │ ├── Header.php │ ├── Image.php │ ├── Insert.php │ ├── Italic.php │ ├── Link.php │ ├── ListItem.php │ └── Video.php ├── Interfaces ├── DeltaInterface.php ├── ParserAttributeInterface.php ├── ParserInterface.php └── RendererInterface.php ├── Options.php ├── Parser ├── GithubMarkdown.php ├── Html.php ├── Markdown.php └── Parse.php ├── Render.php ├── RenderMultiple.php ├── Renderer ├── GithubMarkdown.php ├── Html.php ├── Markdown.php └── Render.php └── Settings.php /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # PHP Project 5 | *.php text 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [deanblackborough] 4 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: Validate dependencies and run tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ${{ matrix.operating-system }} 13 | strategy: 14 | matrix: 15 | operating-system: [ubuntu-latest] 16 | php-versions: ['7.4', '8.0', '8.1'] 17 | 18 | name: PHP ${{ matrix.php-versions }} test on ${{ matrix.operating-system }} 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v2 23 | 24 | - name: Install PHP 25 | uses: shivammathur/setup-php@v2 26 | with: 27 | php-version: ${{ matrix.php-versions }} 28 | 29 | - name: Validate composer.json and composer.lock 30 | run: composer validate --strict 31 | 32 | - name: Cache Composer packages 33 | id: composer-cache 34 | uses: actions/cache@v2 35 | with: 36 | path: vendor 37 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 38 | restore-keys: | 39 | ${{ runner.os }}-php- 40 | 41 | - name: Install dependencies 42 | run: composer install --prefer-dist --no-progress 43 | 44 | - name: Run test suite 45 | run: composer run-script test 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | dev/ 3 | vendor/ 4 | .phpunit.result.cache 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at dean@g3d-development.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute? 2 | 3 | If you would like to contribute, please try to adhere to the coding standards I have detailed below, if you have any questions or believe I have missed something, please contact me, ideally all code should adhere to PSR2. 4 | 5 | ## Pull requests 6 | 7 | Pull requests should be from a branch in your fork, please also try to give your branch a name that relates to the change/feature you want me to merge. Most importantly, before creating a pull request, please update your fork. 8 | 9 | ## Files 10 | 11 | * Use UTF-8 character encoding. 12 | * Unix formatted, (LF). 13 | * A line length of 120 characters, this is not in any way a fixed requirement, please let context dictate, don't make code harder to read by wrapping it to hit a particular line length. 14 | * All code and comments should be in English. 15 | * Spaces for all indenting, I recommend four spaces per tab. 16 | 17 | ## PHP 18 | 19 | * Please always use ``````, never ``````. 20 | * PHP ```CONSTANTS``` should all be in ```UPPERCASE```. 21 | * PHP keywords should be in ```lowercase```, including, ```true```, ```false``` and ```null```. 22 | * Braces on their own line for classes, namespaces and functions 23 | * Braces in line for if/while etc 24 | * ```UpperCamelCase``` for classes, interfaces etc. 25 | * ```lowerCamelCase``` for methods and functions 26 | * ```lowercase_with_underscores``` for multiple word variables/fields 27 | 28 | You can read more about PSR at the following link - 29 | https://www.php-fig.org/psr/psr-2/ 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2019 Dean Blackborough 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://img.shields.io/packagist/v/deanblackborough/php-quill-renderer.svg?style=flat-square)](https://packagist.org/packages/deanblackborough/php-quill-renderer) 2 | ![Packagist](https://img.shields.io/packagist/dt/deanblackborough/php-quill-renderer.svg) 3 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE) 4 | [![Minimum PHP Version](https://img.shields.io/badge/php->=7.4-8892BF.svg)](https://php.net/) 5 | [![Supported PHP Version](https://img.shields.io/badge/php-^8.0-8892BF.svg)](https://php.net/) 6 | [![Supported PHP Version](https://img.shields.io/badge/php-^8.1-8892BF.svg)](https://php.net/) 7 | [![Validate dependencies and run tests](https://github.com/deanblackborough/php-quill-renderer/actions/workflows/php.yml/badge.svg)](https://github.com/deanblackborough/php-quill-renderer/actions/workflows/php.yml) 8 | 9 | # PHP Quill Renderer 10 | 11 | Render quill insert deltas to HTML, Markdown and GitHub flavoured Markdown. 12 | 13 | ## Read-only 14 | It doesn't look like there will be new version of Quill, I've decided to make the repo read-only, I'm not going to dedicate anymore time to this package. 15 | 16 | ## Description 17 | 18 | [Quill](https://github.com/quilljs/quill) deltas renderer, converts deltas to HTML and Markdown, the [Quill](https://github.com/quilljs/quill) attributes 19 | supported are listed in the table below, the goal is to eventually support every Quill feature. 20 | 21 | [Quill](https://github.com/quilljs/quill) is a modern WYSIWYG editor built for compatibility and extensibility. 22 | 23 | ## Installation 24 | 25 | The easiest way to use the `PHP Quill Renderer` is via composer. 26 | ```composer require deanblackborough/php-quill-renderer```, 27 | alternatively you can include the classes in my src/ directory directly in your 28 | library or app. 29 | 30 | ## Usage 31 | 32 | ### Via API, single $quill_json 33 | ```php 34 | try { 35 | $quill = new \DBlackborough\Quill\Render($quill_json); 36 | $result = $quill->render(); 37 | } catch (\Exception $e) { 38 | echo $e->getMessage(); 39 | } 40 | 41 | echo $result; 42 | ``` 43 | 44 | ### Via API, multiple $quill_json, passed in via array 45 | 46 | ```php 47 | try { 48 | $quill = new RenderMultiple($quill_json, 'HTML'); 49 | 50 | $result_one = $quill->render('one'); 51 | $result_two = $quill->render('two'); 52 | } catch (\Exception $e) { 53 | echo $e->getMessage(); 54 | } 55 | 56 | echo $result_one; 57 | echo $result_two; 58 | ``` 59 | 60 | ### Direct, parse and then render, single $quill_json - updated in v3.10.0 61 | 62 | ```php 63 | $parser = new \DBlackborough\Quill\Parser\Html(); 64 | $renderer = new \DBlackborough\Quill\Renderer\Html(); 65 | 66 | $parser->load($quill_json)->parse(); 67 | 68 | echo $renderer->load($parser->deltas())->render(); 69 | ``` 70 | 71 | ### Direct, parse and then render, multiple $quill_json - updated in v3.10.0 72 | 73 | ```php 74 | $parser = new \DBlackborough\Quill\Parser\Html(); 75 | $renderer = new \DBlackborough\Quill\Renderer\Html(); 76 | 77 | $parser->loadMultiple(['one'=> $quill_json_1, 'two' => $quill_json_2)->parseMultiple(); 78 | 79 | echo $renderer->load($parser->deltasByIndex('one'))->render(); 80 | echo $renderer->load($parser->deltasByIndex('two'))->render(); 81 | ``` 82 | 83 | ## Quill attributes and text flow support 84 | 85 | | Attribute | v1+ | v2+ | v3 HTML | v3 Markdown 86 | | :---: | :---: | :---: | :---: | :---: 87 | | Bold | Yes | Yes | Yes | Yes 88 | | Italic | Yes | Yes | Yes | Yes 89 | | Link | Yes | Yes | Yes | Yes 90 | | Strike | Yes | Yes | Yes | N/A 91 | | Script:Sub | Yes | Yes | Yes | N/A 92 | | Script:Super | Yes | Yes | Yes | N/A 93 | | Underline | Yes | Yes | Yes | N/A 94 | | Header | Yes | Yes | Yes | Yes 95 | | Image | Yes | Yes | Yes | Yes 96 | | Video | No | No | Yes | Yes 97 | | List | Yes | Yes | Yes | Yes 98 | | Child lists | No | No | No | No 99 | | Indent/Outdent | No| No | No | No 100 | | Text direction | No | No | No | N/A 101 | | Color | No | No | No | N/K 102 | | Font | No | No | No | N/K 103 | | Text align | No | No | No | N/A 104 | | Block quote | No | No | No | No 105 | | Code block | No | No | No | No 106 | | Custom attributes | No | No | Yes | N/A 107 | | Line breaks | No | No | Yes | Yes 108 | | Paragraphs | Yes | Yes | Yes | Yes 109 | 110 | | Attribute | HTML Tag | Markdown Token 111 | | :---: | :---: | :---: 112 | | Bold | `` | `**` 113 | | Italic | `` | `*` 114 | | Link | `` | `[Text](Link)` 115 | | Strike | `` | 116 | | Script:Sub | `` | 117 | | Script:Super | `` | 118 | | Underline | `` | 119 | | Header | `` | `#[n]` 120 | | Image | `` | `![Image](\path\to\image)` 121 | | Video | `

'; 19 | private $expected_video_attribute = '

'; 20 | private $expected_video_attributes = '

'; 21 | 22 | /** 23 | * Video 24 | * 25 | * @return void 26 | * @throws \Exception 27 | */ 28 | public function testVideo() 29 | { 30 | $result = null; 31 | 32 | try { 33 | $quill = new QuillRender($this->delta_video); 34 | $result = $quill->render(); 35 | } catch (\Exception $e) { 36 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 37 | } 38 | 39 | $this->assertEquals($this->expected_video, trim($result), __METHOD__ . ' Video failure'); 40 | } 41 | 42 | /** 43 | * Video with a single attribute 44 | * 45 | * @return void 46 | * @throws \Exception 47 | */ 48 | public function testVideoWithAttribute() 49 | { 50 | $result = null; 51 | 52 | try { 53 | $quill = new QuillRender($this->delta_video_attribute); 54 | $result = $quill->render(); 55 | } catch (\Exception $e) { 56 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage() . PHP_EOL . $e->getTraceAsString()); 57 | } 58 | 59 | $this->assertEquals($this->expected_video_attribute, trim($result), __METHOD__ . ' Video failure'); 60 | } 61 | 62 | /** 63 | * Video with multiple attributes 64 | * 65 | * @return void 66 | * @throws \Exception 67 | */ 68 | public function testVideoWithAttributes() 69 | { 70 | $result = null; 71 | 72 | try { 73 | $quill = new QuillRender($this->delta_video_attributes); 74 | $result = $quill->render(); 75 | } catch (\Exception $e) { 76 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage() . PHP_EOL . $e->getTraceAsString()); 77 | } 78 | 79 | $this->assertEquals($this->expected_video_attributes, trim($result), __METHOD__ . ' Video failure'); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/HeaderTest.php: -------------------------------------------------------------------------------- 1 | delta_h1, Options::FORMAT_MARKDOWN); 43 | $result = $quill->render(); 44 | } catch (\Exception $e) { 45 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 46 | } 47 | 48 | $this->assertEquals( 49 | $this->expected_h1, 50 | trim($result), 51 | __METHOD__ . ' - Header 1 failure' 52 | ); 53 | } 54 | 55 | /** 56 | * Header 2 57 | * 58 | * @return void 59 | * @throws \Exception 60 | */ 61 | public function testHeader2() 62 | { 63 | $result = null; 64 | 65 | try { 66 | $quill = new QuillRender($this->delta_h2, Options::FORMAT_MARKDOWN); 67 | $result = $quill->render(); 68 | } catch (\Exception $e) { 69 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 70 | } 71 | 72 | $this->assertEquals( 73 | $this->expected_h2, 74 | trim($result), 75 | __METHOD__ . ' - Header 2 failure' 76 | ); 77 | } 78 | 79 | /** 80 | * Header 3 81 | * 82 | * @return void 83 | * @throws \Exception 84 | */ 85 | public function testHeader3() 86 | { 87 | $result = null; 88 | 89 | try { 90 | $quill = new QuillRender($this->delta_h3, Options::FORMAT_MARKDOWN); 91 | $result = $quill->render(); 92 | } catch (\Exception $e) { 93 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 94 | } 95 | 96 | $this->assertEquals( 97 | $this->expected_h3, 98 | trim($result), 99 | __METHOD__ . ' - Header 3 failure' 100 | ); 101 | } 102 | 103 | /** 104 | * Header 4 105 | * 106 | * @return void 107 | * @throws \Exception 108 | */ 109 | public function testHeader4() 110 | { 111 | $result = null; 112 | 113 | try { 114 | $quill = new QuillRender($this->delta_h4, Options::FORMAT_MARKDOWN); 115 | $result = $quill->render(); 116 | } catch (\Exception $e) { 117 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 118 | } 119 | 120 | $this->assertEquals( 121 | $this->expected_h4, 122 | trim($result), 123 | __METHOD__ . ' - Header 4 failure' 124 | ); 125 | } 126 | 127 | /** 128 | * Header 5 129 | * 130 | * @return void 131 | * @throws \Exception 132 | */ 133 | public function testHeader5() 134 | { 135 | $result = null; 136 | 137 | try { 138 | $quill = new QuillRender($this->delta_h5, Options::FORMAT_MARKDOWN); 139 | $result = $quill->render(); 140 | } catch (\Exception $e) { 141 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 142 | } 143 | 144 | $this->assertEquals( 145 | $this->expected_h5, 146 | trim($result), 147 | __METHOD__ . ' - Header 5 failure' 148 | ); 149 | } 150 | 151 | /** 152 | * Header 6 153 | * 154 | * @return void 155 | * @throws \Exception 156 | */ 157 | public function testHeader6() 158 | { 159 | $result = null; 160 | 161 | try { 162 | $quill = new QuillRender($this->delta_h6, Options::FORMAT_MARKDOWN); 163 | $result = $quill->render(); 164 | } catch (\Exception $e) { 165 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 166 | } 167 | 168 | $this->assertEquals( 169 | $this->expected_h6, 170 | trim($result), 171 | __METHOD__ . ' - Header 6 failure' 172 | ); 173 | } 174 | 175 | /** 176 | * Header 7 177 | * 178 | * @return void 179 | * @throws \Exception 180 | */ 181 | public function testHeader7() 182 | { 183 | $result = null; 184 | 185 | try { 186 | $quill = new QuillRender($this->delta_h7, Options::FORMAT_MARKDOWN); 187 | $result = $quill->render(); 188 | } catch (\Exception $e) { 189 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 190 | } 191 | 192 | $this->assertEquals( 193 | $this->expected_h7, 194 | trim($result), 195 | __METHOD__ . ' - Header 7 failure' 196 | ); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/HrefTest.php: -------------------------------------------------------------------------------- 1 | delta_href, OPTIONS::FORMAT_MARKDOWN); 33 | $result = $quill->render(); 34 | } catch (\Exception $e) { 35 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 36 | } 37 | 38 | $this->assertEquals( 39 | $this->expected_href, 40 | $result, 41 | __METHOD__ . ' Href failure' 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/ImageTest.php: -------------------------------------------------------------------------------- 1 | delta_image, OPTIONS::FORMAT_MARKDOWN); 31 | $result = $quill->render(); 32 | } catch (\Exception $e) { 33 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 34 | } 35 | 36 | $this->assertEquals( 37 | $this->expected_image, 38 | $result, 39 | __METHOD__ . ' Image failure' 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/ListTest.php: -------------------------------------------------------------------------------- 1 | delta_ordered, OPTIONS::FORMAT_MARKDOWN); 60 | $result = $quill->render(); 61 | } catch (\Exception $e) { 62 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 63 | } 64 | 65 | $this->assertEquals( 66 | $this->expected_ordered, 67 | $result, 68 | __METHOD__ . ' Ordered list failure' 69 | ); 70 | } 71 | 72 | /** 73 | * Unordered list 74 | * 75 | * @return void 76 | * @throws \Exception 77 | */ 78 | public function testListBullet() 79 | { 80 | $result = null; 81 | 82 | try { 83 | $quill = new QuillRender($this->delta_unordered, OPTIONS::FORMAT_MARKDOWN); 84 | $result = $quill->render(); 85 | } catch (\Exception $e) { 86 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 87 | } 88 | 89 | $this->assertEquals( 90 | $this->expected_unordered, 91 | $result, 92 | __METHOD__ . ' Unordered list failure' 93 | ); 94 | } 95 | 96 | /** 97 | * Unordered list 98 | * 99 | * @return void 100 | * @throws \Exception 101 | */ 102 | public function testListWithAttribute() 103 | { 104 | $result = null; 105 | 106 | try { 107 | $quill = new QuillRender($this->delta_list_with_attribute, OPTIONS::FORMAT_MARKDOWN); 108 | $result = $quill->render(); 109 | } catch (\Exception $e) { 110 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 111 | } 112 | 113 | $this->assertEquals($this->expected_list_with_attribute, trim($result), __METHOD__ . ' Unordered list failure'); 114 | } 115 | 116 | /** 117 | * Single item list, entire list item bold 118 | * 119 | * @return void 120 | * @throws \Exception 121 | */ 122 | public function testSingleListItemBold() 123 | { 124 | $result = null; 125 | 126 | try { 127 | $quill = new QuillRender($this->delta_single_item_list_bold, OPTIONS::FORMAT_MARKDOWN); 128 | $result = $quill->render(); 129 | } catch (\Exception $e) { 130 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 131 | } 132 | 133 | $this->assertEquals($this->expected_single_item_list_bold, trim($result), __METHOD__ . ' Single list item failure'); 134 | } 135 | 136 | /** 137 | * Single item list, entire list item italic 138 | * 139 | * @return void 140 | * @throws \Exception 141 | */ 142 | public function testSingleListItemItalic() 143 | { 144 | $result = null; 145 | 146 | try { 147 | $quill = new QuillRender($this->delta_single_item_list_italic, OPTIONS::FORMAT_MARKDOWN); 148 | $result = $quill->render(); 149 | } catch (\Exception $e) { 150 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 151 | } 152 | 153 | $this->assertEquals($this->expected_single_item_list_italic, trim($result), __METHOD__ . ' Single list item failure'); 154 | } 155 | 156 | /** 157 | * Single item list, entire list item a link 158 | * 159 | * @return void 160 | * @throws \Exception 161 | */ 162 | public function testSingleListItemLink() 163 | { 164 | $result = null; 165 | 166 | try { 167 | $quill = new QuillRender($this->delta_single_item_list_link, OPTIONS::FORMAT_MARKDOWN); 168 | $result = $quill->render(); 169 | } catch (\Exception $e) { 170 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 171 | } 172 | 173 | $this->assertEquals($this->expected_single_item_list_link, trim($result), __METHOD__ . ' Single list item failure'); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/TypographyTest.php: -------------------------------------------------------------------------------- 1 | delta_bold, OPTIONS::FORMAT_MARKDOWN); 37 | $result = $quill->render(); 38 | } catch (\Exception $e) { 39 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 40 | } 41 | 42 | $this->assertEquals( 43 | $this->expected_bold, 44 | $result, 45 | __METHOD__ . ' - Bold attribute failure' 46 | ); 47 | } 48 | 49 | /** 50 | * Test italic attribute 51 | * 52 | * @return void 53 | * @throws \Exception 54 | */ 55 | public function testItalic() 56 | { 57 | $result = null; 58 | 59 | try { 60 | $quill = new QuillRender($this->delta_italic, OPTIONS::FORMAT_MARKDOWN); 61 | $result = $quill->render(); 62 | } catch (\Exception $e) { 63 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 64 | } 65 | 66 | $this->assertEquals( 67 | $this->expected_italic, 68 | $result, 69 | __METHOD__ . ' - Italic attribute failure' 70 | ); 71 | } 72 | 73 | /** 74 | * Test a delta with a compound attribute 75 | * 76 | * @return void 77 | * @throws \Exception 78 | */ 79 | public function testCompoundAttribute() 80 | { 81 | $result = null; 82 | 83 | try { 84 | $quill = new QuillRender($this->delta_compound, OPTIONS::FORMAT_MARKDOWN); 85 | $result = $quill->render(); 86 | } catch (\Exception $e) { 87 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 88 | } 89 | 90 | $this->assertEquals( 91 | $this->expected_compound, 92 | $result, 93 | __METHOD__ . ' - Compound attribute failure' 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Tests/Attributes/Markdown/VideoTest.php: -------------------------------------------------------------------------------- 1 | delta_video, OPTIONS::FORMAT_MARKDOWN); 31 | $result = $quill->render(true); 32 | } catch (\Exception $e) { 33 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 34 | } 35 | 36 | $this->assertEquals( 37 | $this->expected_video, 38 | $result, 39 | __METHOD__ . ' Video failure' 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/Combined/GitHubMarkdown/BreaksTest.php: -------------------------------------------------------------------------------- 1 | delta_paragraphs_with_attributes, 83 | OPTIONS::FORMAT_GITHUB_MARKDOWN 84 | ); 85 | $result = $quill->render(); 86 | } catch (\Exception $e) { 87 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 88 | } 89 | 90 | $this->assertEquals( 91 | $this->expected_paragraphs_with_attributes, 92 | trim($result), 93 | __METHOD__ . ' - Paragraphs with attributes failure' 94 | ); 95 | } 96 | 97 | /** 98 | * Test a single paragraph 99 | * 100 | * @return void 101 | * @throws \Exception 102 | */ 103 | public function testSingleParagraph() 104 | { 105 | $result = null; 106 | 107 | try { 108 | $quill = new QuillRender( 109 | $this->delta_single_paragraph, 110 | OPTIONS::FORMAT_GITHUB_MARKDOWN 111 | ); 112 | $result = $quill->render(); 113 | } catch (\Exception $e) { 114 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 115 | } 116 | 117 | $this->assertEquals( 118 | $this->expected_single_paragraph, 119 | trim($result), 120 | __METHOD__ . ' - Single paragraph failure' 121 | ); 122 | } 123 | 124 | /** 125 | * Test two paragraphs 126 | * 127 | * @return void 128 | * @throws \Exception 129 | */ 130 | public function testTwoParagraphs() 131 | { 132 | $result = null; 133 | 134 | try { 135 | $quill = new QuillRender( 136 | $this->delta_two_paragraphs, 137 | OPTIONS::FORMAT_GITHUB_MARKDOWN 138 | ); 139 | $result = $quill->render(); 140 | } catch (\Exception $e) { 141 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 142 | } 143 | 144 | $this->assertEquals( 145 | $this->expected_two_paragraphs, 146 | trim($result), 147 | __METHOD__ . ' - Two paragraphs failure' 148 | ); 149 | } 150 | 151 | /** 152 | * Test three paragraphs 153 | * 154 | * @return void 155 | * @throws \Exception 156 | */ 157 | public function testThreeParagraphs() 158 | { 159 | $result = null; 160 | 161 | try { 162 | $quill = new QuillRender( 163 | $this->delta_three_paragraphs, 164 | OPTIONS::FORMAT_GITHUB_MARKDOWN 165 | ); 166 | $result = $quill->render(); 167 | } catch (\Exception $e) { 168 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 169 | } 170 | 171 | $this->assertEquals( 172 | $this->expected_three_paragraphs, 173 | trim($result), 174 | __METHOD__ . ' - Three paragraphs failure' 175 | ); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Tests/Combined/GitHubMarkdown/HeaderTest.php: -------------------------------------------------------------------------------- 1 | delta_header_then_text, 38 | OPTIONS::FORMAT_GITHUB_MARKDOWN 39 | ); 40 | $result = $quill->render(true); 41 | } catch (\Exception $e) { 42 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 43 | } 44 | 45 | $this->assertEquals( 46 | $this->expected_header_then_text, 47 | $result, 48 | __METHOD__ . ' - Header then text failure' 49 | ); 50 | } 51 | 52 | /** 53 | * Test a heading then text then another heading 54 | * 55 | * @return void 56 | * @throws \Exception 57 | */ 58 | public function testOutputHeadingTextThenHeading() 59 | { 60 | $result = null; 61 | 62 | try { 63 | $quill = new QuillRender( 64 | $this->delta_header_then_text_then_header, 65 | OPTIONS::FORMAT_GITHUB_MARKDOWN 66 | ); 67 | $result = $quill->render(true); 68 | } catch (\Exception $e) { 69 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 70 | } 71 | 72 | $this->assertEquals( 73 | $this->expected_header_then_text_then_header, 74 | $result, 75 | __METHOD__ . ' - Header then text then header failure' 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tests/Combined/GitHubMarkdown/ListTest.php: -------------------------------------------------------------------------------- 1 | delta_paragraph_then_list, 54 | OPTIONS::FORMAT_GITHUB_MARKDOWN 55 | ); 56 | $result = $quill->render(true); 57 | } catch (\Exception $e) { 58 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 59 | } 60 | 61 | $this->assertEquals( 62 | $this->expected_paragraph_then_list, 63 | trim($result), 64 | __METHOD__ . ' Paragraph then list failure' 65 | ); 66 | } 67 | 68 | /** 69 | * Test a paragraph followed by a list and then a final paragraph 70 | * 71 | * @return void 72 | * @throws \Exception 73 | */ 74 | public function testParagraphThenListTheParagraph() 75 | { 76 | $result = null; 77 | 78 | try { 79 | $quill = new QuillRender( 80 | $this->delta_paragraph_then_list_then_paragraph, 81 | OPTIONS::FORMAT_GITHUB_MARKDOWN 82 | ); 83 | $result = $quill->render(); 84 | } catch (\Exception $e) { 85 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 86 | } 87 | 88 | $this->assertEquals( 89 | $this->expected_paragraph_then_list_then_paragraph, 90 | trim($result), 91 | __METHOD__ . ' Paragraph then list then paragraph failure' 92 | ); 93 | } 94 | 95 | /** 96 | * Test a paragraph followed by a list and then a final paragraph, the final character in the list is bold 97 | * 98 | * @return void 99 | * @throws \Exception 100 | */ 101 | public function testParagraphThenListTheParagraphPlusBoldAttribute() 102 | { 103 | $result = null; 104 | 105 | try { 106 | $quill = new QuillRender( 107 | $this->delta_paragraph_then_list_then_paragraph_final_list_character_bold, 108 | OPTIONS::FORMAT_GITHUB_MARKDOWN 109 | ); 110 | $result = $quill->render(); 111 | } catch (\Exception $e) { 112 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 113 | } 114 | 115 | $this->assertEquals( 116 | $this->expected_paragraph_then_list_then_paragraph_final_list_character_bold, 117 | trim($result), 118 | __METHOD__ . ' Paragraph then list then paragraph failure' 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Tests/Combined/Html/BoldColorTest.php: -------------------------------------------------------------------------------- 1 | My Text

'; 14 | 15 | public function testBoldColor() 16 | { 17 | $result = null; 18 | 19 | try { 20 | $quill = new QuillRender($this->delta_bold_text); 21 | $result = $quill->render(); 22 | } catch (\Exception $e) { 23 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 24 | } 25 | 26 | $this->assertEquals($this->expected_href, trim($result), __METHOD__ . ' BoldColorText'); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /Tests/Combined/Html/BreaksTest.php: -------------------------------------------------------------------------------- 1 | This is a three paragraph test 29 | 30 |

31 |

the difference being this time we 32 | 33 |

34 |

are going to add attributes.

"; 35 | private $expected_single_paragraph = '

Lorem ipsum dolor sit amet

'; 36 | private $expected_two_paragraphs = '

Lorem ipsum dolor sit amet. 37 | 38 |

39 |

Lorem ipsum dolor sit amet.

'; 40 | private $expected_three_paragraphs = '

This is a single entry that 41 | 42 |

43 |

should create three paragraphs 44 | 45 |

46 |

of HTML. 47 |
48 |

'; 49 | private $expected_line_breaks = "

Line 1, should have a BR 50 |
51 | Line 2, should have a BR 52 |
53 | Line 3 54 |
55 |

"; 56 | private $expected_paragraph_then_line_breaks = "

Paragraph 57 | 58 |

59 |

Line 1, should have a BR 60 |
61 | Line 2, should have a BR 62 |
63 | Line 3 64 |
65 |

"; 66 | 67 | /** 68 | * Test paragraphs with attributes 69 | * 70 | * @return void 71 | * @throws \Exception 72 | */ 73 | public function testParagraphWithAttributes() 74 | { 75 | $result = null; 76 | 77 | try { 78 | $quill = new QuillRender($this->delta_paragraphs_with_attributes); 79 | $result = $quill->render(); 80 | } catch (\Exception $e) { 81 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 82 | } 83 | 84 | $this->assertEquals( 85 | $this->expected_paragraphs_with_attributes, 86 | trim($result), 87 | __METHOD__ . ' - Paragraphs with attributes failure' 88 | ); 89 | } 90 | 91 | /** 92 | * Test a single paragraph 93 | * 94 | * @return void 95 | * @throws \Exception 96 | */ 97 | public function testSingleParagraph() 98 | { 99 | $result = null; 100 | 101 | try { 102 | $quill = new QuillRender($this->delta_single_paragraph); 103 | $result = $quill->render(); 104 | } catch (\Exception $e) { 105 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 106 | } 107 | 108 | $this->assertEquals( 109 | $this->expected_single_paragraph, 110 | trim($result), 111 | __METHOD__ . ' - Single paragraph failure' 112 | ); 113 | } 114 | 115 | /** 116 | * Test two paragraphs 117 | * 118 | * @return void 119 | * @throws \Exception 120 | */ 121 | public function testTwoParagraphs() 122 | { 123 | $result = null; 124 | 125 | try { 126 | $quill = new QuillRender($this->delta_two_paragraphs); 127 | $result = $quill->render(); 128 | } catch (\Exception $e) { 129 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 130 | } 131 | 132 | $this->assertEquals( 133 | $this->expected_two_paragraphs, 134 | trim($result), 135 | __METHOD__ . ' - Two paragraphs failure' 136 | ); 137 | } 138 | 139 | /** 140 | * Test three paragraphs 141 | * 142 | * @return void 143 | * @throws \Exception 144 | */ 145 | public function testThreeParagraphs() 146 | { 147 | $result = null; 148 | 149 | try { 150 | $quill = new QuillRender($this->delta_three_paragraphs); 151 | $result = $quill->render(); 152 | } catch (\Exception $e) { 153 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 154 | } 155 | 156 | $this->assertEquals( 157 | $this->expected_three_paragraphs, 158 | trim($result), 159 | __METHOD__ . ' - Three paragraphs failure' 160 | ); 161 | } 162 | 163 | /** 164 | * test two lines breaks inside a paragraph, no other attributes 165 | * 166 | * @return void 167 | * @throws \Exception 168 | */ 169 | public function testTwoLineBreaksInAParagraph() 170 | { 171 | $result = null; 172 | 173 | try { 174 | $quill = new QuillRender($this->delta_line_breaks); 175 | $result = $quill->render(); 176 | } catch (\Exception $e) { 177 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 178 | } 179 | 180 | $this->assertEquals( 181 | $this->expected_line_breaks, 182 | trim($result), 183 | __METHOD__ . ' - Lines breaks in a simple paragraph, failure' 184 | ); 185 | } 186 | 187 | /** 188 | * Test two lines breaks inside a paragraph, following a paragraph, no other attributes 189 | * 190 | * @return void 191 | * @throws \Exception 192 | */ 193 | public function testParagraphThenTwoLineBreaksInAParagraphFollowingParagraph() 194 | { 195 | $result = null; 196 | 197 | try { 198 | $quill = new QuillRender($this->delta_paragraph_then_line_breaks); 199 | $result = $quill->render(); 200 | } catch (\Exception $e) { 201 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 202 | } 203 | 204 | $this->assertEquals( 205 | $this->expected_paragraph_then_line_breaks, 206 | trim($result), 207 | __METHOD__ . ' - Lines breaks in a simple paragraph, following a paragraph, failure' 208 | ); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Tests/Combined/Html/HeaderTest.php: -------------------------------------------------------------------------------- 1 | This is a heading 18 |

19 |
20 | Now some normal text. 21 |
22 |

'; 23 | private $expected_header_then_text_then_header = '

This is a heading

24 |

25 |
26 | Now some normal text. 27 | 28 |

29 |

Now another heading

'; 30 | 31 | /** 32 | * Test a heading then plain text 33 | * 34 | * @return void 35 | * @throws \Exception 36 | */ 37 | public function testOutputHeadingThenText() 38 | { 39 | $result = null; 40 | 41 | try { 42 | $quill = new QuillRender($this->delta_header_then_text); 43 | $result = $quill->render(); 44 | } catch (\Exception $e) { 45 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 46 | } 47 | 48 | $this->assertEquals($this->expected_header_then_text, trim($result), __METHOD__ . ' - Header then text failure'); 49 | } 50 | 51 | /** 52 | * Test a heading then text then another heading 53 | * 54 | * @return void 55 | * @throws \Exception 56 | */ 57 | public function testOutputHeadingTextThenHeading() 58 | { 59 | $result = null; 60 | 61 | try { 62 | $quill = new QuillRender($this->delta_header_then_text_then_header); 63 | $result = $quill->render(); 64 | } catch (\Exception $e) { 65 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 66 | } 67 | 68 | $this->assertEquals($this->expected_header_then_text_then_header, trim($result), 69 | __METHOD__ . ' - Header then text then header failure'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Tests/Combined/Html/ListTest.php: -------------------------------------------------------------------------------- 1 | This is a single line of text. 21 |
22 |

23 |
    24 |
  • Bullet 1
  • 25 |
  • Bullet 2
  • 26 |
  • Bullet 3
  • 27 |
'; 28 | 29 | private string $expected_paragraph_then_list_then_paragraph = '

This is a paragraph. 30 | 31 |

32 |
    33 |
  • List item 1
  • 34 |
  • List item 2
  • 35 |
  • List item 3
  • 36 |
37 |

38 |
39 | This is another paragraph 40 |
41 |

'; 42 | 43 | private string $expected_paragraph_then_list_then_paragraph_final_list_character_bold = '

This is a paragraph. 44 | 45 |

46 |
    47 |
  1. List item 1
  2. 48 |
  3. List item 2
  4. 49 |
  5. List item 3
  6. 50 |
51 |

52 |
53 | This is another paragraph. 54 |
55 |

'; 56 | 57 | private string $expected_paragraph_then_single_item_list = '

Normal paragraph 58 | 59 |

60 |
    61 |
  • List with a single item
  • 62 |
63 |

64 |
65 | Another normal paragraph 66 |
67 |

'; 68 | 69 | public function testParagraphThenList(): void 70 | { 71 | $result = null; 72 | 73 | try { 74 | $quill = new QuillRender($this->delta_paragraph_then_list); 75 | $result = $quill->render(); 76 | } catch (\Exception $e) { 77 | self::fail(__METHOD__ . 'failure, ' . $e->getMessage()); 78 | } 79 | 80 | self::assertEquals( 81 | $this->expected_paragraph_then_list, 82 | trim($result), 83 | __METHOD__ . ' Paragraph then list failure' 84 | ); 85 | } 86 | 87 | public function testParagraphThenSingleItemList(): void 88 | { 89 | $result = null; 90 | 91 | try { 92 | $quill = new QuillRender($this->delta_paragraph_then_single_item_list); 93 | $result = $quill->render(); 94 | } catch (\Exception $e) { 95 | self::fail(__METHOD__ . 'failure, ' . $e->getMessage()); 96 | } 97 | 98 | self::assertEquals( 99 | $this->expected_paragraph_then_single_item_list, 100 | trim($result), 101 | __METHOD__ . ' Paragraph then single item list failure' 102 | ); 103 | } 104 | 105 | public function testParagraphThenListTheParagraph(): void 106 | { 107 | $result = null; 108 | 109 | try { 110 | $quill = new QuillRender($this->delta_paragraph_then_list_then_paragraph); 111 | $result = $quill->render(); 112 | } catch (\Exception $e) { 113 | self::fail(__METHOD__ . 'failure, ' . $e->getMessage()); 114 | } 115 | 116 | self::assertEquals( 117 | $this->expected_paragraph_then_list_then_paragraph, 118 | trim($result), 119 | __METHOD__ . ' Paragraph then list then paragraph failure' 120 | ); 121 | } 122 | 123 | public function testParagraphThenListTheParagraphPlusBoldAttribute(): void 124 | { 125 | $result = null; 126 | 127 | try { 128 | $quill = new QuillRender($this->delta_paragraph_then_list_then_paragraph_final_list_character_bold); 129 | $result = $quill->render(); 130 | } catch (\Exception $e) { 131 | self::fail(__METHOD__ . 'failure, ' . $e->getMessage()); 132 | } 133 | 134 | self::assertEquals( 135 | $this->expected_paragraph_then_list_then_paragraph_final_list_character_bold, 136 | trim($result), 137 | __METHOD__ . ' Paragraph then list then paragraph failure' 138 | ); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Tests/Combined/Markdown/BreaksTest.php: -------------------------------------------------------------------------------- 1 | delta_paragraphs_with_attributes, 48 | OPTIONS::FORMAT_MARKDOWN 49 | ); 50 | $result = $quill->render(); 51 | } catch (\Exception $e) { 52 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 53 | } 54 | 55 | $this->assertEquals( 56 | $this->expected_paragraphs_with_attributes, 57 | trim($result), 58 | __METHOD__ . ' - Paragraphs with attributes failure' 59 | ); 60 | } 61 | 62 | /** 63 | * Test a single paragraph 64 | * 65 | * @return void 66 | * @throws \Exception 67 | */ 68 | public function testSingleParagraph() 69 | { 70 | $result = null; 71 | 72 | try { 73 | $quill = new QuillRender( 74 | $this->delta_single_paragraph, 75 | OPTIONS::FORMAT_MARKDOWN 76 | ); 77 | $result = $quill->render(); 78 | } catch (\Exception $e) { 79 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 80 | } 81 | 82 | $this->assertEquals( 83 | $this->expected_single_paragraph, 84 | trim($result), 85 | __METHOD__ . ' - Single paragraph failure' 86 | ); 87 | } 88 | 89 | /** 90 | * Test two paragraphs 91 | * 92 | * @return void 93 | * @throws \Exception 94 | */ 95 | public function testTwoParagraphs() 96 | { 97 | $result = null; 98 | 99 | try { 100 | $quill = new QuillRender( 101 | $this->delta_two_paragraphs, 102 | OPTIONS::FORMAT_MARKDOWN 103 | ); 104 | $result = $quill->render(); 105 | } catch (\Exception $e) { 106 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 107 | } 108 | 109 | $this->assertEquals( 110 | $this->expected_two_paragraphs, 111 | trim($result), 112 | __METHOD__ . ' - Two paragraphs failure' 113 | ); 114 | } 115 | 116 | /** 117 | * Test three paragraphs 118 | * 119 | * @return void 120 | * @throws \Exception 121 | */ 122 | public function testThreeParagraphs() 123 | { 124 | $result = null; 125 | 126 | try { 127 | $quill = new QuillRender( 128 | $this->delta_three_paragraphs, 129 | OPTIONS::FORMAT_MARKDOWN 130 | ); 131 | $result = $quill->render(); 132 | } catch (\Exception $e) { 133 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 134 | } 135 | 136 | $this->assertEquals( 137 | $this->expected_three_paragraphs, 138 | trim($result), 139 | __METHOD__ . ' - Three paragraphs failure' 140 | ); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Tests/Combined/Markdown/HeaderTest.php: -------------------------------------------------------------------------------- 1 | delta_header_then_text, 38 | OPTIONS::FORMAT_MARKDOWN 39 | ); 40 | $result = $quill->render(true); 41 | } catch (\Exception $e) { 42 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 43 | } 44 | 45 | $this->assertEquals( 46 | $this->expected_header_then_text, 47 | $result, 48 | __METHOD__ . ' - Header then text failure' 49 | ); 50 | } 51 | 52 | /** 53 | * Test a heading then text then another heading 54 | * 55 | * @return void 56 | * @throws \Exception 57 | */ 58 | public function testOutputHeadingTextThenHeading() 59 | { 60 | $result = null; 61 | 62 | try { 63 | $quill = new QuillRender( 64 | $this->delta_header_then_text_then_header, 65 | OPTIONS::FORMAT_MARKDOWN 66 | ); 67 | $result = $quill->render(true); 68 | } catch (\Exception $e) { 69 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 70 | } 71 | 72 | $this->assertEquals( 73 | $this->expected_header_then_text_then_header, 74 | $result, 75 | __METHOD__ . ' - Header then text then header failure' 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tests/Combined/Markdown/ListTest.php: -------------------------------------------------------------------------------- 1 | delta_paragraph_then_list, 54 | OPTIONS::FORMAT_MARKDOWN 55 | ); 56 | $result = $quill->render(true); 57 | } catch (\Exception $e) { 58 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 59 | } 60 | 61 | $this->assertEquals( 62 | $this->expected_paragraph_then_list, 63 | trim($result), 64 | __METHOD__ . ' Paragraph then list failure' 65 | ); 66 | } 67 | 68 | /** 69 | * Test a paragraph followed by a list and then a final paragraph 70 | * 71 | * @return void 72 | * @throws \Exception 73 | */ 74 | public function testParagraphThenListTheParagraph() 75 | { 76 | $result = null; 77 | 78 | try { 79 | $quill = new QuillRender( 80 | $this->delta_paragraph_then_list_then_paragraph, 81 | OPTIONS::FORMAT_MARKDOWN 82 | ); 83 | $result = $quill->render(); 84 | } catch (\Exception $e) { 85 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 86 | } 87 | 88 | $this->assertEquals( 89 | $this->expected_paragraph_then_list_then_paragraph, 90 | trim($result), 91 | __METHOD__ . ' Paragraph then list then paragraph failure' 92 | ); 93 | } 94 | 95 | /** 96 | * Test a paragraph followed by a list and then a final paragraph, the final character in the list is bold 97 | * 98 | * @return void 99 | * @throws \Exception 100 | */ 101 | public function testParagraphThenListTheParagraphPlusBoldAttribute() 102 | { 103 | $result = null; 104 | 105 | try { 106 | $quill = new QuillRender( 107 | $this->delta_paragraph_then_list_then_paragraph_final_list_character_bold, 108 | OPTIONS::FORMAT_MARKDOWN 109 | ); 110 | $result = $quill->render(); 111 | } catch (\Exception $e) { 112 | $this->fail(__METHOD__ . 'failure, ' . $e->getMessage()); 113 | } 114 | 115 | $this->assertEquals( 116 | $this->expected_paragraph_then_list_then_paragraph_final_list_character_bold, 117 | trim($result), 118 | __METHOD__ . ' Paragraph then list then paragraph failure' 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deanblackborough/php-quill-renderer", 3 | "description": "Render quill insert deltas to HTML, Markdown and GitHub flavoured Markdown", 4 | "autoload": { 5 | "psr-4" : { 6 | "DBlackborough\\Quill\\" : "src/" 7 | } 8 | }, 9 | "autoload-dev": { 10 | "psr-4": { 11 | "Tests\\": "Tests/" 12 | } 13 | }, 14 | "homepage": "http://www.transmute-coffee.com/php-quill-renderer.php", 15 | "keywords": [ "quill", "quilljs", "renderer", "delta", "parse", "html", "php", "markdown"], 16 | "authors": [ 17 | { 18 | "name": "Dean Blackborough", 19 | "email": "dean@g3d-development.com" 20 | } 21 | ], 22 | "require": { 23 | "php": "^7.4|^8.0|^8.1", 24 | "ext-json": "*" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "^9" 28 | }, 29 | "suggest": { 30 | "php": "^8.0" 31 | }, 32 | "scripts": { 33 | "test": "phpunit" 34 | }, 35 | "repositories": [ 36 | { 37 | "type": "vcs", 38 | "url": "https://github.com/deanblackborough/php-quill-renderer" 39 | } 40 | ], 41 | "license": "MIT" 42 | } 43 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src/ 6 | 7 | 8 | 9 | 10 | Tests/ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Delta/Delta.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | abstract class Delta implements DeltaInterface 17 | { 18 | /** 19 | * @var array The attributes array 20 | */ 21 | protected $attributes; 22 | 23 | /** 24 | * @var string The insert string 25 | */ 26 | protected $insert; 27 | 28 | /** 29 | * @var boolean $is_first_child Is the delta the first child? 30 | */ 31 | protected $is_first_child = false; 32 | 33 | /** 34 | * @var boolean $is_last_child Id the delta the last child? 35 | */ 36 | protected $is_last_child = false; 37 | 38 | /** 39 | * @var Delta[] $children Child delta objects 40 | */ 41 | protected $children = []; 42 | 43 | /** 44 | * Add a child delta 45 | * 46 | * @param Delta $delta 47 | * 48 | * @return void 49 | */ 50 | public function addChild(Delta $delta): void 51 | { 52 | $this->children[] = $delta; 53 | } 54 | 55 | /** 56 | * Return the child deltas 57 | * 58 | * @return Delta[] 59 | */ 60 | public function children(): array 61 | { 62 | return array_reverse($this->children); 63 | } 64 | 65 | /** 66 | * Does the delta have any children 67 | * 68 | * @return boolean 69 | */ 70 | public function hasChildren(): bool 71 | { 72 | if (count($this->children) > 0) { 73 | return true; 74 | } else { 75 | return false; 76 | } 77 | } 78 | 79 | /** 80 | * Does the delta have any attributes 81 | * 82 | * @return boolean 83 | */ 84 | public function hasAttributes(): bool 85 | { 86 | if (count($this->attributes) > 0) { 87 | return true; 88 | } else { 89 | return false; 90 | } 91 | } 92 | 93 | /** 94 | * Is the delta a child? 95 | * 96 | * @return boolean 97 | */ 98 | public function isChild(): bool 99 | { 100 | return false; 101 | } 102 | 103 | /** 104 | * If the delta is a child, is it the first child? 105 | * 106 | * @return boolean 107 | */ 108 | public function isFirstChild(): bool 109 | { 110 | return $this->is_first_child; 111 | } 112 | 113 | /** 114 | * If the delta is a child, is it the last child? 115 | * 116 | * @return boolean 117 | */ 118 | public function isLastChild(): bool 119 | { 120 | return $this->is_last_child; 121 | } 122 | 123 | /** 124 | * Return the attributes for the delta 125 | * 126 | * @return array 127 | */ 128 | public function getAttributes(): array 129 | { 130 | return $this->attributes; 131 | } 132 | 133 | /** 134 | * Return the plain insert string prior to any parsing 135 | * 136 | * @return string 137 | */ 138 | public function getInsert(): string 139 | { 140 | return $this->insert; 141 | } 142 | 143 | /** 144 | * Render and return the string for the insert ready for the relevant 145 | * renderer 146 | * 147 | * @return string 148 | */ 149 | abstract public function render(): string; 150 | 151 | /** 152 | * Set the current delta to be the first child, alternatively, 153 | * set to false by passing false and clear the value 154 | * 155 | * @var boolean $value Set the value of $this->is_first_child, defaults to true 156 | * 157 | * @return Delta 158 | */ 159 | public function setFirstChild(bool $value = true): Delta 160 | { 161 | $this->is_first_child = $value; 162 | 163 | return $this; 164 | } 165 | 166 | /** 167 | * Set the current delta to be the last child, alternatively, 168 | * set to false by passing false and clear the value 169 | * 170 | * @var boolean $value Set the value of $this->is_last_child, defaults to true 171 | * 172 | * @return Delta 173 | */ 174 | public function setLastChild(bool $value = true): Delta 175 | { 176 | $this->is_last_child = $value; 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * Set the insert string 183 | * 184 | * @param string $insert 185 | */ 186 | public function setInsert(string $insert) 187 | { 188 | $this->insert = $insert; 189 | } 190 | 191 | /** 192 | * Escape the given insert string 193 | * 194 | * @param string $insert Insert string to escape 195 | * 196 | * @return string 197 | */ 198 | abstract protected function escape(string $insert): string; 199 | } 200 | -------------------------------------------------------------------------------- /src/Delta/GithubMarkdown/Delta.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | abstract class Delta extends MarkdownDelta 17 | { 18 | /** 19 | * Escape the given insert string 20 | * 21 | * @param string $insert Insert string to escape 22 | * 23 | * @return string 24 | */ 25 | protected function escape(string $insert): string 26 | { 27 | return str_replace(['*', '#', '~'], ['\*', '\#', '\~'], $insert); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Delta/GithubMarkdown/Strike.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Strike extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->token = Options::GITHUB_MARKDOWN_TOKEN_STRIKE; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->token . $this->escape($this->insert) . $this->token; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/Bold.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Bold extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_BOLD; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/Color.php: -------------------------------------------------------------------------------- 1 | insert = $insert; 21 | $this->attributes = $attributes; 22 | 23 | $this->tag = 'span'; 24 | } 25 | 26 | /** 27 | * Render the HTML for the specific Delta type 28 | * 29 | * @return string 30 | */ 31 | public function render(): string 32 | { 33 | return "<{$this->tag} style=\"color: {$this->attributes['color']};\">{$this->escape($this->insert)}tag}>"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Delta/Html/Compound.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright Dean Blackborough 15 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 16 | */ 17 | class Compound extends Delta 18 | { 19 | /** 20 | * @var array Array of HTML tags 21 | */ 22 | private $tags; 23 | 24 | /** 25 | * @var array An array of element attributes 26 | */ 27 | private $element_attributes; 28 | 29 | /** 30 | * @var string The generated HTML fragment 31 | */ 32 | private $html; 33 | 34 | /** 35 | * @var boolean Contains a link attribute 36 | */ 37 | private $isLink = false; 38 | 39 | /** 40 | * @var string The link 41 | */ 42 | private $link = null; 43 | 44 | /** 45 | * Set the insert for the compound delta insert 46 | * 47 | * @param string $insert 48 | */ 49 | public function __construct(string $insert) 50 | { 51 | $this->insert = $insert; 52 | 53 | $this->tags = []; 54 | $this->element_attributes = []; 55 | $this->html = ''; 56 | } 57 | 58 | /** 59 | * Tags 60 | */ 61 | private function tags(): void 62 | { 63 | foreach ($this->attributes as $attribute => $value) { 64 | switch ($attribute) { 65 | case Options::ATTRIBUTE_BOLD: 66 | $this->tags[] = Options::HTML_TAG_BOLD; 67 | break; 68 | 69 | case Options::ATTRIBUTE_ITALIC: 70 | $this->tags[] = Options::HTML_TAG_ITALIC; 71 | break; 72 | 73 | case Options::ATTRIBUTE_SCRIPT: 74 | $this->tags[] = $value; 75 | break; 76 | 77 | case Options::ATTRIBUTE_STRIKE: 78 | $this->tags[] = Options::HTML_TAG_STRIKE; 79 | break; 80 | 81 | case Options::ATTRIBUTE_UNDERLINE: 82 | $this->tags[] = Options::HTML_TAG_UNDERLINE; 83 | break; 84 | 85 | default: 86 | if (in_array($attribute, Settings::ignoredCustomAttributes()) === false) { 87 | $this->element_attributes[$attribute] = $value; 88 | } 89 | break; 90 | } 91 | } 92 | } 93 | 94 | /** 95 | * Pass in an attribute value for conversion 96 | * 97 | * @param string $attribute Attribute name 98 | * @param string $value Attribute value to assign 99 | * 100 | * @return Compound 101 | */ 102 | public function setAttribute($attribute, $value): Compound 103 | { 104 | if ($attribute !== 'link') { 105 | $this->attributes[$attribute] = $value; 106 | } else { 107 | $this->isLink = true; 108 | $this->link = $value; 109 | } 110 | 111 | return $this; 112 | } 113 | 114 | /** 115 | * Render the Html for the specific Delta type 116 | * 117 | * @return string 118 | */ 119 | public function render(): string 120 | { 121 | $this->tags(); 122 | 123 | if ($this->isLink === true) { 124 | $this->html .= "
link}\">"; 125 | } 126 | 127 | $element_attributes = ''; 128 | foreach ($this->element_attributes as $attribute => $value) { 129 | if (is_string($attribute) && is_string($value)) { 130 | if ($attribute == "color") { 131 | $element_attributes .= "style=\"{$attribute}: $value\""; 132 | } else { 133 | $element_attributes .= "{$attribute}=\"{$value}\" "; 134 | } 135 | } 136 | } 137 | 138 | foreach ($this->tags as $i => $tag) { 139 | if ($i === 0 && strlen($element_attributes) > 0) { 140 | $this->html .= "<{$tag} " . rtrim($element_attributes) . '>'; 141 | } else { 142 | $this->html .= "<{$tag}>"; 143 | } 144 | } 145 | 146 | $this->html .= $this->escape($this->insert); 147 | 148 | foreach (array_reverse($this->tags) as $tag) { 149 | $this->html .= ""; 150 | } 151 | 152 | if ($this->isLink === true) { 153 | $this->html .= ''; 154 | } 155 | 156 | return $this->html; 157 | } 158 | 159 | /** 160 | * Override the method to include the link in the attributes array if 161 | * necessary as it will have be striped 162 | * 163 | * @return array 164 | */ 165 | public function getAttributes(): array 166 | { 167 | if ($this->isLink === false) { 168 | return $this->attributes; 169 | } else { 170 | return array_merge( 171 | ['link' => $this->link], 172 | $this->attributes 173 | ); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/Delta/Html/CompoundImage.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class CompoundImage extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | */ 23 | public function __construct(string $insert) 24 | { 25 | $this->insert = $insert; 26 | } 27 | 28 | /** 29 | * Pass in an attribute value for conversion 30 | * 31 | * @param string $attribute Attribute name 32 | * @param string $value Attribute value to assign 33 | * 34 | * @return CompoundImage 35 | */ 36 | public function setAttribute($attribute, $value): CompoundImage 37 | { 38 | $this->attributes[$attribute] = $value; 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * Render the HTML for the specific Delta type 45 | * 46 | * @return string 47 | */ 48 | public function render(): string 49 | { 50 | $image_attributes = ''; 51 | foreach ($this->attributes as $attribute => $value) { 52 | if ( 53 | is_string($attribute) && 54 | is_string($value) && 55 | in_array($attribute, Settings::ignoredCustomAttributes()) === false 56 | ) { 57 | $image_attributes .= "{$attribute}=\"{$value}\" "; 58 | } 59 | } 60 | return "insert}\" {$image_attributes}/>"; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Delta/Html/CompoundVideo.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class CompoundVideo extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | */ 23 | public function __construct(string $insert) 24 | { 25 | $this->insert = $insert; 26 | } 27 | 28 | /** 29 | * Pass in an attribute value for conversion 30 | * 31 | * @param string $attribute Attribute name 32 | * @param string $value Attribute value to assign 33 | * 34 | * @return CompoundVideo 35 | */ 36 | public function setAttribute($attribute, $value): CompoundVideo 37 | { 38 | $this->attributes[$attribute] = $value; 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * Render the HTML for the specific Delta type 45 | * 46 | * @return string 47 | */ 48 | public function render(): string 49 | { 50 | $video_attributes = ''; 51 | foreach ($this->attributes as $attribute => $value) { 52 | if ( 53 | is_string($attribute) && 54 | is_string($value) && 55 | in_array($attribute, Settings::ignoredCustomAttributes()) === false 56 | ) { 57 | $video_attributes .= "{$attribute}=\"{$value}\" "; 58 | } 59 | } 60 | return ''; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Delta/Html/Delta.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | abstract class Delta extends BaseDelta 17 | { 18 | public CONST DISPLAY_BLOCK = 'block'; 19 | public CONST DISPLAY_INLINE = 'inline'; 20 | 21 | private $pre_new_line = false; 22 | 23 | /** 24 | * @var string|null The HTML tag for the delta when rendered as HTML 25 | */ 26 | protected $tag; 27 | 28 | /** 29 | * @var boolean $close 30 | */ 31 | protected $close = false; 32 | 33 | /** 34 | * @var boolean $new_line 35 | */ 36 | protected $new_line = false; 37 | 38 | /** 39 | * Should we close the block 40 | * 41 | * @return boolean 42 | */ 43 | public function close(): bool 44 | { 45 | return $this->close; 46 | } 47 | 48 | /** 49 | * Return the display type for the resultant HTML created by the delta, either inline or block, defaults to 50 | * inline block 51 | * 52 | * @return string 53 | */ 54 | public function displayType(): string 55 | { 56 | return self::DISPLAY_INLINE; 57 | } 58 | 59 | /** 60 | * Return whether or not a new line needs to be added 61 | * 62 | * @return boolean 63 | */ 64 | public function newLine(): bool 65 | { 66 | return $this->new_line; 67 | } 68 | 69 | /** 70 | * If the delta is a child, what type of tag is the parent 71 | * 72 | * @return string|null 73 | */ 74 | public function parentTag(): ?string 75 | { 76 | return null; 77 | } 78 | 79 | /** 80 | * Return whether or not a pre new line needs to be added 81 | * 82 | * @return boolean 83 | */ 84 | public function preNewLine(): bool 85 | { 86 | return $this->pre_new_line; 87 | } 88 | 89 | /** 90 | * Set the close attribute 91 | * 92 | * @return void 93 | */ 94 | public function setClose() 95 | { 96 | $this->close = true; 97 | } 98 | 99 | /** 100 | * Set the new line state 101 | * 102 | * @var boolean $value Set the value of $this->new_line, defaults to true 103 | * 104 | * @return Delta 105 | */ 106 | public function setNewLine(bool $value = true): Delta 107 | { 108 | $this->new_line = $value; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * Set the pre new line state 115 | * 116 | * @var boolean $value Set the value of $this->pre_new_line, defaults to true 117 | * 118 | * @return Delta 119 | */ 120 | public function setPreNewLine(bool $value = true): Delta 121 | { 122 | $this->pre_new_line = $value; 123 | 124 | return $this; 125 | } 126 | 127 | /** 128 | * Generate the HTML fragment for a simple insert replacement 129 | * 130 | * @param string $tag HTML tag to wrap around insert 131 | * @param string $insert Insert for tag 132 | * @param boolean $new_line Append a new line 133 | * 134 | * @return string 135 | */ 136 | protected function renderSimpleTag($tag, $insert, $new_line = false): string 137 | { 138 | return "<{$tag}>{$insert}" . ($new_line === true ? "\n" : null); 139 | } 140 | 141 | /** 142 | * Escape the given insert string 143 | * 144 | * @param string $insert Insert string to escape 145 | * 146 | * @return string 147 | */ 148 | protected function escape(string $insert): string 149 | { 150 | return htmlspecialchars($insert, ENT_COMPAT, 'UTF-8'); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Delta/Html/Header.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Header extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | 29 | $this->tag = Options::HTML_TAG_HEADER . $this->attributes['header']; 30 | } 31 | 32 | /** 33 | * Return the display type for the resultant HTML created by the delta, either inline or block 34 | * 35 | * @return string 36 | */ 37 | public function displayType(): string 38 | { 39 | return parent::DISPLAY_BLOCK; 40 | } 41 | 42 | /** 43 | * Render the HTML for the specific Delta type 44 | * 45 | * @return string 46 | */ 47 | public function render(): string 48 | { 49 | $html = "<{$this->tag}>"; 50 | if ($this->hasChildren() === true) { 51 | 52 | foreach ($this->children() as $child) { 53 | $html .= $child->render(); 54 | } 55 | } 56 | $html .= "{$this->escape($this->insert)}tag}>\n"; 57 | 58 | return $html; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Delta/Html/Image.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Image extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->tag = null; 25 | 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | } 29 | 30 | /** 31 | * Render the HTML for the specific Delta type 32 | * 33 | * @return string 34 | */ 35 | public function render(): string 36 | { 37 | return "escape($this->insert)}\" />"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Delta/Html/Insert.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Insert extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = null; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | $html = ''; 40 | 41 | $add_span = false; 42 | if (count($this->attributes) > 0) { 43 | $add_span = true; 44 | } 45 | 46 | if ($this->preNewLine() === true) { 47 | $html .= "
\n"; 48 | } 49 | 50 | if ($add_span === false) { 51 | $html .= $this->escape($this->insert); 52 | } else { 53 | $html .= 'attributes as $attribute => $value) { 55 | if ( 56 | is_string($attribute) && 57 | is_string($value) && 58 | in_array($attribute, Settings::ignoredCustomAttributes()) === false 59 | ) { 60 | $html .= " {$attribute}=\"{$value}\""; 61 | } 62 | } 63 | $html .= ">{$this->escape($this->insert)}"; 64 | } 65 | 66 | if ($this->newLine() === true) { 67 | $html .= "
\n"; 68 | } 69 | 70 | return $html; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Delta/Html/Italic.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Italic extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_ITALIC; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/Link.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Link extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->insert = $insert; 25 | $this->attributes = $attributes; 26 | 27 | $this->tag = 'a'; 28 | } 29 | 30 | /** 31 | * Render the HTML for the specific Delta type 32 | * 33 | * @return string 34 | */ 35 | public function render(): string 36 | { 37 | return "<{$this->tag} href=\"{$this->attributes['link']}\">{$this->escape($this->insert)}tag}>"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Delta/Html/ListItem.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class ListItem extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | 29 | $this->tag = Options::HTML_TAG_LIST_ITEM; 30 | } 31 | 32 | /** 33 | * Return the display type for the resultant HTML created by the delta, either inline or block 34 | * 35 | * @return string 36 | */ 37 | public function displayType(): string 38 | { 39 | return parent::DISPLAY_BLOCK; 40 | } 41 | 42 | /** 43 | * Is the delta a child? 44 | * 45 | * @return boolean 46 | */ 47 | public function isChild(): bool 48 | { 49 | return true; 50 | } 51 | 52 | /** 53 | * If the delta is a child, what type of tag is the parent 54 | * 55 | * @return string|null 56 | */ 57 | public function parentTag(): ?string 58 | { 59 | switch ($this->attributes['list']) { 60 | case Options::ATTRIBUTE_LIST_ORDERED: 61 | return Options::HTML_TAG_LIST_ORDERED; 62 | break; 63 | case Options::ATTRIBUTE_LIST_BULLET: 64 | return Options::HTML_TAG_LIST_UNORDERED; 65 | break; 66 | 67 | default: 68 | return Options::HTML_TAG_LIST_UNORDERED; 69 | break; 70 | } 71 | } 72 | 73 | /** 74 | * Render the HTML for the specific Delta type 75 | * 76 | * @return string 77 | */ 78 | public function render(): string 79 | { 80 | $html = "<{$this->tag}>"; 81 | if ($this->hasChildren() === true) { 82 | 83 | foreach ($this->children() as $child) { 84 | $html .= $child->render(); 85 | } 86 | } 87 | $html .= "{$this->escape($this->insert)}tag}>\n"; 88 | 89 | return $html; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Delta/Html/Strike.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Strike extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_STRIKE; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/SubScript.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class SubScript extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_SUB_SCRIPT; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/SuperScript.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class SuperScript extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_SUPER_SCRIPT; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/Underline.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Underline extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->tag = Options::HTML_TAG_UNDERLINE; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->renderSimpleTag($this->tag, $this->escape($this->insert)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Html/Video.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Video extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->tag = null; 25 | 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | } 29 | 30 | /** 31 | * Render the HTML for the specific Delta type 32 | * 33 | * @return string 34 | */ 35 | public function render(): string 36 | { 37 | return ''; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Bold.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Bold extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->token = Options::MARKDOWN_TOKEN_BOLD; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->token . $this->escape($this->insert) . $this->token; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Compound.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Compound extends Delta 17 | { 18 | /** 19 | * @var array Array of Markdown tokens 20 | */ 21 | private $tokens; 22 | 23 | /** 24 | * @var array Array of passed in attributes 25 | */ 26 | 27 | /** 28 | * Set the insert for the compound delta insert 29 | * 30 | * @param string $insert 31 | */ 32 | public function __construct(string $insert) 33 | { 34 | $this->insert = $insert; 35 | 36 | $this->tokens = []; 37 | } 38 | 39 | /** 40 | * Pass in an attribute value for conversion 41 | * 42 | * @param string $attribute Attribute name 43 | * @param string $value Attribute value to assign 44 | * 45 | * @return Compound 46 | */ 47 | public function setAttribute($attribute, $value): Compound 48 | { 49 | $this->attributes[$attribute] = $value; 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * Convert attributes to tokens 56 | */ 57 | private function tokens(): void 58 | { 59 | foreach ($this->attributes as $attribute => $value) { 60 | switch ($attribute) { 61 | case Options::ATTRIBUTE_BOLD: 62 | $this->tokens[] = Options::MARKDOWN_TOKEN_BOLD; 63 | break; 64 | 65 | case Options::ATTRIBUTE_ITALIC: 66 | $this->tokens[] = Options::MARKDOWN_TOKEN_ITALIC; 67 | break; 68 | 69 | default: 70 | break; 71 | } 72 | } 73 | } 74 | 75 | /** 76 | * Render the Html for the specific Delta type 77 | * 78 | * @return string 79 | */ 80 | public function render(): string 81 | { 82 | $return = ''; 83 | 84 | $this->tokens(); 85 | 86 | foreach ($this->tokens as $token) { 87 | $return .= $token; 88 | } 89 | 90 | $return .= $this->escape($this->insert); 91 | 92 | foreach (array_reverse($this->tokens) as $token) { 93 | $return .= $token; 94 | } 95 | 96 | return $return; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Delta.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | abstract class Delta extends BaseDelta 17 | { 18 | /** 19 | * @var string The token to use for markdown 20 | */ 21 | protected $token; 22 | 23 | protected $new_line = false; 24 | 25 | /** 26 | * Return whether or not the insert ends with a new line 27 | * 28 | * @return boolean 29 | */ 30 | public function newLine(): bool 31 | { 32 | return $this->new_line; 33 | } 34 | 35 | /** 36 | * Set the new line state 37 | * 38 | * @return Delta 39 | */ 40 | public function setNewLine(): Delta 41 | { 42 | if (preg_match("/[\n]{1}/", $this->insert) !== 0) { 43 | $this->new_line = true; 44 | } 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Escape the given insert string 51 | * 52 | * @param string $insert Insert string to escape 53 | * 54 | * @return string 55 | */ 56 | protected function escape(string $insert): string 57 | { 58 | return str_replace(['*', '#'], ['\*', '\#'], $insert); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Header.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Header extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | 29 | $this->token = Options::MARKDOWN_TOKEN_HEADER; 30 | } 31 | 32 | /** 33 | * Return the display type 34 | * 35 | * @return string 36 | */ 37 | public function displayType(): string 38 | { 39 | return parent::DISPLAY_BLOCK; 40 | } 41 | 42 | /** 43 | * Render the Markdown string 44 | * 45 | * @return string 46 | */ 47 | public function render(): string 48 | { 49 | $string = str_repeat('#', intval($this->attributes['header'])) . ' '; 50 | if ($this->hasChildren() === true) { 51 | 52 | foreach ($this->children() as $child) { 53 | $string .= $child->render(); 54 | } 55 | } 56 | $string .= "{$this->escape($this->insert)}"; 57 | 58 | return $string; 59 | 60 | 61 | 62 | /*return str_repeat('#', intval($this->attributes['header'])) . 63 | " {$this->escape($this->insert)}";*/ 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Image.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Image extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->insert = $insert; 25 | $this->attributes = $attributes; 26 | } 27 | 28 | /** 29 | * Render the HTML for the specific Delta type 30 | * 31 | * @return string 32 | */ 33 | public function render(): string 34 | { 35 | return "![Image]({$this->escape($this->insert)})"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Insert.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Insert extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->token = null; 25 | 26 | $this->insert = $insert; 27 | $this->attributes = $attributes; 28 | } 29 | 30 | /** 31 | * Render the plain text 32 | * 33 | * @return string 34 | */ 35 | public function render(): string 36 | { 37 | return $this->escape($this->insert); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Italic.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class Italic extends Delta 17 | { 18 | /** 19 | * Set the initial properties for the delta 20 | * 21 | * @param string $insert 22 | * @param array $attributes 23 | */ 24 | public function __construct(string $insert, array $attributes = []) 25 | { 26 | $this->token = Options::MARKDOWN_TOKEN_ITALIC; 27 | 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | } 31 | 32 | /** 33 | * Render the HTML for the specific Delta type 34 | * 35 | * @return string 36 | */ 37 | public function render(): string 38 | { 39 | return $this->token . $this->escape($this->insert) . $this->token; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Link.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class Link extends Delta 15 | { 16 | /** 17 | * Set the initial properties for the delta 18 | * 19 | * @param string $insert 20 | * @param array $attributes 21 | */ 22 | public function __construct(string $insert, array $attributes = []) 23 | { 24 | $this->insert = $insert; 25 | $this->attributes = $attributes; 26 | } 27 | 28 | /** 29 | * Render the HTML for the specific Delta type 30 | * 31 | * @return string 32 | */ 33 | public function render(): string 34 | { 35 | $append = str_replace(trim($this->insert), '', $this->insert); 36 | 37 | return "[" . trim($this->escape($this->insert)) . "]({$this->attributes['link']})" . $append; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Delta/Markdown/ListItem.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class ListItem extends Delta 17 | { 18 | private $counter = null; 19 | 20 | /** 21 | * Set the initial properties for the delta 22 | * 23 | * @param string $insert 24 | * @param array $attributes 25 | */ 26 | public function __construct(string $insert, array $attributes = []) 27 | { 28 | $this->insert = $insert; 29 | $this->attributes = $attributes; 30 | 31 | $this->token = null; 32 | 33 | if ($this->attributes['list'] === 'bullet') { 34 | $this->token = Options::MARKDOWN_TOKEN_LIST_ITEM_UNORDERED; 35 | } 36 | } 37 | 38 | /** 39 | * Set the counter for ordered lists 40 | * 41 | * @param integer $counter 42 | * 43 | * @return Delta 44 | */ 45 | public function setCounter(int $counter): Delta 46 | { 47 | $this->counter = $counter; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * Is the delta a child? 54 | * 55 | * @return boolean 56 | */ 57 | public function isChild(): bool 58 | { 59 | return true; 60 | } 61 | 62 | /** 63 | * Render the HTML for the specific Delta type 64 | * 65 | * @return string 66 | */ 67 | public function render(): string 68 | { 69 | $output = ''; 70 | 71 | if ($this->token === null) { 72 | $output .= $this->counter . ". "; 73 | } else { 74 | $output .= $this->token; 75 | } 76 | 77 | if ($this->hasChildren() === true) { 78 | foreach ($this->children() as $child) { 79 | $output .= $child->render(); 80 | } 81 | } 82 | 83 | $output .= $this->escape($this->insert); 84 | 85 | return $output; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Delta/Markdown/Video.php: -------------------------------------------------------------------------------- 1 | 11 | * @author kingga 12 | * @copyright Dean Blackborough 13 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 14 | */ 15 | class Video extends Delta 16 | { 17 | /** 18 | * Set the initial properties for the delta 19 | * 20 | * @param string $insert 21 | * @param array $attributes 22 | */ 23 | public function __construct(string $insert, array $attributes = []) 24 | { 25 | $this->insert = $insert; 26 | $this->attributes = $attributes; 27 | } 28 | 29 | /** 30 | * Render the HTML for the specific Delta type 31 | * 32 | * @return string 33 | */ 34 | public function render(): string 35 | { 36 | return "![Video]({$this->escape($this->insert)})"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Interfaces/DeltaInterface.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | interface DeltaInterface 17 | { 18 | /** 19 | * Add a child delta 20 | * 21 | * @param Delta $delta 22 | * 23 | * @return void 24 | */ 25 | public function addChild(Delta $delta): void; 26 | 27 | /** 28 | * Return the child deltas 29 | * 30 | * @return Delta[] 31 | */ 32 | public function children(): array; 33 | 34 | /** 35 | * Does the delta have any children 36 | * 37 | * @return boolean 38 | */ 39 | public function hasChildren(): bool; 40 | 41 | /** 42 | * Is the delta a child? 43 | * 44 | * @return boolean 45 | */ 46 | public function isChild(): bool; 47 | 48 | /** 49 | * If the delta is a child, is it the first child? 50 | * 51 | * @return boolean 52 | */ 53 | public function isFirstChild(): bool; 54 | 55 | /** 56 | * If the delta is a child, is it the last child? 57 | * 58 | * @return boolean 59 | */ 60 | public function isLastChild(): bool; 61 | 62 | /** 63 | * Return the plain insert string prior to any parsing 64 | * 65 | * @return string 66 | */ 67 | public function getInsert(): string; 68 | 69 | /** 70 | * Render and return the string for the insert ready for renderer 71 | * 72 | * @return string 73 | */ 74 | public function render(): string; 75 | 76 | /** 77 | * Set the current delta to be the first child, alternatively, 78 | * set to false by passing false and clear the value 79 | * 80 | * @var boolean $value Set the value of $this->is_first_child, defaults to true 81 | * 82 | * @return Delta 83 | */ 84 | public function setFirstChild(bool $value = true): Delta; 85 | 86 | /** 87 | * Set the current delta to be the last child, alternatively, 88 | * set to false by passing false and clear the value 89 | * 90 | * @var boolean $value Set the value of $this->is_last_child, defaults to true 91 | * 92 | * @return Delta 93 | */ 94 | public function setLastChild(bool $value = true): Delta; 95 | } 96 | -------------------------------------------------------------------------------- /src/Interfaces/ParserAttributeInterface.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | interface ParserAttributeInterface 15 | { 16 | /** 17 | * Bold Quill attribute, assign the relevant Delta class and set up 18 | * the data 19 | * 20 | * @param array $quill 21 | * 22 | * @return void 23 | */ 24 | public function attributeBold(array $quill); 25 | 26 | /** 27 | * Header Quill attribute, assign the relevant Delta class and set up 28 | * the data 29 | * 30 | * @param array $quill 31 | * 32 | * @return void 33 | */ 34 | public function attributeHeader(array $quill); 35 | 36 | /** 37 | * Italic Quill attribute, assign the relevant Delta class and set up 38 | * the data 39 | * 40 | * @param array $quill 41 | * 42 | * @return void 43 | */ 44 | public function attributeItalic(array $quill); 45 | 46 | /** 47 | * Link Quill attribute, assign the relevant Delta class and set up 48 | * the data 49 | * 50 | * @param array $quill 51 | * 52 | * @return void 53 | */ 54 | public function attributeLink(array $quill); 55 | 56 | /** 57 | * Quill list assign the relevant Delta class and set up the data, needs to 58 | * modify/remove previous Deltas 59 | * 60 | * @param array $quill 61 | * 62 | * @return void 63 | */ 64 | public function attributeList(array $quill); 65 | 66 | /** 67 | * Script Quill attribute, assign the relevant Delta class and set up 68 | * the data, script could be sub or super 69 | * 70 | * @param array $quill 71 | * 72 | * @return void 73 | */ 74 | public function attributeScript(array $quill); 75 | 76 | /** 77 | * Strike Quill attribute, assign the relevant Delta class and set up 78 | * the data 79 | * 80 | * @param array $quill 81 | * 82 | * @return void 83 | */ 84 | public function attributeStrike(array $quill); 85 | 86 | /** 87 | * Underline Quill attribute, assign the relevant Delta class and set up 88 | * the data 89 | * 90 | * @param array $quill 91 | * 92 | * @return void 93 | */ 94 | public function attributeUnderline(array $quill); 95 | 96 | /** 97 | * Basic Quill insert 98 | * 99 | * @param array $quill 100 | * 101 | * @return void 102 | */ 103 | public function insert(array $quill); 104 | 105 | /** 106 | * Multiple attributes set, handle accordingly 107 | * 108 | * @param array $quill 109 | * 110 | * @return void 111 | */ 112 | public function compoundInsert(array $quill); 113 | 114 | /** 115 | * Image, assign to the image Delta 116 | * 117 | * @param array $quill 118 | * 119 | * @return void 120 | */ 121 | public function image(array $quill); 122 | 123 | /** 124 | * Video, assign to the video Delta 125 | * 126 | * @param array $quill 127 | * 128 | * @return void 129 | */ 130 | public function video(array $quill); 131 | } 132 | -------------------------------------------------------------------------------- /src/Interfaces/ParserInterface.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Dean Blackborough 13 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 14 | */ 15 | interface ParserInterface 16 | { 17 | /** 18 | * Load the deltas string, checks the json is valid and can be decoded 19 | * and then saves the decoded array to the the $quill_json property 20 | * 21 | * @param array|string $quill_json Quill json string 22 | * 23 | * @return Parse 24 | * @throws \InvalidArgumentException Throws an exception if there was an error decoding the json 25 | */ 26 | public function load($quill_json): Parse; 27 | 28 | /** 29 | * Load multiple delta strings, checks the json is valid for each index, 30 | * ensures they can be decoded and the saves each decoded array to the 31 | * $quill_json_stack property indexed by the given key 32 | * 33 | * @param array An array of $quill json array|strings, returnable via array index 34 | * 35 | * @return Parse 36 | * @throws \InvalidArgumentException Throws an exception if there was an error decoding the json 37 | */ 38 | public function loadMultiple(array $quill_json): Parse; 39 | 40 | /** 41 | * Parse the $quill_json array and generate an array of Delta[] objects 42 | * 43 | * @return boolean 44 | */ 45 | public function parse(): bool; 46 | 47 | /** 48 | * Parse the $quill_json_stack arrays and generate an indexed array of 49 | * Delta[] objects 50 | * 51 | * @return boolean 52 | */ 53 | public function parseMultiple(): bool; 54 | 55 | /** 56 | * Return the array of Delta[] objects after a call to parse() 57 | * 58 | * @return array 59 | */ 60 | public function deltas(): array; 61 | 62 | /** 63 | * Return a specific Delta[] objects array after a call to parseMultiple() 64 | * 65 | * @param string $index Index of the Delta[] array you are after 66 | * 67 | * @return array 68 | * @throws \OutOfRangeException 69 | */ 70 | public function deltasByIndex(string $index): array; 71 | } 72 | -------------------------------------------------------------------------------- /src/Interfaces/RendererInterface.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Dean Blackborough 13 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 14 | */ 15 | interface RendererInterface 16 | { 17 | /** 18 | * Load the Deltas array from the relevant parser 19 | * 20 | * @param array $deltas Deltas array from the parser 21 | * 22 | * @return Render 23 | */ 24 | public function load(array $deltas): Render; 25 | 26 | /** 27 | * Generate the final output string from the Delta[] array 28 | * 29 | * @param boolean $trim Optionally trim the output 30 | * 31 | * @return string 32 | */ 33 | public function render(bool $trim = false): string; 34 | } 35 | -------------------------------------------------------------------------------- /src/Options.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright Dean Blackborough 11 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 12 | */ 13 | class Options 14 | { 15 | public const FORMAT_HTML = 'HTML'; 16 | public const FORMAT_MARKDOWN = 'Markdown'; 17 | public const FORMAT_GITHUB_MARKDOWN = 'GithubMarkdown'; // Github flavoured markdown 18 | 19 | public const ALL_FORMATS = [ 20 | self::FORMAT_HTML, 21 | self::FORMAT_MARKDOWN, 22 | self::FORMAT_GITHUB_MARKDOWN, 23 | ]; 24 | 25 | public const GITHUB_MARKDOWN_TOKEN_STRIKE = '~~'; 26 | 27 | public const HTML_TAG_BOLD = 'strong'; 28 | public const HTML_TAG_HEADER = 'h'; 29 | public const HTML_TAG_ITALIC = 'em'; 30 | public const HTML_TAG_LIST_ITEM = 'li'; 31 | public const HTML_TAG_STRIKE = 's'; 32 | public const HTML_TAG_SUB_SCRIPT = 'sub'; 33 | public const HTML_TAG_SUPER_SCRIPT = 'sup'; 34 | public const HTML_TAG_UNDERLINE = 'u'; 35 | 36 | public const MARKDOWN_TOKEN_BOLD = '**'; 37 | public const MARKDOWN_TOKEN_HEADER = '#'; 38 | public const MARKDOWN_TOKEN_ITALIC = '*'; 39 | public const MARKDOWN_TOKEN_LIST_ITEM_UNORDERED = '* '; 40 | 41 | public const HTML_TAG_LIST_ORDERED = 'ol'; 42 | public const HTML_TAG_LIST_UNORDERED = 'ul'; 43 | 44 | public const ATTRIBUTE_BOLD = 'bold'; 45 | public const ATTRIBUTE_COLOR = 'color'; 46 | public const ATTRIBUTE_HEADER = 'header'; 47 | public const ATTRIBUTE_ITALIC = 'italic'; 48 | public const ATTRIBUTE_LINK = 'link'; 49 | public const ATTRIBUTE_LIST = 'list'; 50 | public const ATTRIBUTE_LIST_ORDERED = 'ordered'; 51 | public const ATTRIBUTE_LIST_BULLET = 'bullet'; 52 | public const ATTRIBUTE_SCRIPT = 'script'; 53 | public const ATTRIBUTE_SCRIPT_SUB = 'sub'; 54 | public const ATTRIBUTE_SCRIPT_SUPER = 'super'; 55 | public const ATTRIBUTE_STRIKE = 'strike'; 56 | public const ATTRIBUTE_UNDERLINE = 'underline'; 57 | } 58 | -------------------------------------------------------------------------------- /src/Parser/GithubMarkdown.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Dean Blackborough 14 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 15 | */ 16 | class GithubMarkdown extends Markdown 17 | { 18 | /** 19 | * Constructor 20 | */ 21 | public function __construct() 22 | { 23 | parent::__construct(); 24 | 25 | $this->class_delta_strike = Strike::class; 26 | } 27 | 28 | /** 29 | * Strike Quill attribute, assign the relevant Delta class and set up 30 | * the data 31 | * 32 | * @param array $quill 33 | * 34 | * @return void 35 | */ 36 | public function attributeStrike(array $quill) 37 | { 38 | $this->deltas[] = new $this->class_delta_strike($quill['insert']); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Parser/Markdown.php: -------------------------------------------------------------------------------- 1 | 23 | * @copyright Dean Blackborough 24 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 25 | */ 26 | class Markdown extends Parse 27 | { 28 | /** 29 | * Deltas array after parsing, array of Delta objects 30 | * 31 | * @var Delta[] 32 | */ 33 | protected $deltas; 34 | 35 | protected $counter; 36 | 37 | /** 38 | * Constructor. 39 | */ 40 | public function __construct() 41 | { 42 | parent::__construct(); 43 | 44 | $this->counter = 1; 45 | 46 | $this->class_delta_bold = Bold::class; 47 | $this->class_delta_header = Header::class; 48 | $this->class_delta_image = Image::class; 49 | $this->class_delta_insert = Insert::class; 50 | $this->class_delta_italic = Italic::class; 51 | $this->class_delta_link = Link::class; 52 | $this->class_delta_video = Video::class; 53 | } 54 | 55 | /** 56 | * Quill list assign the relevant Delta class and set up the data, needs to 57 | * modify/remove previous Deltas 58 | * 59 | * @param array $quill 60 | * 61 | * @return void 62 | */ 63 | public function attributeList(array $quill) 64 | { 65 | if (in_array($quill['attributes'][OPTIONS::ATTRIBUTE_LIST], array('ordered', 'bullet')) === true) { 66 | $insert = $this->deltas[count($this->deltas) - 1]->getInsert(); 67 | $attributes = $this->deltas[count($this->deltas) - 1]->getAttributes(); 68 | 69 | unset($this->deltas[count($this->deltas) - 1]); 70 | 71 | if (count($attributes) === 0) { 72 | $this->deltas[] = new ListItem($insert . "\n", $quill['attributes']); 73 | } else { 74 | $delta = new ListItem("\n", $quill['attributes']); 75 | 76 | foreach ($attributes as $attribute_name => $value) { 77 | switch ($attribute_name) { 78 | case Options::ATTRIBUTE_BOLD: 79 | $delta->addChild(new Bold($insert)); 80 | break; 81 | 82 | case Options::ATTRIBUTE_ITALIC: 83 | $delta->addChild(new Italic($insert)); 84 | break; 85 | 86 | case Options::ATTRIBUTE_LINK: 87 | $delta->addChild(new Link($insert, $attributes)); 88 | break; 89 | 90 | default: 91 | break; 92 | } 93 | } 94 | $this->deltas[] = $delta; 95 | } 96 | 97 | $this->deltas = array_values($this->deltas); 98 | 99 | $current_index = count($this->deltas) - 1; 100 | 101 | for ($i = $current_index - 1; $i >= 0; $i--) { 102 | $this_delta = $this->deltas[$i]->setNewLine(); 103 | if ($this_delta->newLine() === true) { 104 | break; 105 | } else { 106 | $this->deltas[$current_index]->addChild($this->deltas[$i]); 107 | unset($this->deltas[$i]); 108 | } 109 | } 110 | 111 | $this->deltas = array_values($this->deltas); 112 | $current_index = count($this->deltas) - 1; 113 | $previous_index = $current_index -1; 114 | 115 | if ($previous_index < 0) { 116 | $this->counter = 1; 117 | $this->deltas[$current_index]->setFirstChild()->setCounter($this->counter); 118 | $this->deltas[$current_index]->setLastChild(); 119 | } else { 120 | if ($this->deltas[$previous_index]->isChild() === true) { 121 | $this->counter++; 122 | $this->deltas[$current_index]->setLastChild()->setCounter($this->counter); 123 | $this->deltas[$previous_index]->setLastChild(false); 124 | } else { 125 | $this->counter = 1; 126 | $this->deltas[$current_index]->setFirstChild()->setCounter($this->counter); 127 | $this->deltas[$current_index]->setLastChild(); 128 | } 129 | } 130 | } 131 | } 132 | 133 | /** 134 | * Color Quill attribute, assign the relevant Delta class and set up the data 135 | * 136 | * @param array $quill 137 | * 138 | * @return void 139 | */ 140 | public function attributeColor(array $quill) 141 | { 142 | $this->deltas[] = new Insert($quill['insert']); 143 | } 144 | 145 | /** 146 | * Script Quill attribute, assign the relevant Delta class and set up 147 | * the data, script could be sub or super 148 | * 149 | * @param array $quill 150 | * 151 | * @return void 152 | */ 153 | public function attributeScript(array $quill) 154 | { 155 | $this->deltas[] = new Insert($quill['insert']); 156 | } 157 | 158 | /** 159 | * Strike Quill attribute, assign the relevant Delta class and set up 160 | * the data 161 | * 162 | * @param array $quill 163 | * 164 | * @return void 165 | */ 166 | public function attributeStrike(array $quill) 167 | { 168 | $this->deltas[] = new Insert($quill['insert']); 169 | } 170 | 171 | /** 172 | * Underline Quill attribute, assign the relevant Delta class and set up 173 | * the data 174 | * 175 | * @param array $quill 176 | * 177 | * @return void 178 | */ 179 | public function attributeUnderline(array $quill) 180 | { 181 | $this->deltas[] = new Insert($quill['insert']); 182 | } 183 | 184 | /** 185 | * Multiple attributes set, handle accordingly 186 | * 187 | * @param array $quill 188 | * 189 | * @return void 190 | */ 191 | public function compoundInsert(array $quill) 192 | { 193 | if (count($quill['attributes']) > 0) { 194 | if (is_array($quill['insert']) === false) { 195 | $delta = new Compound($quill['insert']); 196 | 197 | foreach ($quill['attributes'] as $attribute => $value) { 198 | $delta->setAttribute($attribute, $value); 199 | } 200 | 201 | $this->deltas[] = $delta; 202 | } 203 | } 204 | } 205 | 206 | /** 207 | * Extended Quill insert, insert will need to be split before creation 208 | * of Deltas 209 | * 210 | * @param array $quill 211 | * 212 | * @return void 213 | */ 214 | public function extendedInsert(array $quill) 215 | { 216 | if (preg_match("/[\n]{2,}/", $quill['insert']) !== 0) { 217 | $sub_inserts = preg_split("/[\n]{2,}/", $quill['insert']); 218 | $i = 0; 219 | foreach ($sub_inserts as $match) { 220 | $append = "\n\n"; 221 | if ($i === (count($sub_inserts)-1)) { 222 | $append = null; 223 | } 224 | $this->deltas[] = new Insert($match . $append); 225 | $i++; 226 | } 227 | } else { 228 | if (preg_match("/[\n]{1}/", $quill['insert']) !== 0) { 229 | $sub_inserts = preg_split("/[\n]{1}/", $quill['insert']); 230 | $i = 0; 231 | foreach ($sub_inserts as $match) { 232 | $append = "\n"; 233 | if ($i === (count($sub_inserts)-1)) { 234 | $append = null; 235 | } 236 | $this->deltas[] = new Insert($match . $append); 237 | $i++; 238 | } 239 | } else { 240 | $this->deltas[] = new Insert($quill['insert']); 241 | } 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/Render.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright Dean Blackborough 11 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 12 | */ 13 | class Render 14 | { 15 | /** 16 | * @var \DBlackborough\Quill\Parser\Parse 17 | */ 18 | private $parser; 19 | 20 | /** 21 | * @var string 22 | */ 23 | private $format; 24 | 25 | /** 26 | * Renderer constructor, pass in the $quill_json string and set the requested 27 | * output format 28 | * 29 | * @param string $quill_json 30 | * @param string $format Requested output format 31 | * 32 | * @throws \InvalidArgumentException 33 | */ 34 | public function __construct(string $quill_json, string $format = Options::FORMAT_HTML) 35 | { 36 | switch ($format) { 37 | case Options::FORMAT_GITHUB_MARKDOWN: 38 | $this->parser = new Parser\GithubMarkdown(); 39 | break; 40 | case Options::FORMAT_HTML: 41 | $this->parser = new Parser\Html(); 42 | break; 43 | case Options::FORMAT_MARKDOWN: 44 | $this->parser = new Parser\Markdown(); 45 | break; 46 | default: 47 | throw new \InvalidArgumentException( 48 | 'Requested $format not supported, formats supported, ' . 49 | implode(', ', Options::ALL_FORMATS) 50 | ); 51 | break; 52 | } 53 | 54 | $this->format = $format; 55 | 56 | try { 57 | $this->parser->load($quill_json); 58 | } catch (\InvalidArgumentException $e) { 59 | throw new \InvalidArgumentException($e->getMessage()); 60 | } 61 | } 62 | 63 | /** 64 | * Set the custom attributes which you would like the parser to ignore 65 | * 66 | * @param array $ignored_attributes 67 | */ 68 | public function setIgnoredCustomAttributes(array $ignored_attributes = []) 69 | { 70 | if (count($ignored_attributes) > 0) { 71 | Settings::setIgnoredCustomAttributes($ignored_attributes); 72 | } 73 | } 74 | 75 | /** 76 | * Pass the content array to the renderer and return the generated output 77 | * 78 | * @param boolean Optionally trim the output 79 | * 80 | * @return string 81 | * @throws \InvalidArgumentException 82 | * @throws \Exception 83 | */ 84 | public function render(bool $trim = false): string 85 | { 86 | if ($this->parser->parse() === true) { 87 | switch ($this->format) { 88 | case Options::FORMAT_GITHUB_MARKDOWN: 89 | $renderer = new Renderer\GithubMarkdown(); 90 | break; 91 | case Options::FORMAT_HTML: 92 | $renderer = new Renderer\Html(); 93 | break; 94 | case Options::FORMAT_MARKDOWN: 95 | $renderer = new Renderer\Markdown(); 96 | break; 97 | default: 98 | // Shouldn't be possible to get here 99 | throw new \InvalidArgumentException( 100 | 'Requested $format not supported, formats supported, ' . 101 | implode(', ', Options::ALL_FORMATS) 102 | ); 103 | break; 104 | } 105 | 106 | return $renderer->load($this->parser->deltas())->render($trim); 107 | } 108 | 109 | throw new \Exception('Failed to parse the supplied $quill_json array'); 110 | } 111 | 112 | /** 113 | * Return the generated deltas array 114 | * 115 | * @return array|null 116 | */ 117 | public function deltas(): ?array 118 | { 119 | return $this->parser->deltas(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/RenderMultiple.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright Dean Blackborough 12 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 13 | */ 14 | class RenderMultiple 15 | { 16 | /** 17 | * @var \DBlackborough\Quill\Parser\Parse 18 | */ 19 | private $parser; 20 | 21 | /** 22 | * @var string 23 | */ 24 | private $format; 25 | 26 | /** 27 | * Renderer constructor, pass in the $quill_json string and set the requested output format 28 | * 29 | * @param array $quill_json An indexed array of $quill_json string 30 | * @param string $format Requested output format 31 | * 32 | * @throws \Exception 33 | */ 34 | public function __construct(array $quill_json, string $format = Options::FORMAT_HTML) 35 | { 36 | switch ($format) { 37 | case Options::FORMAT_HTML: 38 | $this->parser = new Parser\Html(); 39 | break; 40 | default: 41 | throw new \InvalidArgumentException( 42 | 'Requested $format not supported, formats supported, ' . 43 | Options::FORMAT_HTML 44 | ); 45 | break; 46 | } 47 | 48 | $this->format = $format; 49 | 50 | try { 51 | $this->parser->loadMultiple($quill_json); 52 | } catch (\InvalidArgumentException $e){ 53 | throw new \InvalidArgumentException($e->getMessage()); 54 | } 55 | } 56 | 57 | /** 58 | * Pass the content array to the renderer and return the generated output 59 | * 60 | * @param string $index Index to return 61 | * @param boolean Optionally trim the output 62 | * 63 | * @return string 64 | * @throws \Exception 65 | * @throws \BadMethodCallException 66 | * @throws \OutOfRangeException 67 | */ 68 | public function render(string $index, bool $trim = false): string 69 | { 70 | if ($this->parser->parseMultiple() !== true) { 71 | throw new \Exception('Failed to parse the supplied $quill_json arrays'); 72 | } 73 | 74 | $deltas = $this->parser->deltasByIndex($index); 75 | 76 | switch ($this->format) { 77 | case Options::FORMAT_HTML: 78 | $renderer = new Renderer\Html(); 79 | break; 80 | default: 81 | throw new \InvalidArgumentException( 82 | 'Requested $format not supported, formats supported, ' . 83 | Options::FORMAT_HTML 84 | ); 85 | break; 86 | } 87 | 88 | return $renderer->load($deltas)->render($trim); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Renderer/GithubMarkdown.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright Dean Blackborough 11 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 12 | */ 13 | class GithubMarkdown extends Markdown 14 | { 15 | /** 16 | * GithubMarkdown constructor. 17 | */ 18 | public function __construct() 19 | { 20 | parent::__construct(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Renderer/Html.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Dean Blackborough 13 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 14 | */ 15 | class Html extends Render 16 | { 17 | /** 18 | * @var Delta[] 19 | */ 20 | protected $deltas; 21 | 22 | /** 23 | * Renderer constructor. 24 | * 25 | * @return void 26 | */ 27 | public function __construct() 28 | { 29 | parent::__construct(); 30 | } 31 | 32 | /** 33 | * Generate the final HTML, calls the render method on each object 34 | * 35 | * @param boolean $trim Optionally trim the output 36 | * 37 | * @return string 38 | */ 39 | public function render(bool $trim = false): string 40 | { 41 | $this->output = ''; 42 | 43 | $block_open = false; 44 | 45 | foreach ($this->deltas as $i => $delta) { 46 | if ( 47 | $delta->displayType() === Delta::DISPLAY_INLINE && 48 | $block_open === false 49 | ) { 50 | $block_open = true; 51 | $this->output .= '

'; 52 | } 53 | 54 | if ($delta->isChild() === true && $delta->isFirstChild() === true) { 55 | 56 | if ( 57 | $block_open === true && 58 | $this->deltas[$i - 1]->displayType() === Delta::DISPLAY_INLINE 59 | ) { 60 | $this->output .= "

\n"; 61 | $block_open = false; 62 | } 63 | 64 | $this->output .= '<' . $delta->parentTag() . ">\n"; 65 | } 66 | 67 | if ( 68 | $delta->displayType() === Delta::DISPLAY_BLOCK && 69 | $block_open === true 70 | ) { 71 | $block_open = false; 72 | $this->output .= "

\n"; 73 | } 74 | 75 | $this->output .= $delta->render(); 76 | 77 | if ( 78 | $delta->displayType() === Delta::DISPLAY_INLINE && 79 | ( 80 | $block_open === true && 81 | $delta->close() === true 82 | ) 83 | ) { 84 | $this->output .= "

\n"; 85 | $block_open = false; 86 | } 87 | 88 | if ($delta->isChild() === true && $delta->isLastChild() === true) { 89 | $this->output .= 'parentTag() . ">\n"; 90 | } 91 | 92 | if ( 93 | $i === count($this->deltas) - 1 && 94 | $delta->displayType() === Delta::DISPLAY_INLINE && $block_open === true 95 | ) { 96 | $this->output .= "

\n"; 97 | } 98 | } 99 | 100 | if ($trim === false) { 101 | return $this->output; 102 | } 103 | 104 | return trim($this->output); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Renderer/Markdown.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Dean Blackborough 13 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 14 | */ 15 | class Markdown extends Render 16 | { 17 | /** 18 | * @var Delta[] 19 | */ 20 | protected $deltas; 21 | 22 | /** 23 | * Renderer constructor. 24 | * 25 | * @return void 26 | */ 27 | public function __construct() 28 | { 29 | parent::__construct(); 30 | } 31 | 32 | /** 33 | * Generate the final Markdown, calls the render method on each object 34 | * 35 | * @param boolean $trim Optionally trim the output 36 | * 37 | * @return string 38 | */ 39 | public function render(bool $trim = false): string 40 | { 41 | $this->output = ''; 42 | 43 | foreach ($this->deltas as $i => $delta) { 44 | $this->output .= $delta->render(); 45 | } 46 | 47 | if ($trim === false) { 48 | return $this->output; 49 | } else { 50 | return trim($this->output); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Renderer/Render.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright Dean Blackborough 15 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 16 | */ 17 | abstract class Render implements RendererInterface 18 | { 19 | /** 20 | * @var Delta[] 21 | */ 22 | protected $deltas; 23 | 24 | /** 25 | * The generated HTML 26 | * 27 | * @var string 28 | */ 29 | protected $output; 30 | 31 | /** 32 | * Renderer constructor. 33 | * 34 | * @return void 35 | */ 36 | public function __construct() 37 | { 38 | $this->deltas = []; 39 | } 40 | 41 | /** 42 | * Load the Deltas array from the relevant parser 43 | * 44 | * @param array $deltas Deltas array from the parser 45 | * 46 | * @return Render 47 | */ 48 | public function load(array $deltas) : Render 49 | { 50 | $this->deltas = $deltas; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Generate the final output string from the Delta[] array 57 | * 58 | * @param boolean $trim Optionally trim the output 59 | * 60 | * @return string 61 | */ 62 | abstract public function render(bool $trim = false): string; 63 | } 64 | -------------------------------------------------------------------------------- /src/Settings.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright Dean Blackborough 11 | * @license https://github.com/deanblackborough/php-quill-renderer/blob/master/LICENSE 12 | */ 13 | class Settings 14 | { 15 | private static $ignored_custom_attributes = []; 16 | 17 | /** 18 | * Set any attributes which you would like the parser to ignore, specifically 19 | * the compound delta 20 | * 21 | * @param array $attributes 22 | */ 23 | static public function setIgnoredCustomAttributes(array $attributes) 24 | { 25 | self::$ignored_custom_attributes = $attributes; 26 | } 27 | 28 | /** 29 | * Return the ignore attributes 30 | * 31 | * @return array 32 | */ 33 | static public function ignoredCustomAttributes(): array 34 | { 35 | return self::$ignored_custom_attributes; 36 | } 37 | } 38 | --------------------------------------------------------------------------------