Skip to content

Commit 9e13da2

Browse files
committed
update QuillJs to version 2.0, add new fields, update readme && clean code
1 parent a7cea4d commit 9e13da2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1979
-432
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Please do not submit any Pull Requests here. They will be closed.
2+
---
3+
4+
Please submit your PR here instead:
5+
https://github.com/symfony/ux
6+
7+
This repository is what we call a "subtree split": a read-only subset of that main repository.
8+
We're looking forward to your PR there!
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Check subtree split
2+
on:
3+
pull_request_target:
4+
jobs:
5+
close-pull-request:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- name: Close pull request
9+
uses: actions/github-script@v6
10+
with:
11+
script: |
12+
if (context.repo.owner === "symfony") {
13+
github.rest.issues.createComment({
14+
owner: "symfony",
15+
repo: context.repo.repo,
16+
issue_number: context.issue.number,
17+
body: `
18+
Thanks for your Pull Request! We love contributions.
19+
20+
However, you should instead open your PR on the main repository:
21+
https://github.com/symfony/ux
22+
23+
This repository is what we call a "subtree split": a read-only subset of that main repository.
24+
We're looking forward to your PR there!
25+
`
26+
});
27+
github.rest.pulls.update({
28+
owner: "symfony",
29+
repo: context.repo.repo,
30+
pull_number: context.issue.number,
31+
state: "closed"
32+
});
33+
}

src/QuillJs/LICENSE

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
MIT License
2-
3-
Copyright (c) 2023 Matthieu Gostiaux
1+
Copyright (c) 2024-present Fabien Potencier
42

53
Permission is hereby granted, free of charge, to any person obtaining a copy
64
of this software and associated documentation files (the "Software"), to deal
75
in the Software without restriction, including without limitation the rights
86
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:
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
119

1210
The above copyright notice and this permission notice shall be included in all
1311
copies or substantial portions of the Software.
@@ -17,5 +15,5 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1715
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1816
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1917
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.
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

src/QuillJs/README.md

Lines changed: 271 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,275 @@
1-
# Symfony UX QuillJs
1+
# QuillJs Bundle for Symfony using Symfony UX
22

3-
Symfony UX QuillJs integrates [QuillJs](https://quilljs.com/) into Symfony applications.
3+
Symfony UX Bundle implementing the Quill JS Wysiwyg https://quilljs.com/
44

5-
**This repository is a READ-ONLY sub-tree split**. See
6-
https://github.com/symfony/ux to create issues or submit pull requests.
5+
If you need a easy to use WYSIWYG (with no complex configuration) into a symfony project this is what you need.
76

8-
## Resources
7+
* [Installation](#installation)
98

10-
- [Documentation](https://symfony.com/bundles/ux-quill/current/index.html)
11-
- [Report issues](https://github.com/symfony/ux/issues) and
12-
[send Pull Requests](https://github.com/symfony/ux/pulls)
13-
in the [main Symfony UX repository](https://github.com/symfony/ux)
9+
10+
* [Basic Usage](#basic-usage)
11+
* [Display Result](#display-result)
12+
13+
14+
* [Customize quillJS with options and extra_options](#customize-options)
15+
* [Handle images uploads](#image-upload-handling)
16+
17+
18+
* [EasyAdmin Integration](#easyadmin-integration)
19+
* [EasyAdmin Usage](#usage)
20+
21+
## Installation
22+
### Step 1 Require bundle
23+
```sh
24+
composer require symfony/ux-quill
25+
```
26+
If you are using the AssetMapper Component you're done !
27+
28+
### step 2 next run (If you are using webpack encore, not needed with AssetMapper)
29+
``` sh
30+
yarn install --force
31+
yarn watch
32+
```
33+
OR
34+
``` sh
35+
npm install --force
36+
npm run watch
37+
```
38+
It's done, you can use the QuillType to build a QuillJs WYSIWYG
39+
40+
You can add as many WYSIWYG fields inside same page like any normal fields.
41+
42+
# Basic Usage
43+
In a form, use QuillType. It works like a classic Type except it has more options : e.g:
44+
```php
45+
use Symfony\UX\QuillJs\Form\QuillType;
46+
47+
public function buildForm(FormBuilderInterface $builder, array $options)
48+
{
49+
$builder
50+
// ...
51+
->add('myField', QuillType::class)
52+
;
53+
}
54+
```
55+
56+
# Display result
57+
in a twig template simply :
58+
```
59+
<div>{{ myField|raw }}</div>
60+
```
61+
you can of course sanitize HTML if you need to for security reason, but don't forget to configure it
62+
to your needs as many html balise and style elements will be removed by default.
63+
Same goes in your Form configuration
64+
```
65+
'sanitize_html' => false,
66+
'sanitizer' => 'my_awesome_sanitizer_config
67+
```
68+
69+
70+
For the most basic this is only what you have to do.
71+
# Customize Options
72+
```php
73+
use Symfony\UX\QuillJs\Form\QuillType;
74+
75+
public function buildForm(FormBuilderInterface $builder, array $options)
76+
{
77+
$builder
78+
// ...
79+
->add('myField', QuillType::class, [
80+
'quill_extra_options' => [
81+
'height' => '780px',
82+
'theme' => 'snow',
83+
'placeholder' => 'Hello Quill WYSIWYG',
84+
],
85+
'quill_options' => [
86+
// this is where you customize the WYSIWYG by creating one or many Groups
87+
// you can also build your groups using a classic array but many classes are covering every Quill available Fields (see below for detailed list)
88+
QuillGroup::build(
89+
new BoldInlineField(),
90+
new ItalicInlineField(),
91+
// and many more
92+
),
93+
QuillGroup::build(
94+
new HeaderField(HeaderField::HEADER_OPTION_1),
95+
new HeaderField(HeaderField::HEADER_OPTION_2),
96+
// and many more
97+
),
98+
// Or add all available fields at once
99+
QuillGroup::buildWithAllFields()
100+
]
101+
])
102+
;
103+
}
104+
```
105+
106+
107+
## quill_options :
108+
This is where you will choose what elements you want to display in your WYSIWYG.
109+
You can build an array like you would do following the QuillJs official documentation
110+
Or use a more convenient with Autocomplete using the many Fields Object in this bundle.
111+
```
112+
QuillGroup::build(
113+
new HeaderField(HeaderField::HEADER_OPTION_1),
114+
new HeaderField(HeaderField::HEADER_OPTION_2),
115+
)
116+
```
117+
This example will display a h1 and h2 header options side by side
118+
```
119+
QuillGroup::build(
120+
new HeaderField(HeaderField::HEADER_OPTION_1),
121+
new HeaderField(HeaderField::HEADER_OPTION_2),
122+
)
123+
QuillGroup::build(
124+
new BoldInlineField(),
125+
new ItalicInlineField(),
126+
)
127+
```
128+
This example will display a h1 and h2 header options side by side and another Group containing a Bold and an Italic fields
129+
130+
You can add as many Groups as you like or just One if you don't need the WYSIWYG options to have spaces between them.
131+
132+
### Fields
133+
- Below is the list of available fields from QuillJS (https://v2.quilljs.com/docs/formats)
134+
135+
| Field | Description | Available options (options are available as class constants in each Field Class) | Default option | QuillJS field name |
136+
|:--------------------:|:------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------:|:--------------:|:------------------:|
137+
| BoldField | mark text as bold | - | | bold |
138+
| ColorField | Change color of the font | array of colors (default is empty array to get quillJS default value | | color |
139+
| BackGroundColorField | change background color of the selected text | array of colors (default is empty array to get quillJS default value | | background |
140+
| AlignField | Choose text alignment | false (left), center, right, justify | all | align |
141+
| DirectionField | Choose text direction | rtl (right to left, this is the only option available this widget is more like a toggle) | rtl | direction |
142+
| FontField | Choose a font | ''(sans serif) ,serif, monospace | all | font |
143+
| HeaderGroupField | Display a list of header levels | 1, 2, 3, 4, 5, 6, false (will only display normal) | all | header |
144+
| HeaderField | Add a H1 or H2 widget only | 1, 2 | 1 | header |
145+
| IndentField | Add or Remove indent | +1, -1 | +1 | indent |
146+
| ListField | Add a list | ordered, bullet, check | ordered | list |
147+
| ScriptField | | sub, super | sub | script |
148+
| SizeField | Change text size | small, false (normal), large, huge | all | size |
149+
| BlockQuoteField | Quote a text | - | | blockquote |
150+
| CleanField | Clean text styling | - | | clean |
151+
| CodeBlockField | Add a code-block | - | | code-block |
152+
| CodeField | Add some code | - | | code |
153+
| FormulaField | add a formula (with [Katex](https://katex.org/)) | - | | formula |
154+
| ImageField | Add an image (see [quill_extra_options](#image-upload-handling) for uploads options) | - | | image |
155+
| ItalicField | mark text as italic | - | | italic |
156+
| LinkField | Add a link to a text | - | | link |
157+
| StrikeField | mark a text as striked | - | | strike |
158+
| UnderlineField | mark text as underlined | - | | underline |
159+
| VideoField | add an embed video | - | | video |
160+
161+
162+
- Below is a list of fields not available in QuillJS but taken from community
163+
164+
| Field | Description | Available options (options are available as class constants in each Field Class) | Default option |
165+
|:----------:|:------------:|:----------------------------------------------------------------------------------:|:--------------:|
166+
| EmojiField | Add an emoji | - | |
167+
168+
169+
170+
## quill_extra_options:
171+
172+
- **debug**: type:string, values: 'error', 'warn', 'log', 'info' (you can use DebugOption class to build it)
173+
- **height**: type string, examples: 200px, 200em, default: '200px'
174+
- **theme**: type: string, values: 'snow', 'bubble', default: 'snow' (you can use ThemeOption class to build it)
175+
- **placeholder**: type: string
176+
- **upload_handler**: type: array (explained below)
177+
178+
### Image upload Handling
179+
in ***ImageInlineField*** : QuillJS transform images in base64 encoded file by default to save your files.
180+
However, you can specify a custom endpoint to handle image uploading and pass in response the entire public URL to display the image.
181+
- currently handling :
182+
- data sending in base64 inside a json
183+
- OR
184+
- in a multipart/form-data
185+
```
186+
'quill_extra_options' => [
187+
///
188+
'upload_handler' => [
189+
'type' => 'json',
190+
// or 'type' => 'form',
191+
'path' => '/my-custom-endpoint/upload',
192+
]
193+
],
194+
```
195+
- your endpoint must return the complete URL of the file example :
196+
```
197+
https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/480px-JavaScript-logo.png
198+
```
199+
- in json mode data will look like this by calling $request->getContent() and ```application/json``` in content-type headers
200+
```
201+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAQAAAAUb1BXAAAABGdBTUEAALGPC/xhBQAAACyygyyioiBqFCUIKC64x..."
202+
```
203+
- in form mode you will find a ```multipart/form-data``` in content-type headers and file will be present in $request->files named ```file```
204+
- then you can handle it like you would do with a FileType
205+
206+
207+
208+
# Easyadmin Integration
209+
- First create a quill-admin.js inside assets directory
210+
```
211+
// start the Stimulus application
212+
import './bootstrap';
213+
```
214+
## When using AssetMapper
215+
create a new entry in importmap.php
216+
(the key must be quill-admin as it is the name used in the built-in QuillAdminField)
217+
```
218+
'quill-admin' => [
219+
'path' => './assets/quill-admin.js',
220+
'entrypoint' => true,
221+
],
222+
```
223+
and i should be done. but read below
224+
225+
WARNING => at the moment there seems to have an issue with easyadmin with the ->addAssetMapperEntries() function
226+
as I can not get it work as it should be.
227+
a quick fix is to add in your crudControllers
228+
```
229+
public function configureAssets(Assets $assets): Assets
230+
{
231+
$assets->addAssetMapperEntry('quill-admin');
232+
return parent::configureAssets($assets); // TODO: Change the autogenerated stub
233+
}
234+
```
235+
236+
OR
237+
238+
in your dashboard
239+
```
240+
public function configureAssets(): Assets
241+
{
242+
$assets = Assets::new();
243+
$assets->addAssetMapperEntry('quill-admin');
244+
245+
return $assets;
246+
}
247+
```
248+
249+
## When using webpack
250+
- Next create in webpack.config a new entry
251+
(the entry name must be quill-admin as it is the name used in the built-in QuillAdminField)
252+
```
253+
.addEntry('quill-admin', './assets/quill-admin.js')
254+
```
255+
don't forget to recompile assets (yarn build/watch or npm equivalent).
256+
257+
## EasyAdmin
258+
Then you can use the QuillAdminField like this :
259+
```
260+
QuillAdminField::new('quill')
261+
```
262+
263+
Or add custom options like you would do with the normal type
264+
```
265+
QuillAdminField::new('quill')
266+
->setFormTypeOptions([
267+
'quill_options' =>
268+
QuillGroup::build(
269+
new BoldInlineField(),
270+
new ItalicInlineField(),
271+
new HeaderField(HeaderField::HEADER_OPTION_1),
272+
new HeaderField(HeaderField::HEADER_OPTION_2),
273+
)
274+
])
275+
```
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Quill from 'quill';
2+
const InlineBlot = Quill.import('blots/block');
3+
class LoadingImage extends InlineBlot {
4+
static create(src) {
5+
const node = super.create(src);
6+
if (src === true) return node;
7+
const image = document.createElement('img');
8+
image.setAttribute('src', src);
9+
node.appendChild(image);
10+
return node;
11+
}
12+
deleteAt(index, length) {
13+
super.deleteAt(index, length);
14+
this.cache = {};
15+
}
16+
static value(domNode) {
17+
const {
18+
src,
19+
custom
20+
} = domNode.dataset;
21+
return {
22+
src,
23+
custom
24+
};
25+
}
26+
}
27+
LoadingImage.blotName = 'imageBlot';
28+
LoadingImage.className = 'image-uploading';
29+
LoadingImage.tagName = 'span';
30+
Quill.register({
31+
'formats/imageBlot': LoadingImage
32+
});
33+
export default LoadingImage;

0 commit comments

Comments
 (0)