├── .gitignore ├── .idea ├── angular_quill.iml └── modules.xml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── build.yaml ├── lib ├── angular_quill.dart ├── quill-1.3.6 │ ├── quill.bubble.css │ ├── quill.core.css │ ├── quill.core.js │ ├── quill.js │ ├── quill.min.js │ ├── quill.min.js.map │ └── quill.snow.css └── src │ └── quill │ ├── quill.dart │ ├── quill_component.dart │ └── quill_component.html ├── pubspec.yaml └── test └── app_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .packages 3 | .pub/ 4 | # Remove the following pattern if you wish to check in your lock file 5 | pubspec.lock 6 | 7 | # Directory created by dartdoc 8 | doc/api/ 9 | 10 | .idea/libraries 11 | .idea/workspace.xml 12 | .idea/vcs.xml 13 | 14 | .dart_tool 15 | -------------------------------------------------------------------------------- /.idea/angular_quill.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.2.1 4 | 5 | - Minimum sdk 2.12.0 6 | 7 | 8 | ## 0.2.0 9 | 10 | - Null saftey. Requires AngularDart 7 11 | - Quill 1.3.6 12 | 13 | ## 0.1.4 14 | 15 | - Allow angular_forms 3.0.0 16 | 17 | ## 0.1.3 18 | 19 | - Allow angular 6 20 | 21 | ## 0.1.2 22 | 23 | - Fix type of `off` to fix crash when destroying component in DDC. 24 | - Dart fmt 25 | 26 | ## 0.1.1 27 | 28 | - Add `build.yaml` file so theme css files are included in build. 29 | 30 | ## 0.1.0 31 | 32 | - Upgrade to dart 2 and angular 5 33 | 34 | ## 0.0.6 35 | 36 | - Upgrade to angular 4.0.0 37 | 38 | ## 0.0.5 39 | 40 | - Update README 41 | 42 | ## 0.0.3 43 | 44 | - Split example out of main repo 45 | 46 | ## 0.0.1 47 | 48 | - Initial version, created by Stagehand 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Adam Lofts. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Quill 2 | 3 | An angular dart component for the Quill rich text editor 4 | 5 | ## [See it in action](https://adamlofts.github.io/angular_quill_example/build/web/index.html) 6 | 7 | Visit https://adamlofts.github.io/angular_quill_example/build/web/index.html 8 | 9 | And view the corresponding [example source code](https://github.com/adamlofts/angular_quill_example/blob/master/web/app_component.html). 10 | 11 | ## Usage 12 | 13 | Add the dependency to pub: 14 | 15 | ```yaml 16 | dependencies: 17 | angular_quill: 18 | ``` 19 | 20 | Add the component to your template 21 | 22 | ```html 23 | 24 | 30 | 31 | 32 | ``` 33 | 34 | Add `quillDirectives` to the directives on your app component 35 | 36 | ```dart 37 | @Component( 38 | selector: 'my-app', 39 | templateUrl: 'app_component.html', 40 | directives: const [COMMON_DIRECTIVES, quillDirectives], 41 | ) 42 | class AppComponent {} 43 | 44 | ``` 45 | 46 | Include Quill JS and css files in your app html. 47 | 48 | ```html 49 | 50 | 51 | 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | # exclude: 3 | # - path/to/excluded/files/** 4 | 5 | # Lint rules and documentation, see http://dart-lang.github.io/linter/lints 6 | linter: 7 | rules: 8 | - cancel_subscriptions 9 | - close_sinks 10 | - hash_and_equals 11 | - iterable_contains_unrelated_type 12 | - list_remove_unrelated_type 13 | - test_types_in_equals 14 | - unrelated_type_equality_checks 15 | - valid_regexps 16 | -------------------------------------------------------------------------------- /build.yaml: -------------------------------------------------------------------------------- 1 | # Angular by default deletes css files under lib because it assumes it inlines them into dart code 2 | # To make sure the css file is included in the build output we specify a build.yaml file and configure specific 3 | # file excludes for the builder in the angular package that performs the cleanup. 4 | targets: 5 | $default: 6 | builders: 7 | angular|component_source_cleanup: 8 | enabled: true 9 | generate_for: 10 | exclude: 11 | - "lib/quill-1.3.6/quill.snow.css" -------------------------------------------------------------------------------- /lib/angular_quill.dart: -------------------------------------------------------------------------------- 1 | export 'src/quill/quill_component.dart' show QuillValueAccessor, QuillComponent; 2 | import 'src/quill/quill_component.dart' show QuillValueAccessor, QuillComponent; 3 | 4 | const List quillDirectives = const [QuillValueAccessor, QuillComponent]; 5 | -------------------------------------------------------------------------------- /lib/quill-1.3.6/quill.bubble.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Quill Editor v1.3.6 3 | * https://quilljs.com/ 4 | * Copyright (c) 2014, Jason Chen 5 | * Copyright (c) 2013, salesforce.com 6 | */ 7 | .ql-container { 8 | box-sizing: border-box; 9 | font-family: Helvetica, Arial, sans-serif; 10 | font-size: 13px; 11 | height: 100%; 12 | margin: 0px; 13 | position: relative; 14 | } 15 | .ql-container.ql-disabled .ql-tooltip { 16 | visibility: hidden; 17 | } 18 | .ql-container.ql-disabled .ql-editor ul[data-checked] > li::before { 19 | pointer-events: none; 20 | } 21 | .ql-clipboard { 22 | left: -100000px; 23 | height: 1px; 24 | overflow-y: hidden; 25 | position: absolute; 26 | top: 50%; 27 | } 28 | .ql-clipboard p { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | .ql-editor { 33 | box-sizing: border-box; 34 | line-height: 1.42; 35 | height: 100%; 36 | outline: none; 37 | overflow-y: auto; 38 | padding: 12px 15px; 39 | tab-size: 4; 40 | -moz-tab-size: 4; 41 | text-align: left; 42 | white-space: pre-wrap; 43 | word-wrap: break-word; 44 | } 45 | .ql-editor > * { 46 | cursor: text; 47 | } 48 | .ql-editor p, 49 | .ql-editor ol, 50 | .ql-editor ul, 51 | .ql-editor pre, 52 | .ql-editor blockquote, 53 | .ql-editor h1, 54 | .ql-editor h2, 55 | .ql-editor h3, 56 | .ql-editor h4, 57 | .ql-editor h5, 58 | .ql-editor h6 { 59 | margin: 0; 60 | padding: 0; 61 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 62 | } 63 | .ql-editor ol, 64 | .ql-editor ul { 65 | padding-left: 1.5em; 66 | } 67 | .ql-editor ol > li, 68 | .ql-editor ul > li { 69 | list-style-type: none; 70 | } 71 | .ql-editor ul > li::before { 72 | content: '\2022'; 73 | } 74 | .ql-editor ul[data-checked=true], 75 | .ql-editor ul[data-checked=false] { 76 | pointer-events: none; 77 | } 78 | .ql-editor ul[data-checked=true] > li *, 79 | .ql-editor ul[data-checked=false] > li * { 80 | pointer-events: all; 81 | } 82 | .ql-editor ul[data-checked=true] > li::before, 83 | .ql-editor ul[data-checked=false] > li::before { 84 | color: #777; 85 | cursor: pointer; 86 | pointer-events: all; 87 | } 88 | .ql-editor ul[data-checked=true] > li::before { 89 | content: '\2611'; 90 | } 91 | .ql-editor ul[data-checked=false] > li::before { 92 | content: '\2610'; 93 | } 94 | .ql-editor li::before { 95 | display: inline-block; 96 | white-space: nowrap; 97 | width: 1.2em; 98 | } 99 | .ql-editor li:not(.ql-direction-rtl)::before { 100 | margin-left: -1.5em; 101 | margin-right: 0.3em; 102 | text-align: right; 103 | } 104 | .ql-editor li.ql-direction-rtl::before { 105 | margin-left: 0.3em; 106 | margin-right: -1.5em; 107 | } 108 | .ql-editor ol li:not(.ql-direction-rtl), 109 | .ql-editor ul li:not(.ql-direction-rtl) { 110 | padding-left: 1.5em; 111 | } 112 | .ql-editor ol li.ql-direction-rtl, 113 | .ql-editor ul li.ql-direction-rtl { 114 | padding-right: 1.5em; 115 | } 116 | .ql-editor ol li { 117 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 118 | counter-increment: list-0; 119 | } 120 | .ql-editor ol li:before { 121 | content: counter(list-0, decimal) '. '; 122 | } 123 | .ql-editor ol li.ql-indent-1 { 124 | counter-increment: list-1; 125 | } 126 | .ql-editor ol li.ql-indent-1:before { 127 | content: counter(list-1, lower-alpha) '. '; 128 | } 129 | .ql-editor ol li.ql-indent-1 { 130 | counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 131 | } 132 | .ql-editor ol li.ql-indent-2 { 133 | counter-increment: list-2; 134 | } 135 | .ql-editor ol li.ql-indent-2:before { 136 | content: counter(list-2, lower-roman) '. '; 137 | } 138 | .ql-editor ol li.ql-indent-2 { 139 | counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9; 140 | } 141 | .ql-editor ol li.ql-indent-3 { 142 | counter-increment: list-3; 143 | } 144 | .ql-editor ol li.ql-indent-3:before { 145 | content: counter(list-3, decimal) '. '; 146 | } 147 | .ql-editor ol li.ql-indent-3 { 148 | counter-reset: list-4 list-5 list-6 list-7 list-8 list-9; 149 | } 150 | .ql-editor ol li.ql-indent-4 { 151 | counter-increment: list-4; 152 | } 153 | .ql-editor ol li.ql-indent-4:before { 154 | content: counter(list-4, lower-alpha) '. '; 155 | } 156 | .ql-editor ol li.ql-indent-4 { 157 | counter-reset: list-5 list-6 list-7 list-8 list-9; 158 | } 159 | .ql-editor ol li.ql-indent-5 { 160 | counter-increment: list-5; 161 | } 162 | .ql-editor ol li.ql-indent-5:before { 163 | content: counter(list-5, lower-roman) '. '; 164 | } 165 | .ql-editor ol li.ql-indent-5 { 166 | counter-reset: list-6 list-7 list-8 list-9; 167 | } 168 | .ql-editor ol li.ql-indent-6 { 169 | counter-increment: list-6; 170 | } 171 | .ql-editor ol li.ql-indent-6:before { 172 | content: counter(list-6, decimal) '. '; 173 | } 174 | .ql-editor ol li.ql-indent-6 { 175 | counter-reset: list-7 list-8 list-9; 176 | } 177 | .ql-editor ol li.ql-indent-7 { 178 | counter-increment: list-7; 179 | } 180 | .ql-editor ol li.ql-indent-7:before { 181 | content: counter(list-7, lower-alpha) '. '; 182 | } 183 | .ql-editor ol li.ql-indent-7 { 184 | counter-reset: list-8 list-9; 185 | } 186 | .ql-editor ol li.ql-indent-8 { 187 | counter-increment: list-8; 188 | } 189 | .ql-editor ol li.ql-indent-8:before { 190 | content: counter(list-8, lower-roman) '. '; 191 | } 192 | .ql-editor ol li.ql-indent-8 { 193 | counter-reset: list-9; 194 | } 195 | .ql-editor ol li.ql-indent-9 { 196 | counter-increment: list-9; 197 | } 198 | .ql-editor ol li.ql-indent-9:before { 199 | content: counter(list-9, decimal) '. '; 200 | } 201 | .ql-editor .ql-indent-1:not(.ql-direction-rtl) { 202 | padding-left: 3em; 203 | } 204 | .ql-editor li.ql-indent-1:not(.ql-direction-rtl) { 205 | padding-left: 4.5em; 206 | } 207 | .ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right { 208 | padding-right: 3em; 209 | } 210 | .ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right { 211 | padding-right: 4.5em; 212 | } 213 | .ql-editor .ql-indent-2:not(.ql-direction-rtl) { 214 | padding-left: 6em; 215 | } 216 | .ql-editor li.ql-indent-2:not(.ql-direction-rtl) { 217 | padding-left: 7.5em; 218 | } 219 | .ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right { 220 | padding-right: 6em; 221 | } 222 | .ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right { 223 | padding-right: 7.5em; 224 | } 225 | .ql-editor .ql-indent-3:not(.ql-direction-rtl) { 226 | padding-left: 9em; 227 | } 228 | .ql-editor li.ql-indent-3:not(.ql-direction-rtl) { 229 | padding-left: 10.5em; 230 | } 231 | .ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right { 232 | padding-right: 9em; 233 | } 234 | .ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right { 235 | padding-right: 10.5em; 236 | } 237 | .ql-editor .ql-indent-4:not(.ql-direction-rtl) { 238 | padding-left: 12em; 239 | } 240 | .ql-editor li.ql-indent-4:not(.ql-direction-rtl) { 241 | padding-left: 13.5em; 242 | } 243 | .ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right { 244 | padding-right: 12em; 245 | } 246 | .ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right { 247 | padding-right: 13.5em; 248 | } 249 | .ql-editor .ql-indent-5:not(.ql-direction-rtl) { 250 | padding-left: 15em; 251 | } 252 | .ql-editor li.ql-indent-5:not(.ql-direction-rtl) { 253 | padding-left: 16.5em; 254 | } 255 | .ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right { 256 | padding-right: 15em; 257 | } 258 | .ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right { 259 | padding-right: 16.5em; 260 | } 261 | .ql-editor .ql-indent-6:not(.ql-direction-rtl) { 262 | padding-left: 18em; 263 | } 264 | .ql-editor li.ql-indent-6:not(.ql-direction-rtl) { 265 | padding-left: 19.5em; 266 | } 267 | .ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right { 268 | padding-right: 18em; 269 | } 270 | .ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right { 271 | padding-right: 19.5em; 272 | } 273 | .ql-editor .ql-indent-7:not(.ql-direction-rtl) { 274 | padding-left: 21em; 275 | } 276 | .ql-editor li.ql-indent-7:not(.ql-direction-rtl) { 277 | padding-left: 22.5em; 278 | } 279 | .ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right { 280 | padding-right: 21em; 281 | } 282 | .ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right { 283 | padding-right: 22.5em; 284 | } 285 | .ql-editor .ql-indent-8:not(.ql-direction-rtl) { 286 | padding-left: 24em; 287 | } 288 | .ql-editor li.ql-indent-8:not(.ql-direction-rtl) { 289 | padding-left: 25.5em; 290 | } 291 | .ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right { 292 | padding-right: 24em; 293 | } 294 | .ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right { 295 | padding-right: 25.5em; 296 | } 297 | .ql-editor .ql-indent-9:not(.ql-direction-rtl) { 298 | padding-left: 27em; 299 | } 300 | .ql-editor li.ql-indent-9:not(.ql-direction-rtl) { 301 | padding-left: 28.5em; 302 | } 303 | .ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right { 304 | padding-right: 27em; 305 | } 306 | .ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right { 307 | padding-right: 28.5em; 308 | } 309 | .ql-editor .ql-video { 310 | display: block; 311 | max-width: 100%; 312 | } 313 | .ql-editor .ql-video.ql-align-center { 314 | margin: 0 auto; 315 | } 316 | .ql-editor .ql-video.ql-align-right { 317 | margin: 0 0 0 auto; 318 | } 319 | .ql-editor .ql-bg-black { 320 | background-color: #000; 321 | } 322 | .ql-editor .ql-bg-red { 323 | background-color: #e60000; 324 | } 325 | .ql-editor .ql-bg-orange { 326 | background-color: #f90; 327 | } 328 | .ql-editor .ql-bg-yellow { 329 | background-color: #ff0; 330 | } 331 | .ql-editor .ql-bg-green { 332 | background-color: #008a00; 333 | } 334 | .ql-editor .ql-bg-blue { 335 | background-color: #06c; 336 | } 337 | .ql-editor .ql-bg-purple { 338 | background-color: #93f; 339 | } 340 | .ql-editor .ql-color-white { 341 | color: #fff; 342 | } 343 | .ql-editor .ql-color-red { 344 | color: #e60000; 345 | } 346 | .ql-editor .ql-color-orange { 347 | color: #f90; 348 | } 349 | .ql-editor .ql-color-yellow { 350 | color: #ff0; 351 | } 352 | .ql-editor .ql-color-green { 353 | color: #008a00; 354 | } 355 | .ql-editor .ql-color-blue { 356 | color: #06c; 357 | } 358 | .ql-editor .ql-color-purple { 359 | color: #93f; 360 | } 361 | .ql-editor .ql-font-serif { 362 | font-family: Georgia, Times New Roman, serif; 363 | } 364 | .ql-editor .ql-font-monospace { 365 | font-family: Monaco, Courier New, monospace; 366 | } 367 | .ql-editor .ql-size-small { 368 | font-size: 0.75em; 369 | } 370 | .ql-editor .ql-size-large { 371 | font-size: 1.5em; 372 | } 373 | .ql-editor .ql-size-huge { 374 | font-size: 2.5em; 375 | } 376 | .ql-editor .ql-direction-rtl { 377 | direction: rtl; 378 | text-align: inherit; 379 | } 380 | .ql-editor .ql-align-center { 381 | text-align: center; 382 | } 383 | .ql-editor .ql-align-justify { 384 | text-align: justify; 385 | } 386 | .ql-editor .ql-align-right { 387 | text-align: right; 388 | } 389 | .ql-editor.ql-blank::before { 390 | color: rgba(0,0,0,0.6); 391 | content: attr(data-placeholder); 392 | font-style: italic; 393 | left: 15px; 394 | pointer-events: none; 395 | position: absolute; 396 | right: 15px; 397 | } 398 | .ql-bubble.ql-toolbar:after, 399 | .ql-bubble .ql-toolbar:after { 400 | clear: both; 401 | content: ''; 402 | display: table; 403 | } 404 | .ql-bubble.ql-toolbar button, 405 | .ql-bubble .ql-toolbar button { 406 | background: none; 407 | border: none; 408 | cursor: pointer; 409 | display: inline-block; 410 | float: left; 411 | height: 24px; 412 | padding: 3px 5px; 413 | width: 28px; 414 | } 415 | .ql-bubble.ql-toolbar button svg, 416 | .ql-bubble .ql-toolbar button svg { 417 | float: left; 418 | height: 100%; 419 | } 420 | .ql-bubble.ql-toolbar button:active:hover, 421 | .ql-bubble .ql-toolbar button:active:hover { 422 | outline: none; 423 | } 424 | .ql-bubble.ql-toolbar input.ql-image[type=file], 425 | .ql-bubble .ql-toolbar input.ql-image[type=file] { 426 | display: none; 427 | } 428 | .ql-bubble.ql-toolbar button:hover, 429 | .ql-bubble .ql-toolbar button:hover, 430 | .ql-bubble.ql-toolbar button:focus, 431 | .ql-bubble .ql-toolbar button:focus, 432 | .ql-bubble.ql-toolbar button.ql-active, 433 | .ql-bubble .ql-toolbar button.ql-active, 434 | .ql-bubble.ql-toolbar .ql-picker-label:hover, 435 | .ql-bubble .ql-toolbar .ql-picker-label:hover, 436 | .ql-bubble.ql-toolbar .ql-picker-label.ql-active, 437 | .ql-bubble .ql-toolbar .ql-picker-label.ql-active, 438 | .ql-bubble.ql-toolbar .ql-picker-item:hover, 439 | .ql-bubble .ql-toolbar .ql-picker-item:hover, 440 | .ql-bubble.ql-toolbar .ql-picker-item.ql-selected, 441 | .ql-bubble .ql-toolbar .ql-picker-item.ql-selected { 442 | color: #fff; 443 | } 444 | .ql-bubble.ql-toolbar button:hover .ql-fill, 445 | .ql-bubble .ql-toolbar button:hover .ql-fill, 446 | .ql-bubble.ql-toolbar button:focus .ql-fill, 447 | .ql-bubble .ql-toolbar button:focus .ql-fill, 448 | .ql-bubble.ql-toolbar button.ql-active .ql-fill, 449 | .ql-bubble .ql-toolbar button.ql-active .ql-fill, 450 | .ql-bubble.ql-toolbar .ql-picker-label:hover .ql-fill, 451 | .ql-bubble .ql-toolbar .ql-picker-label:hover .ql-fill, 452 | .ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-fill, 453 | .ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-fill, 454 | .ql-bubble.ql-toolbar .ql-picker-item:hover .ql-fill, 455 | .ql-bubble .ql-toolbar .ql-picker-item:hover .ql-fill, 456 | .ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-fill, 457 | .ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-fill, 458 | .ql-bubble.ql-toolbar button:hover .ql-stroke.ql-fill, 459 | .ql-bubble .ql-toolbar button:hover .ql-stroke.ql-fill, 460 | .ql-bubble.ql-toolbar button:focus .ql-stroke.ql-fill, 461 | .ql-bubble .ql-toolbar button:focus .ql-stroke.ql-fill, 462 | .ql-bubble.ql-toolbar button.ql-active .ql-stroke.ql-fill, 463 | .ql-bubble .ql-toolbar button.ql-active .ql-stroke.ql-fill, 464 | .ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, 465 | .ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, 466 | .ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, 467 | .ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, 468 | .ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, 469 | .ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, 470 | .ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill, 471 | .ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill { 472 | fill: #fff; 473 | } 474 | .ql-bubble.ql-toolbar button:hover .ql-stroke, 475 | .ql-bubble .ql-toolbar button:hover .ql-stroke, 476 | .ql-bubble.ql-toolbar button:focus .ql-stroke, 477 | .ql-bubble .ql-toolbar button:focus .ql-stroke, 478 | .ql-bubble.ql-toolbar button.ql-active .ql-stroke, 479 | .ql-bubble .ql-toolbar button.ql-active .ql-stroke, 480 | .ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke, 481 | .ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke, 482 | .ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke, 483 | .ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke, 484 | .ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke, 485 | .ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke, 486 | .ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke, 487 | .ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke, 488 | .ql-bubble.ql-toolbar button:hover .ql-stroke-miter, 489 | .ql-bubble .ql-toolbar button:hover .ql-stroke-miter, 490 | .ql-bubble.ql-toolbar button:focus .ql-stroke-miter, 491 | .ql-bubble .ql-toolbar button:focus .ql-stroke-miter, 492 | .ql-bubble.ql-toolbar button.ql-active .ql-stroke-miter, 493 | .ql-bubble .ql-toolbar button.ql-active .ql-stroke-miter, 494 | .ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke-miter, 495 | .ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke-miter, 496 | .ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, 497 | .ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, 498 | .ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke-miter, 499 | .ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke-miter, 500 | .ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter, 501 | .ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter { 502 | stroke: #fff; 503 | } 504 | @media (pointer: coarse) { 505 | .ql-bubble.ql-toolbar button:hover:not(.ql-active), 506 | .ql-bubble .ql-toolbar button:hover:not(.ql-active) { 507 | color: #ccc; 508 | } 509 | .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-fill, 510 | .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-fill, 511 | .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill, 512 | .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill { 513 | fill: #ccc; 514 | } 515 | .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke, 516 | .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke, 517 | .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter, 518 | .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter { 519 | stroke: #ccc; 520 | } 521 | } 522 | .ql-bubble { 523 | box-sizing: border-box; 524 | } 525 | .ql-bubble * { 526 | box-sizing: border-box; 527 | } 528 | .ql-bubble .ql-hidden { 529 | display: none; 530 | } 531 | .ql-bubble .ql-out-bottom, 532 | .ql-bubble .ql-out-top { 533 | visibility: hidden; 534 | } 535 | .ql-bubble .ql-tooltip { 536 | position: absolute; 537 | transform: translateY(10px); 538 | } 539 | .ql-bubble .ql-tooltip a { 540 | cursor: pointer; 541 | text-decoration: none; 542 | } 543 | .ql-bubble .ql-tooltip.ql-flip { 544 | transform: translateY(-10px); 545 | } 546 | .ql-bubble .ql-formats { 547 | display: inline-block; 548 | vertical-align: middle; 549 | } 550 | .ql-bubble .ql-formats:after { 551 | clear: both; 552 | content: ''; 553 | display: table; 554 | } 555 | .ql-bubble .ql-stroke { 556 | fill: none; 557 | stroke: #ccc; 558 | stroke-linecap: round; 559 | stroke-linejoin: round; 560 | stroke-width: 2; 561 | } 562 | .ql-bubble .ql-stroke-miter { 563 | fill: none; 564 | stroke: #ccc; 565 | stroke-miterlimit: 10; 566 | stroke-width: 2; 567 | } 568 | .ql-bubble .ql-fill, 569 | .ql-bubble .ql-stroke.ql-fill { 570 | fill: #ccc; 571 | } 572 | .ql-bubble .ql-empty { 573 | fill: none; 574 | } 575 | .ql-bubble .ql-even { 576 | fill-rule: evenodd; 577 | } 578 | .ql-bubble .ql-thin, 579 | .ql-bubble .ql-stroke.ql-thin { 580 | stroke-width: 1; 581 | } 582 | .ql-bubble .ql-transparent { 583 | opacity: 0.4; 584 | } 585 | .ql-bubble .ql-direction svg:last-child { 586 | display: none; 587 | } 588 | .ql-bubble .ql-direction.ql-active svg:last-child { 589 | display: inline; 590 | } 591 | .ql-bubble .ql-direction.ql-active svg:first-child { 592 | display: none; 593 | } 594 | .ql-bubble .ql-editor h1 { 595 | font-size: 2em; 596 | } 597 | .ql-bubble .ql-editor h2 { 598 | font-size: 1.5em; 599 | } 600 | .ql-bubble .ql-editor h3 { 601 | font-size: 1.17em; 602 | } 603 | .ql-bubble .ql-editor h4 { 604 | font-size: 1em; 605 | } 606 | .ql-bubble .ql-editor h5 { 607 | font-size: 0.83em; 608 | } 609 | .ql-bubble .ql-editor h6 { 610 | font-size: 0.67em; 611 | } 612 | .ql-bubble .ql-editor a { 613 | text-decoration: underline; 614 | } 615 | .ql-bubble .ql-editor blockquote { 616 | border-left: 4px solid #ccc; 617 | margin-bottom: 5px; 618 | margin-top: 5px; 619 | padding-left: 16px; 620 | } 621 | .ql-bubble .ql-editor code, 622 | .ql-bubble .ql-editor pre { 623 | background-color: #f0f0f0; 624 | border-radius: 3px; 625 | } 626 | .ql-bubble .ql-editor pre { 627 | white-space: pre-wrap; 628 | margin-bottom: 5px; 629 | margin-top: 5px; 630 | padding: 5px 10px; 631 | } 632 | .ql-bubble .ql-editor code { 633 | font-size: 85%; 634 | padding: 2px 4px; 635 | } 636 | .ql-bubble .ql-editor pre.ql-syntax { 637 | background-color: #23241f; 638 | color: #f8f8f2; 639 | overflow: visible; 640 | } 641 | .ql-bubble .ql-editor img { 642 | max-width: 100%; 643 | } 644 | .ql-bubble .ql-picker { 645 | color: #ccc; 646 | display: inline-block; 647 | float: left; 648 | font-size: 14px; 649 | font-weight: 500; 650 | height: 24px; 651 | position: relative; 652 | vertical-align: middle; 653 | } 654 | .ql-bubble .ql-picker-label { 655 | cursor: pointer; 656 | display: inline-block; 657 | height: 100%; 658 | padding-left: 8px; 659 | padding-right: 2px; 660 | position: relative; 661 | width: 100%; 662 | } 663 | .ql-bubble .ql-picker-label::before { 664 | display: inline-block; 665 | line-height: 22px; 666 | } 667 | .ql-bubble .ql-picker-options { 668 | background-color: #444; 669 | display: none; 670 | min-width: 100%; 671 | padding: 4px 8px; 672 | position: absolute; 673 | white-space: nowrap; 674 | } 675 | .ql-bubble .ql-picker-options .ql-picker-item { 676 | cursor: pointer; 677 | display: block; 678 | padding-bottom: 5px; 679 | padding-top: 5px; 680 | } 681 | .ql-bubble .ql-picker.ql-expanded .ql-picker-label { 682 | color: #777; 683 | z-index: 2; 684 | } 685 | .ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-fill { 686 | fill: #777; 687 | } 688 | .ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-stroke { 689 | stroke: #777; 690 | } 691 | .ql-bubble .ql-picker.ql-expanded .ql-picker-options { 692 | display: block; 693 | margin-top: -1px; 694 | top: 100%; 695 | z-index: 1; 696 | } 697 | .ql-bubble .ql-color-picker, 698 | .ql-bubble .ql-icon-picker { 699 | width: 28px; 700 | } 701 | .ql-bubble .ql-color-picker .ql-picker-label, 702 | .ql-bubble .ql-icon-picker .ql-picker-label { 703 | padding: 2px 4px; 704 | } 705 | .ql-bubble .ql-color-picker .ql-picker-label svg, 706 | .ql-bubble .ql-icon-picker .ql-picker-label svg { 707 | right: 4px; 708 | } 709 | .ql-bubble .ql-icon-picker .ql-picker-options { 710 | padding: 4px 0px; 711 | } 712 | .ql-bubble .ql-icon-picker .ql-picker-item { 713 | height: 24px; 714 | width: 24px; 715 | padding: 2px 4px; 716 | } 717 | .ql-bubble .ql-color-picker .ql-picker-options { 718 | padding: 3px 5px; 719 | width: 152px; 720 | } 721 | .ql-bubble .ql-color-picker .ql-picker-item { 722 | border: 1px solid transparent; 723 | float: left; 724 | height: 16px; 725 | margin: 2px; 726 | padding: 0px; 727 | width: 16px; 728 | } 729 | .ql-bubble .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg { 730 | position: absolute; 731 | margin-top: -9px; 732 | right: 0; 733 | top: 50%; 734 | width: 18px; 735 | } 736 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before, 737 | .ql-bubble .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before, 738 | .ql-bubble .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before, 739 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before, 740 | .ql-bubble .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before, 741 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before { 742 | content: attr(data-label); 743 | } 744 | .ql-bubble .ql-picker.ql-header { 745 | width: 98px; 746 | } 747 | .ql-bubble .ql-picker.ql-header .ql-picker-label::before, 748 | .ql-bubble .ql-picker.ql-header .ql-picker-item::before { 749 | content: 'Normal'; 750 | } 751 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, 752 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { 753 | content: 'Heading 1'; 754 | } 755 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, 756 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { 757 | content: 'Heading 2'; 758 | } 759 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, 760 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { 761 | content: 'Heading 3'; 762 | } 763 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, 764 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { 765 | content: 'Heading 4'; 766 | } 767 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, 768 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { 769 | content: 'Heading 5'; 770 | } 771 | .ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, 772 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { 773 | content: 'Heading 6'; 774 | } 775 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { 776 | font-size: 2em; 777 | } 778 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { 779 | font-size: 1.5em; 780 | } 781 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { 782 | font-size: 1.17em; 783 | } 784 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { 785 | font-size: 1em; 786 | } 787 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { 788 | font-size: 0.83em; 789 | } 790 | .ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { 791 | font-size: 0.67em; 792 | } 793 | .ql-bubble .ql-picker.ql-font { 794 | width: 108px; 795 | } 796 | .ql-bubble .ql-picker.ql-font .ql-picker-label::before, 797 | .ql-bubble .ql-picker.ql-font .ql-picker-item::before { 798 | content: 'Sans Serif'; 799 | } 800 | .ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=serif]::before, 801 | .ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { 802 | content: 'Serif'; 803 | } 804 | .ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before, 805 | .ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { 806 | content: 'Monospace'; 807 | } 808 | .ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { 809 | font-family: Georgia, Times New Roman, serif; 810 | } 811 | .ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { 812 | font-family: Monaco, Courier New, monospace; 813 | } 814 | .ql-bubble .ql-picker.ql-size { 815 | width: 98px; 816 | } 817 | .ql-bubble .ql-picker.ql-size .ql-picker-label::before, 818 | .ql-bubble .ql-picker.ql-size .ql-picker-item::before { 819 | content: 'Normal'; 820 | } 821 | .ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=small]::before, 822 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before { 823 | content: 'Small'; 824 | } 825 | .ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=large]::before, 826 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before { 827 | content: 'Large'; 828 | } 829 | .ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, 830 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { 831 | content: 'Huge'; 832 | } 833 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before { 834 | font-size: 10px; 835 | } 836 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before { 837 | font-size: 18px; 838 | } 839 | .ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { 840 | font-size: 32px; 841 | } 842 | .ql-bubble .ql-color-picker.ql-background .ql-picker-item { 843 | background-color: #fff; 844 | } 845 | .ql-bubble .ql-color-picker.ql-color .ql-picker-item { 846 | background-color: #000; 847 | } 848 | .ql-bubble .ql-toolbar .ql-formats { 849 | margin: 8px 12px 8px 0px; 850 | } 851 | .ql-bubble .ql-toolbar .ql-formats:first-child { 852 | margin-left: 12px; 853 | } 854 | .ql-bubble .ql-color-picker svg { 855 | margin: 1px; 856 | } 857 | .ql-bubble .ql-color-picker .ql-picker-item.ql-selected, 858 | .ql-bubble .ql-color-picker .ql-picker-item:hover { 859 | border-color: #fff; 860 | } 861 | .ql-bubble .ql-tooltip { 862 | background-color: #444; 863 | border-radius: 25px; 864 | color: #fff; 865 | } 866 | .ql-bubble .ql-tooltip-arrow { 867 | border-left: 6px solid transparent; 868 | border-right: 6px solid transparent; 869 | content: " "; 870 | display: block; 871 | left: 50%; 872 | margin-left: -6px; 873 | position: absolute; 874 | } 875 | .ql-bubble .ql-tooltip:not(.ql-flip) .ql-tooltip-arrow { 876 | border-bottom: 6px solid #444; 877 | top: -6px; 878 | } 879 | .ql-bubble .ql-tooltip.ql-flip .ql-tooltip-arrow { 880 | border-top: 6px solid #444; 881 | bottom: -6px; 882 | } 883 | .ql-bubble .ql-tooltip.ql-editing .ql-tooltip-editor { 884 | display: block; 885 | } 886 | .ql-bubble .ql-tooltip.ql-editing .ql-formats { 887 | visibility: hidden; 888 | } 889 | .ql-bubble .ql-tooltip-editor { 890 | display: none; 891 | } 892 | .ql-bubble .ql-tooltip-editor input[type=text] { 893 | background: transparent; 894 | border: none; 895 | color: #fff; 896 | font-size: 13px; 897 | height: 100%; 898 | outline: none; 899 | padding: 10px 20px; 900 | position: absolute; 901 | width: 100%; 902 | } 903 | .ql-bubble .ql-tooltip-editor a { 904 | top: 10px; 905 | position: absolute; 906 | right: 20px; 907 | } 908 | .ql-bubble .ql-tooltip-editor a:before { 909 | color: #ccc; 910 | content: "\D7"; 911 | font-size: 16px; 912 | font-weight: bold; 913 | } 914 | .ql-container.ql-bubble:not(.ql-disabled) a { 915 | position: relative; 916 | white-space: nowrap; 917 | } 918 | .ql-container.ql-bubble:not(.ql-disabled) a::before { 919 | background-color: #444; 920 | border-radius: 15px; 921 | top: -5px; 922 | font-size: 12px; 923 | color: #fff; 924 | content: attr(href); 925 | font-weight: normal; 926 | overflow: hidden; 927 | padding: 5px 15px; 928 | text-decoration: none; 929 | z-index: 1; 930 | } 931 | .ql-container.ql-bubble:not(.ql-disabled) a::after { 932 | border-top: 6px solid #444; 933 | border-left: 6px solid transparent; 934 | border-right: 6px solid transparent; 935 | top: 0; 936 | content: " "; 937 | height: 0; 938 | width: 0; 939 | } 940 | .ql-container.ql-bubble:not(.ql-disabled) a::before, 941 | .ql-container.ql-bubble:not(.ql-disabled) a::after { 942 | left: 0; 943 | margin-left: 50%; 944 | position: absolute; 945 | transform: translate(-50%, -100%); 946 | transition: visibility 0s ease 200ms; 947 | visibility: hidden; 948 | } 949 | .ql-container.ql-bubble:not(.ql-disabled) a:hover::before, 950 | .ql-container.ql-bubble:not(.ql-disabled) a:hover::after { 951 | visibility: visible; 952 | } 953 | -------------------------------------------------------------------------------- /lib/quill-1.3.6/quill.core.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Quill Editor v1.3.6 3 | * https://quilljs.com/ 4 | * Copyright (c) 2014, Jason Chen 5 | * Copyright (c) 2013, salesforce.com 6 | */ 7 | .ql-container { 8 | box-sizing: border-box; 9 | font-family: Helvetica, Arial, sans-serif; 10 | font-size: 13px; 11 | height: 100%; 12 | margin: 0px; 13 | position: relative; 14 | } 15 | .ql-container.ql-disabled .ql-tooltip { 16 | visibility: hidden; 17 | } 18 | .ql-container.ql-disabled .ql-editor ul[data-checked] > li::before { 19 | pointer-events: none; 20 | } 21 | .ql-clipboard { 22 | left: -100000px; 23 | height: 1px; 24 | overflow-y: hidden; 25 | position: absolute; 26 | top: 50%; 27 | } 28 | .ql-clipboard p { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | .ql-editor { 33 | box-sizing: border-box; 34 | line-height: 1.42; 35 | height: 100%; 36 | outline: none; 37 | overflow-y: auto; 38 | padding: 12px 15px; 39 | tab-size: 4; 40 | -moz-tab-size: 4; 41 | text-align: left; 42 | white-space: pre-wrap; 43 | word-wrap: break-word; 44 | } 45 | .ql-editor > * { 46 | cursor: text; 47 | } 48 | .ql-editor p, 49 | .ql-editor ol, 50 | .ql-editor ul, 51 | .ql-editor pre, 52 | .ql-editor blockquote, 53 | .ql-editor h1, 54 | .ql-editor h2, 55 | .ql-editor h3, 56 | .ql-editor h4, 57 | .ql-editor h5, 58 | .ql-editor h6 { 59 | margin: 0; 60 | padding: 0; 61 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 62 | } 63 | .ql-editor ol, 64 | .ql-editor ul { 65 | padding-left: 1.5em; 66 | } 67 | .ql-editor ol > li, 68 | .ql-editor ul > li { 69 | list-style-type: none; 70 | } 71 | .ql-editor ul > li::before { 72 | content: '\2022'; 73 | } 74 | .ql-editor ul[data-checked=true], 75 | .ql-editor ul[data-checked=false] { 76 | pointer-events: none; 77 | } 78 | .ql-editor ul[data-checked=true] > li *, 79 | .ql-editor ul[data-checked=false] > li * { 80 | pointer-events: all; 81 | } 82 | .ql-editor ul[data-checked=true] > li::before, 83 | .ql-editor ul[data-checked=false] > li::before { 84 | color: #777; 85 | cursor: pointer; 86 | pointer-events: all; 87 | } 88 | .ql-editor ul[data-checked=true] > li::before { 89 | content: '\2611'; 90 | } 91 | .ql-editor ul[data-checked=false] > li::before { 92 | content: '\2610'; 93 | } 94 | .ql-editor li::before { 95 | display: inline-block; 96 | white-space: nowrap; 97 | width: 1.2em; 98 | } 99 | .ql-editor li:not(.ql-direction-rtl)::before { 100 | margin-left: -1.5em; 101 | margin-right: 0.3em; 102 | text-align: right; 103 | } 104 | .ql-editor li.ql-direction-rtl::before { 105 | margin-left: 0.3em; 106 | margin-right: -1.5em; 107 | } 108 | .ql-editor ol li:not(.ql-direction-rtl), 109 | .ql-editor ul li:not(.ql-direction-rtl) { 110 | padding-left: 1.5em; 111 | } 112 | .ql-editor ol li.ql-direction-rtl, 113 | .ql-editor ul li.ql-direction-rtl { 114 | padding-right: 1.5em; 115 | } 116 | .ql-editor ol li { 117 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 118 | counter-increment: list-0; 119 | } 120 | .ql-editor ol li:before { 121 | content: counter(list-0, decimal) '. '; 122 | } 123 | .ql-editor ol li.ql-indent-1 { 124 | counter-increment: list-1; 125 | } 126 | .ql-editor ol li.ql-indent-1:before { 127 | content: counter(list-1, lower-alpha) '. '; 128 | } 129 | .ql-editor ol li.ql-indent-1 { 130 | counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 131 | } 132 | .ql-editor ol li.ql-indent-2 { 133 | counter-increment: list-2; 134 | } 135 | .ql-editor ol li.ql-indent-2:before { 136 | content: counter(list-2, lower-roman) '. '; 137 | } 138 | .ql-editor ol li.ql-indent-2 { 139 | counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9; 140 | } 141 | .ql-editor ol li.ql-indent-3 { 142 | counter-increment: list-3; 143 | } 144 | .ql-editor ol li.ql-indent-3:before { 145 | content: counter(list-3, decimal) '. '; 146 | } 147 | .ql-editor ol li.ql-indent-3 { 148 | counter-reset: list-4 list-5 list-6 list-7 list-8 list-9; 149 | } 150 | .ql-editor ol li.ql-indent-4 { 151 | counter-increment: list-4; 152 | } 153 | .ql-editor ol li.ql-indent-4:before { 154 | content: counter(list-4, lower-alpha) '. '; 155 | } 156 | .ql-editor ol li.ql-indent-4 { 157 | counter-reset: list-5 list-6 list-7 list-8 list-9; 158 | } 159 | .ql-editor ol li.ql-indent-5 { 160 | counter-increment: list-5; 161 | } 162 | .ql-editor ol li.ql-indent-5:before { 163 | content: counter(list-5, lower-roman) '. '; 164 | } 165 | .ql-editor ol li.ql-indent-5 { 166 | counter-reset: list-6 list-7 list-8 list-9; 167 | } 168 | .ql-editor ol li.ql-indent-6 { 169 | counter-increment: list-6; 170 | } 171 | .ql-editor ol li.ql-indent-6:before { 172 | content: counter(list-6, decimal) '. '; 173 | } 174 | .ql-editor ol li.ql-indent-6 { 175 | counter-reset: list-7 list-8 list-9; 176 | } 177 | .ql-editor ol li.ql-indent-7 { 178 | counter-increment: list-7; 179 | } 180 | .ql-editor ol li.ql-indent-7:before { 181 | content: counter(list-7, lower-alpha) '. '; 182 | } 183 | .ql-editor ol li.ql-indent-7 { 184 | counter-reset: list-8 list-9; 185 | } 186 | .ql-editor ol li.ql-indent-8 { 187 | counter-increment: list-8; 188 | } 189 | .ql-editor ol li.ql-indent-8:before { 190 | content: counter(list-8, lower-roman) '. '; 191 | } 192 | .ql-editor ol li.ql-indent-8 { 193 | counter-reset: list-9; 194 | } 195 | .ql-editor ol li.ql-indent-9 { 196 | counter-increment: list-9; 197 | } 198 | .ql-editor ol li.ql-indent-9:before { 199 | content: counter(list-9, decimal) '. '; 200 | } 201 | .ql-editor .ql-indent-1:not(.ql-direction-rtl) { 202 | padding-left: 3em; 203 | } 204 | .ql-editor li.ql-indent-1:not(.ql-direction-rtl) { 205 | padding-left: 4.5em; 206 | } 207 | .ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right { 208 | padding-right: 3em; 209 | } 210 | .ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right { 211 | padding-right: 4.5em; 212 | } 213 | .ql-editor .ql-indent-2:not(.ql-direction-rtl) { 214 | padding-left: 6em; 215 | } 216 | .ql-editor li.ql-indent-2:not(.ql-direction-rtl) { 217 | padding-left: 7.5em; 218 | } 219 | .ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right { 220 | padding-right: 6em; 221 | } 222 | .ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right { 223 | padding-right: 7.5em; 224 | } 225 | .ql-editor .ql-indent-3:not(.ql-direction-rtl) { 226 | padding-left: 9em; 227 | } 228 | .ql-editor li.ql-indent-3:not(.ql-direction-rtl) { 229 | padding-left: 10.5em; 230 | } 231 | .ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right { 232 | padding-right: 9em; 233 | } 234 | .ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right { 235 | padding-right: 10.5em; 236 | } 237 | .ql-editor .ql-indent-4:not(.ql-direction-rtl) { 238 | padding-left: 12em; 239 | } 240 | .ql-editor li.ql-indent-4:not(.ql-direction-rtl) { 241 | padding-left: 13.5em; 242 | } 243 | .ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right { 244 | padding-right: 12em; 245 | } 246 | .ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right { 247 | padding-right: 13.5em; 248 | } 249 | .ql-editor .ql-indent-5:not(.ql-direction-rtl) { 250 | padding-left: 15em; 251 | } 252 | .ql-editor li.ql-indent-5:not(.ql-direction-rtl) { 253 | padding-left: 16.5em; 254 | } 255 | .ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right { 256 | padding-right: 15em; 257 | } 258 | .ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right { 259 | padding-right: 16.5em; 260 | } 261 | .ql-editor .ql-indent-6:not(.ql-direction-rtl) { 262 | padding-left: 18em; 263 | } 264 | .ql-editor li.ql-indent-6:not(.ql-direction-rtl) { 265 | padding-left: 19.5em; 266 | } 267 | .ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right { 268 | padding-right: 18em; 269 | } 270 | .ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right { 271 | padding-right: 19.5em; 272 | } 273 | .ql-editor .ql-indent-7:not(.ql-direction-rtl) { 274 | padding-left: 21em; 275 | } 276 | .ql-editor li.ql-indent-7:not(.ql-direction-rtl) { 277 | padding-left: 22.5em; 278 | } 279 | .ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right { 280 | padding-right: 21em; 281 | } 282 | .ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right { 283 | padding-right: 22.5em; 284 | } 285 | .ql-editor .ql-indent-8:not(.ql-direction-rtl) { 286 | padding-left: 24em; 287 | } 288 | .ql-editor li.ql-indent-8:not(.ql-direction-rtl) { 289 | padding-left: 25.5em; 290 | } 291 | .ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right { 292 | padding-right: 24em; 293 | } 294 | .ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right { 295 | padding-right: 25.5em; 296 | } 297 | .ql-editor .ql-indent-9:not(.ql-direction-rtl) { 298 | padding-left: 27em; 299 | } 300 | .ql-editor li.ql-indent-9:not(.ql-direction-rtl) { 301 | padding-left: 28.5em; 302 | } 303 | .ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right { 304 | padding-right: 27em; 305 | } 306 | .ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right { 307 | padding-right: 28.5em; 308 | } 309 | .ql-editor .ql-video { 310 | display: block; 311 | max-width: 100%; 312 | } 313 | .ql-editor .ql-video.ql-align-center { 314 | margin: 0 auto; 315 | } 316 | .ql-editor .ql-video.ql-align-right { 317 | margin: 0 0 0 auto; 318 | } 319 | .ql-editor .ql-bg-black { 320 | background-color: #000; 321 | } 322 | .ql-editor .ql-bg-red { 323 | background-color: #e60000; 324 | } 325 | .ql-editor .ql-bg-orange { 326 | background-color: #f90; 327 | } 328 | .ql-editor .ql-bg-yellow { 329 | background-color: #ff0; 330 | } 331 | .ql-editor .ql-bg-green { 332 | background-color: #008a00; 333 | } 334 | .ql-editor .ql-bg-blue { 335 | background-color: #06c; 336 | } 337 | .ql-editor .ql-bg-purple { 338 | background-color: #93f; 339 | } 340 | .ql-editor .ql-color-white { 341 | color: #fff; 342 | } 343 | .ql-editor .ql-color-red { 344 | color: #e60000; 345 | } 346 | .ql-editor .ql-color-orange { 347 | color: #f90; 348 | } 349 | .ql-editor .ql-color-yellow { 350 | color: #ff0; 351 | } 352 | .ql-editor .ql-color-green { 353 | color: #008a00; 354 | } 355 | .ql-editor .ql-color-blue { 356 | color: #06c; 357 | } 358 | .ql-editor .ql-color-purple { 359 | color: #93f; 360 | } 361 | .ql-editor .ql-font-serif { 362 | font-family: Georgia, Times New Roman, serif; 363 | } 364 | .ql-editor .ql-font-monospace { 365 | font-family: Monaco, Courier New, monospace; 366 | } 367 | .ql-editor .ql-size-small { 368 | font-size: 0.75em; 369 | } 370 | .ql-editor .ql-size-large { 371 | font-size: 1.5em; 372 | } 373 | .ql-editor .ql-size-huge { 374 | font-size: 2.5em; 375 | } 376 | .ql-editor .ql-direction-rtl { 377 | direction: rtl; 378 | text-align: inherit; 379 | } 380 | .ql-editor .ql-align-center { 381 | text-align: center; 382 | } 383 | .ql-editor .ql-align-justify { 384 | text-align: justify; 385 | } 386 | .ql-editor .ql-align-right { 387 | text-align: right; 388 | } 389 | .ql-editor.ql-blank::before { 390 | color: rgba(0,0,0,0.6); 391 | content: attr(data-placeholder); 392 | font-style: italic; 393 | left: 15px; 394 | pointer-events: none; 395 | position: absolute; 396 | right: 15px; 397 | } 398 | -------------------------------------------------------------------------------- /lib/quill-1.3.6/quill.snow.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Quill Editor v1.3.6 3 | * https://quilljs.com/ 4 | * Copyright (c) 2014, Jason Chen 5 | * Copyright (c) 2013, salesforce.com 6 | */ 7 | .ql-container { 8 | box-sizing: border-box; 9 | font-family: Helvetica, Arial, sans-serif; 10 | font-size: 13px; 11 | height: 100%; 12 | margin: 0px; 13 | position: relative; 14 | } 15 | .ql-container.ql-disabled .ql-tooltip { 16 | visibility: hidden; 17 | } 18 | .ql-container.ql-disabled .ql-editor ul[data-checked] > li::before { 19 | pointer-events: none; 20 | } 21 | .ql-clipboard { 22 | left: -100000px; 23 | height: 1px; 24 | overflow-y: hidden; 25 | position: absolute; 26 | top: 50%; 27 | } 28 | .ql-clipboard p { 29 | margin: 0; 30 | padding: 0; 31 | } 32 | .ql-editor { 33 | box-sizing: border-box; 34 | line-height: 1.42; 35 | height: 100%; 36 | outline: none; 37 | overflow-y: auto; 38 | padding: 12px 15px; 39 | tab-size: 4; 40 | -moz-tab-size: 4; 41 | text-align: left; 42 | white-space: pre-wrap; 43 | word-wrap: break-word; 44 | } 45 | .ql-editor > * { 46 | cursor: text; 47 | } 48 | .ql-editor p, 49 | .ql-editor ol, 50 | .ql-editor ul, 51 | .ql-editor pre, 52 | .ql-editor blockquote, 53 | .ql-editor h1, 54 | .ql-editor h2, 55 | .ql-editor h3, 56 | .ql-editor h4, 57 | .ql-editor h5, 58 | .ql-editor h6 { 59 | margin: 0; 60 | padding: 0; 61 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 62 | } 63 | .ql-editor ol, 64 | .ql-editor ul { 65 | padding-left: 1.5em; 66 | } 67 | .ql-editor ol > li, 68 | .ql-editor ul > li { 69 | list-style-type: none; 70 | } 71 | .ql-editor ul > li::before { 72 | content: '\2022'; 73 | } 74 | .ql-editor ul[data-checked=true], 75 | .ql-editor ul[data-checked=false] { 76 | pointer-events: none; 77 | } 78 | .ql-editor ul[data-checked=true] > li *, 79 | .ql-editor ul[data-checked=false] > li * { 80 | pointer-events: all; 81 | } 82 | .ql-editor ul[data-checked=true] > li::before, 83 | .ql-editor ul[data-checked=false] > li::before { 84 | color: #777; 85 | cursor: pointer; 86 | pointer-events: all; 87 | } 88 | .ql-editor ul[data-checked=true] > li::before { 89 | content: '\2611'; 90 | } 91 | .ql-editor ul[data-checked=false] > li::before { 92 | content: '\2610'; 93 | } 94 | .ql-editor li::before { 95 | display: inline-block; 96 | white-space: nowrap; 97 | width: 1.2em; 98 | } 99 | .ql-editor li:not(.ql-direction-rtl)::before { 100 | margin-left: -1.5em; 101 | margin-right: 0.3em; 102 | text-align: right; 103 | } 104 | .ql-editor li.ql-direction-rtl::before { 105 | margin-left: 0.3em; 106 | margin-right: -1.5em; 107 | } 108 | .ql-editor ol li:not(.ql-direction-rtl), 109 | .ql-editor ul li:not(.ql-direction-rtl) { 110 | padding-left: 1.5em; 111 | } 112 | .ql-editor ol li.ql-direction-rtl, 113 | .ql-editor ul li.ql-direction-rtl { 114 | padding-right: 1.5em; 115 | } 116 | .ql-editor ol li { 117 | counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 118 | counter-increment: list-0; 119 | } 120 | .ql-editor ol li:before { 121 | content: counter(list-0, decimal) '. '; 122 | } 123 | .ql-editor ol li.ql-indent-1 { 124 | counter-increment: list-1; 125 | } 126 | .ql-editor ol li.ql-indent-1:before { 127 | content: counter(list-1, lower-alpha) '. '; 128 | } 129 | .ql-editor ol li.ql-indent-1 { 130 | counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; 131 | } 132 | .ql-editor ol li.ql-indent-2 { 133 | counter-increment: list-2; 134 | } 135 | .ql-editor ol li.ql-indent-2:before { 136 | content: counter(list-2, lower-roman) '. '; 137 | } 138 | .ql-editor ol li.ql-indent-2 { 139 | counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9; 140 | } 141 | .ql-editor ol li.ql-indent-3 { 142 | counter-increment: list-3; 143 | } 144 | .ql-editor ol li.ql-indent-3:before { 145 | content: counter(list-3, decimal) '. '; 146 | } 147 | .ql-editor ol li.ql-indent-3 { 148 | counter-reset: list-4 list-5 list-6 list-7 list-8 list-9; 149 | } 150 | .ql-editor ol li.ql-indent-4 { 151 | counter-increment: list-4; 152 | } 153 | .ql-editor ol li.ql-indent-4:before { 154 | content: counter(list-4, lower-alpha) '. '; 155 | } 156 | .ql-editor ol li.ql-indent-4 { 157 | counter-reset: list-5 list-6 list-7 list-8 list-9; 158 | } 159 | .ql-editor ol li.ql-indent-5 { 160 | counter-increment: list-5; 161 | } 162 | .ql-editor ol li.ql-indent-5:before { 163 | content: counter(list-5, lower-roman) '. '; 164 | } 165 | .ql-editor ol li.ql-indent-5 { 166 | counter-reset: list-6 list-7 list-8 list-9; 167 | } 168 | .ql-editor ol li.ql-indent-6 { 169 | counter-increment: list-6; 170 | } 171 | .ql-editor ol li.ql-indent-6:before { 172 | content: counter(list-6, decimal) '. '; 173 | } 174 | .ql-editor ol li.ql-indent-6 { 175 | counter-reset: list-7 list-8 list-9; 176 | } 177 | .ql-editor ol li.ql-indent-7 { 178 | counter-increment: list-7; 179 | } 180 | .ql-editor ol li.ql-indent-7:before { 181 | content: counter(list-7, lower-alpha) '. '; 182 | } 183 | .ql-editor ol li.ql-indent-7 { 184 | counter-reset: list-8 list-9; 185 | } 186 | .ql-editor ol li.ql-indent-8 { 187 | counter-increment: list-8; 188 | } 189 | .ql-editor ol li.ql-indent-8:before { 190 | content: counter(list-8, lower-roman) '. '; 191 | } 192 | .ql-editor ol li.ql-indent-8 { 193 | counter-reset: list-9; 194 | } 195 | .ql-editor ol li.ql-indent-9 { 196 | counter-increment: list-9; 197 | } 198 | .ql-editor ol li.ql-indent-9:before { 199 | content: counter(list-9, decimal) '. '; 200 | } 201 | .ql-editor .ql-indent-1:not(.ql-direction-rtl) { 202 | padding-left: 3em; 203 | } 204 | .ql-editor li.ql-indent-1:not(.ql-direction-rtl) { 205 | padding-left: 4.5em; 206 | } 207 | .ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right { 208 | padding-right: 3em; 209 | } 210 | .ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right { 211 | padding-right: 4.5em; 212 | } 213 | .ql-editor .ql-indent-2:not(.ql-direction-rtl) { 214 | padding-left: 6em; 215 | } 216 | .ql-editor li.ql-indent-2:not(.ql-direction-rtl) { 217 | padding-left: 7.5em; 218 | } 219 | .ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right { 220 | padding-right: 6em; 221 | } 222 | .ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right { 223 | padding-right: 7.5em; 224 | } 225 | .ql-editor .ql-indent-3:not(.ql-direction-rtl) { 226 | padding-left: 9em; 227 | } 228 | .ql-editor li.ql-indent-3:not(.ql-direction-rtl) { 229 | padding-left: 10.5em; 230 | } 231 | .ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right { 232 | padding-right: 9em; 233 | } 234 | .ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right { 235 | padding-right: 10.5em; 236 | } 237 | .ql-editor .ql-indent-4:not(.ql-direction-rtl) { 238 | padding-left: 12em; 239 | } 240 | .ql-editor li.ql-indent-4:not(.ql-direction-rtl) { 241 | padding-left: 13.5em; 242 | } 243 | .ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right { 244 | padding-right: 12em; 245 | } 246 | .ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right { 247 | padding-right: 13.5em; 248 | } 249 | .ql-editor .ql-indent-5:not(.ql-direction-rtl) { 250 | padding-left: 15em; 251 | } 252 | .ql-editor li.ql-indent-5:not(.ql-direction-rtl) { 253 | padding-left: 16.5em; 254 | } 255 | .ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right { 256 | padding-right: 15em; 257 | } 258 | .ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right { 259 | padding-right: 16.5em; 260 | } 261 | .ql-editor .ql-indent-6:not(.ql-direction-rtl) { 262 | padding-left: 18em; 263 | } 264 | .ql-editor li.ql-indent-6:not(.ql-direction-rtl) { 265 | padding-left: 19.5em; 266 | } 267 | .ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right { 268 | padding-right: 18em; 269 | } 270 | .ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right { 271 | padding-right: 19.5em; 272 | } 273 | .ql-editor .ql-indent-7:not(.ql-direction-rtl) { 274 | padding-left: 21em; 275 | } 276 | .ql-editor li.ql-indent-7:not(.ql-direction-rtl) { 277 | padding-left: 22.5em; 278 | } 279 | .ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right { 280 | padding-right: 21em; 281 | } 282 | .ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right { 283 | padding-right: 22.5em; 284 | } 285 | .ql-editor .ql-indent-8:not(.ql-direction-rtl) { 286 | padding-left: 24em; 287 | } 288 | .ql-editor li.ql-indent-8:not(.ql-direction-rtl) { 289 | padding-left: 25.5em; 290 | } 291 | .ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right { 292 | padding-right: 24em; 293 | } 294 | .ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right { 295 | padding-right: 25.5em; 296 | } 297 | .ql-editor .ql-indent-9:not(.ql-direction-rtl) { 298 | padding-left: 27em; 299 | } 300 | .ql-editor li.ql-indent-9:not(.ql-direction-rtl) { 301 | padding-left: 28.5em; 302 | } 303 | .ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right { 304 | padding-right: 27em; 305 | } 306 | .ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right { 307 | padding-right: 28.5em; 308 | } 309 | .ql-editor .ql-video { 310 | display: block; 311 | max-width: 100%; 312 | } 313 | .ql-editor .ql-video.ql-align-center { 314 | margin: 0 auto; 315 | } 316 | .ql-editor .ql-video.ql-align-right { 317 | margin: 0 0 0 auto; 318 | } 319 | .ql-editor .ql-bg-black { 320 | background-color: #000; 321 | } 322 | .ql-editor .ql-bg-red { 323 | background-color: #e60000; 324 | } 325 | .ql-editor .ql-bg-orange { 326 | background-color: #f90; 327 | } 328 | .ql-editor .ql-bg-yellow { 329 | background-color: #ff0; 330 | } 331 | .ql-editor .ql-bg-green { 332 | background-color: #008a00; 333 | } 334 | .ql-editor .ql-bg-blue { 335 | background-color: #06c; 336 | } 337 | .ql-editor .ql-bg-purple { 338 | background-color: #93f; 339 | } 340 | .ql-editor .ql-color-white { 341 | color: #fff; 342 | } 343 | .ql-editor .ql-color-red { 344 | color: #e60000; 345 | } 346 | .ql-editor .ql-color-orange { 347 | color: #f90; 348 | } 349 | .ql-editor .ql-color-yellow { 350 | color: #ff0; 351 | } 352 | .ql-editor .ql-color-green { 353 | color: #008a00; 354 | } 355 | .ql-editor .ql-color-blue { 356 | color: #06c; 357 | } 358 | .ql-editor .ql-color-purple { 359 | color: #93f; 360 | } 361 | .ql-editor .ql-font-serif { 362 | font-family: Georgia, Times New Roman, serif; 363 | } 364 | .ql-editor .ql-font-monospace { 365 | font-family: Monaco, Courier New, monospace; 366 | } 367 | .ql-editor .ql-size-small { 368 | font-size: 0.75em; 369 | } 370 | .ql-editor .ql-size-large { 371 | font-size: 1.5em; 372 | } 373 | .ql-editor .ql-size-huge { 374 | font-size: 2.5em; 375 | } 376 | .ql-editor .ql-direction-rtl { 377 | direction: rtl; 378 | text-align: inherit; 379 | } 380 | .ql-editor .ql-align-center { 381 | text-align: center; 382 | } 383 | .ql-editor .ql-align-justify { 384 | text-align: justify; 385 | } 386 | .ql-editor .ql-align-right { 387 | text-align: right; 388 | } 389 | .ql-editor.ql-blank::before { 390 | color: rgba(0,0,0,0.6); 391 | content: attr(data-placeholder); 392 | font-style: italic; 393 | left: 15px; 394 | pointer-events: none; 395 | position: absolute; 396 | right: 15px; 397 | } 398 | .ql-snow.ql-toolbar:after, 399 | .ql-snow .ql-toolbar:after { 400 | clear: both; 401 | content: ''; 402 | display: table; 403 | } 404 | .ql-snow.ql-toolbar button, 405 | .ql-snow .ql-toolbar button { 406 | background: none; 407 | border: none; 408 | cursor: pointer; 409 | display: inline-block; 410 | float: left; 411 | height: 24px; 412 | padding: 3px 5px; 413 | width: 28px; 414 | } 415 | .ql-snow.ql-toolbar button svg, 416 | .ql-snow .ql-toolbar button svg { 417 | float: left; 418 | height: 100%; 419 | } 420 | .ql-snow.ql-toolbar button:active:hover, 421 | .ql-snow .ql-toolbar button:active:hover { 422 | outline: none; 423 | } 424 | .ql-snow.ql-toolbar input.ql-image[type=file], 425 | .ql-snow .ql-toolbar input.ql-image[type=file] { 426 | display: none; 427 | } 428 | .ql-snow.ql-toolbar button:hover, 429 | .ql-snow .ql-toolbar button:hover, 430 | .ql-snow.ql-toolbar button:focus, 431 | .ql-snow .ql-toolbar button:focus, 432 | .ql-snow.ql-toolbar button.ql-active, 433 | .ql-snow .ql-toolbar button.ql-active, 434 | .ql-snow.ql-toolbar .ql-picker-label:hover, 435 | .ql-snow .ql-toolbar .ql-picker-label:hover, 436 | .ql-snow.ql-toolbar .ql-picker-label.ql-active, 437 | .ql-snow .ql-toolbar .ql-picker-label.ql-active, 438 | .ql-snow.ql-toolbar .ql-picker-item:hover, 439 | .ql-snow .ql-toolbar .ql-picker-item:hover, 440 | .ql-snow.ql-toolbar .ql-picker-item.ql-selected, 441 | .ql-snow .ql-toolbar .ql-picker-item.ql-selected { 442 | color: #06c; 443 | } 444 | .ql-snow.ql-toolbar button:hover .ql-fill, 445 | .ql-snow .ql-toolbar button:hover .ql-fill, 446 | .ql-snow.ql-toolbar button:focus .ql-fill, 447 | .ql-snow .ql-toolbar button:focus .ql-fill, 448 | .ql-snow.ql-toolbar button.ql-active .ql-fill, 449 | .ql-snow .ql-toolbar button.ql-active .ql-fill, 450 | .ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill, 451 | .ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill, 452 | .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill, 453 | .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill, 454 | .ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill, 455 | .ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill, 456 | .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill, 457 | .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill, 458 | .ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill, 459 | .ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill, 460 | .ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill, 461 | .ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill, 462 | .ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill, 463 | .ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill, 464 | .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, 465 | .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, 466 | .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, 467 | .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, 468 | .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, 469 | .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, 470 | .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill, 471 | .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill { 472 | fill: #06c; 473 | } 474 | .ql-snow.ql-toolbar button:hover .ql-stroke, 475 | .ql-snow .ql-toolbar button:hover .ql-stroke, 476 | .ql-snow.ql-toolbar button:focus .ql-stroke, 477 | .ql-snow .ql-toolbar button:focus .ql-stroke, 478 | .ql-snow.ql-toolbar button.ql-active .ql-stroke, 479 | .ql-snow .ql-toolbar button.ql-active .ql-stroke, 480 | .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke, 481 | .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke, 482 | .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke, 483 | .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke, 484 | .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke, 485 | .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke, 486 | .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke, 487 | .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke, 488 | .ql-snow.ql-toolbar button:hover .ql-stroke-miter, 489 | .ql-snow .ql-toolbar button:hover .ql-stroke-miter, 490 | .ql-snow.ql-toolbar button:focus .ql-stroke-miter, 491 | .ql-snow .ql-toolbar button:focus .ql-stroke-miter, 492 | .ql-snow.ql-toolbar button.ql-active .ql-stroke-miter, 493 | .ql-snow .ql-toolbar button.ql-active .ql-stroke-miter, 494 | .ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter, 495 | .ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter, 496 | .ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, 497 | .ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, 498 | .ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter, 499 | .ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter, 500 | .ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter, 501 | .ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter { 502 | stroke: #06c; 503 | } 504 | @media (pointer: coarse) { 505 | .ql-snow.ql-toolbar button:hover:not(.ql-active), 506 | .ql-snow .ql-toolbar button:hover:not(.ql-active) { 507 | color: #444; 508 | } 509 | .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill, 510 | .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill, 511 | .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill, 512 | .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill { 513 | fill: #444; 514 | } 515 | .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke, 516 | .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke, 517 | .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter, 518 | .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter { 519 | stroke: #444; 520 | } 521 | } 522 | .ql-snow { 523 | box-sizing: border-box; 524 | } 525 | .ql-snow * { 526 | box-sizing: border-box; 527 | } 528 | .ql-snow .ql-hidden { 529 | display: none; 530 | } 531 | .ql-snow .ql-out-bottom, 532 | .ql-snow .ql-out-top { 533 | visibility: hidden; 534 | } 535 | .ql-snow .ql-tooltip { 536 | position: absolute; 537 | transform: translateY(10px); 538 | } 539 | .ql-snow .ql-tooltip a { 540 | cursor: pointer; 541 | text-decoration: none; 542 | } 543 | .ql-snow .ql-tooltip.ql-flip { 544 | transform: translateY(-10px); 545 | } 546 | .ql-snow .ql-formats { 547 | display: inline-block; 548 | vertical-align: middle; 549 | } 550 | .ql-snow .ql-formats:after { 551 | clear: both; 552 | content: ''; 553 | display: table; 554 | } 555 | .ql-snow .ql-stroke { 556 | fill: none; 557 | stroke: #444; 558 | stroke-linecap: round; 559 | stroke-linejoin: round; 560 | stroke-width: 2; 561 | } 562 | .ql-snow .ql-stroke-miter { 563 | fill: none; 564 | stroke: #444; 565 | stroke-miterlimit: 10; 566 | stroke-width: 2; 567 | } 568 | .ql-snow .ql-fill, 569 | .ql-snow .ql-stroke.ql-fill { 570 | fill: #444; 571 | } 572 | .ql-snow .ql-empty { 573 | fill: none; 574 | } 575 | .ql-snow .ql-even { 576 | fill-rule: evenodd; 577 | } 578 | .ql-snow .ql-thin, 579 | .ql-snow .ql-stroke.ql-thin { 580 | stroke-width: 1; 581 | } 582 | .ql-snow .ql-transparent { 583 | opacity: 0.4; 584 | } 585 | .ql-snow .ql-direction svg:last-child { 586 | display: none; 587 | } 588 | .ql-snow .ql-direction.ql-active svg:last-child { 589 | display: inline; 590 | } 591 | .ql-snow .ql-direction.ql-active svg:first-child { 592 | display: none; 593 | } 594 | .ql-snow .ql-editor h1 { 595 | font-size: 2em; 596 | } 597 | .ql-snow .ql-editor h2 { 598 | font-size: 1.5em; 599 | } 600 | .ql-snow .ql-editor h3 { 601 | font-size: 1.17em; 602 | } 603 | .ql-snow .ql-editor h4 { 604 | font-size: 1em; 605 | } 606 | .ql-snow .ql-editor h5 { 607 | font-size: 0.83em; 608 | } 609 | .ql-snow .ql-editor h6 { 610 | font-size: 0.67em; 611 | } 612 | .ql-snow .ql-editor a { 613 | text-decoration: underline; 614 | } 615 | .ql-snow .ql-editor blockquote { 616 | border-left: 4px solid #ccc; 617 | margin-bottom: 5px; 618 | margin-top: 5px; 619 | padding-left: 16px; 620 | } 621 | .ql-snow .ql-editor code, 622 | .ql-snow .ql-editor pre { 623 | background-color: #f0f0f0; 624 | border-radius: 3px; 625 | } 626 | .ql-snow .ql-editor pre { 627 | white-space: pre-wrap; 628 | margin-bottom: 5px; 629 | margin-top: 5px; 630 | padding: 5px 10px; 631 | } 632 | .ql-snow .ql-editor code { 633 | font-size: 85%; 634 | padding: 2px 4px; 635 | } 636 | .ql-snow .ql-editor pre.ql-syntax { 637 | background-color: #23241f; 638 | color: #f8f8f2; 639 | overflow: visible; 640 | } 641 | .ql-snow .ql-editor img { 642 | max-width: 100%; 643 | } 644 | .ql-snow .ql-picker { 645 | color: #444; 646 | display: inline-block; 647 | float: left; 648 | font-size: 14px; 649 | font-weight: 500; 650 | height: 24px; 651 | position: relative; 652 | vertical-align: middle; 653 | } 654 | .ql-snow .ql-picker-label { 655 | cursor: pointer; 656 | display: inline-block; 657 | height: 100%; 658 | padding-left: 8px; 659 | padding-right: 2px; 660 | position: relative; 661 | width: 100%; 662 | } 663 | .ql-snow .ql-picker-label::before { 664 | display: inline-block; 665 | line-height: 22px; 666 | } 667 | .ql-snow .ql-picker-options { 668 | background-color: #fff; 669 | display: none; 670 | min-width: 100%; 671 | padding: 4px 8px; 672 | position: absolute; 673 | white-space: nowrap; 674 | } 675 | .ql-snow .ql-picker-options .ql-picker-item { 676 | cursor: pointer; 677 | display: block; 678 | padding-bottom: 5px; 679 | padding-top: 5px; 680 | } 681 | .ql-snow .ql-picker.ql-expanded .ql-picker-label { 682 | color: #ccc; 683 | z-index: 2; 684 | } 685 | .ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill { 686 | fill: #ccc; 687 | } 688 | .ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke { 689 | stroke: #ccc; 690 | } 691 | .ql-snow .ql-picker.ql-expanded .ql-picker-options { 692 | display: block; 693 | margin-top: -1px; 694 | top: 100%; 695 | z-index: 1; 696 | } 697 | .ql-snow .ql-color-picker, 698 | .ql-snow .ql-icon-picker { 699 | width: 28px; 700 | } 701 | .ql-snow .ql-color-picker .ql-picker-label, 702 | .ql-snow .ql-icon-picker .ql-picker-label { 703 | padding: 2px 4px; 704 | } 705 | .ql-snow .ql-color-picker .ql-picker-label svg, 706 | .ql-snow .ql-icon-picker .ql-picker-label svg { 707 | right: 4px; 708 | } 709 | .ql-snow .ql-icon-picker .ql-picker-options { 710 | padding: 4px 0px; 711 | } 712 | .ql-snow .ql-icon-picker .ql-picker-item { 713 | height: 24px; 714 | width: 24px; 715 | padding: 2px 4px; 716 | } 717 | .ql-snow .ql-color-picker .ql-picker-options { 718 | padding: 3px 5px; 719 | width: 152px; 720 | } 721 | .ql-snow .ql-color-picker .ql-picker-item { 722 | border: 1px solid transparent; 723 | float: left; 724 | height: 16px; 725 | margin: 2px; 726 | padding: 0px; 727 | width: 16px; 728 | } 729 | .ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg { 730 | position: absolute; 731 | margin-top: -9px; 732 | right: 0; 733 | top: 50%; 734 | width: 18px; 735 | } 736 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before, 737 | .ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before, 738 | .ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before, 739 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before, 740 | .ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before, 741 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before { 742 | content: attr(data-label); 743 | } 744 | .ql-snow .ql-picker.ql-header { 745 | width: 98px; 746 | } 747 | .ql-snow .ql-picker.ql-header .ql-picker-label::before, 748 | .ql-snow .ql-picker.ql-header .ql-picker-item::before { 749 | content: 'Normal'; 750 | } 751 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, 752 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { 753 | content: 'Heading 1'; 754 | } 755 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, 756 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { 757 | content: 'Heading 2'; 758 | } 759 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, 760 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { 761 | content: 'Heading 3'; 762 | } 763 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, 764 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { 765 | content: 'Heading 4'; 766 | } 767 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, 768 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { 769 | content: 'Heading 5'; 770 | } 771 | .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, 772 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { 773 | content: 'Heading 6'; 774 | } 775 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { 776 | font-size: 2em; 777 | } 778 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { 779 | font-size: 1.5em; 780 | } 781 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { 782 | font-size: 1.17em; 783 | } 784 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { 785 | font-size: 1em; 786 | } 787 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { 788 | font-size: 0.83em; 789 | } 790 | .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { 791 | font-size: 0.67em; 792 | } 793 | .ql-snow .ql-picker.ql-font { 794 | width: 108px; 795 | } 796 | .ql-snow .ql-picker.ql-font .ql-picker-label::before, 797 | .ql-snow .ql-picker.ql-font .ql-picker-item::before { 798 | content: 'Sans Serif'; 799 | } 800 | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before, 801 | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { 802 | content: 'Serif'; 803 | } 804 | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before, 805 | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { 806 | content: 'Monospace'; 807 | } 808 | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { 809 | font-family: Georgia, Times New Roman, serif; 810 | } 811 | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { 812 | font-family: Monaco, Courier New, monospace; 813 | } 814 | .ql-snow .ql-picker.ql-size { 815 | width: 98px; 816 | } 817 | .ql-snow .ql-picker.ql-size .ql-picker-label::before, 818 | .ql-snow .ql-picker.ql-size .ql-picker-item::before { 819 | content: 'Normal'; 820 | } 821 | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before, 822 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { 823 | content: 'Small'; 824 | } 825 | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before, 826 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { 827 | content: 'Large'; 828 | } 829 | .ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, 830 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { 831 | content: 'Huge'; 832 | } 833 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { 834 | font-size: 10px; 835 | } 836 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { 837 | font-size: 18px; 838 | } 839 | .ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { 840 | font-size: 32px; 841 | } 842 | .ql-snow .ql-color-picker.ql-background .ql-picker-item { 843 | background-color: #fff; 844 | } 845 | .ql-snow .ql-color-picker.ql-color .ql-picker-item { 846 | background-color: #000; 847 | } 848 | .ql-toolbar.ql-snow { 849 | border: 1px solid #ccc; 850 | box-sizing: border-box; 851 | font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; 852 | padding: 8px; 853 | } 854 | .ql-toolbar.ql-snow .ql-formats { 855 | margin-right: 15px; 856 | } 857 | .ql-toolbar.ql-snow .ql-picker-label { 858 | border: 1px solid transparent; 859 | } 860 | .ql-toolbar.ql-snow .ql-picker-options { 861 | border: 1px solid transparent; 862 | box-shadow: rgba(0,0,0,0.2) 0 2px 8px; 863 | } 864 | .ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label { 865 | border-color: #ccc; 866 | } 867 | .ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options { 868 | border-color: #ccc; 869 | } 870 | .ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected, 871 | .ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover { 872 | border-color: #000; 873 | } 874 | .ql-toolbar.ql-snow + .ql-container.ql-snow { 875 | border-top: 0px; 876 | } 877 | .ql-snow .ql-tooltip { 878 | background-color: #fff; 879 | border: 1px solid #ccc; 880 | box-shadow: 0px 0px 5px #ddd; 881 | color: #444; 882 | padding: 5px 12px; 883 | white-space: nowrap; 884 | } 885 | .ql-snow .ql-tooltip::before { 886 | content: "Visit URL:"; 887 | line-height: 26px; 888 | margin-right: 8px; 889 | } 890 | .ql-snow .ql-tooltip input[type=text] { 891 | display: none; 892 | border: 1px solid #ccc; 893 | font-size: 13px; 894 | height: 26px; 895 | margin: 0px; 896 | padding: 3px 5px; 897 | width: 170px; 898 | } 899 | .ql-snow .ql-tooltip a.ql-preview { 900 | display: inline-block; 901 | max-width: 200px; 902 | overflow-x: hidden; 903 | text-overflow: ellipsis; 904 | vertical-align: top; 905 | } 906 | .ql-snow .ql-tooltip a.ql-action::after { 907 | border-right: 1px solid #ccc; 908 | content: 'Edit'; 909 | margin-left: 16px; 910 | padding-right: 8px; 911 | } 912 | .ql-snow .ql-tooltip a.ql-remove::before { 913 | content: 'Remove'; 914 | margin-left: 8px; 915 | } 916 | .ql-snow .ql-tooltip a { 917 | line-height: 26px; 918 | } 919 | .ql-snow .ql-tooltip.ql-editing a.ql-preview, 920 | .ql-snow .ql-tooltip.ql-editing a.ql-remove { 921 | display: none; 922 | } 923 | .ql-snow .ql-tooltip.ql-editing input[type=text] { 924 | display: inline-block; 925 | } 926 | .ql-snow .ql-tooltip.ql-editing a.ql-action::after { 927 | border-right: 0px; 928 | content: 'Save'; 929 | padding-right: 0px; 930 | } 931 | .ql-snow .ql-tooltip[data-mode=link]::before { 932 | content: "Enter link:"; 933 | } 934 | .ql-snow .ql-tooltip[data-mode=formula]::before { 935 | content: "Enter formula:"; 936 | } 937 | .ql-snow .ql-tooltip[data-mode=video]::before { 938 | content: "Enter video:"; 939 | } 940 | .ql-snow a { 941 | color: #06c; 942 | } 943 | .ql-container.ql-snow { 944 | border: 1px solid #ccc; 945 | } 946 | -------------------------------------------------------------------------------- /lib/src/quill/quill.dart: -------------------------------------------------------------------------------- 1 | @JS() 2 | library quill; 3 | 4 | import "package:js/js.dart"; 5 | 6 | /// Type definitions for Quill v1.0.3 7 | /// Project: http://quilljs.com 8 | /// Definitions by: Sumit 9 | /// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 10 | 11 | // Module QuillJS 12 | @anonymous 13 | @JS() 14 | abstract class QuillOptionsStatic { 15 | external String get debug; 16 | external set debug(String v); 17 | external dynamic /*JSMap of */ get modules; 18 | external set modules(dynamic /*JSMap of */ v); 19 | external String get placeholder; 20 | external set placeholder(String v); 21 | external bool get readOnly; 22 | external set readOnly(bool v); 23 | external String get theme; 24 | external set theme(String v); 25 | external factory QuillOptionsStatic( 26 | {String debug, 27 | dynamic /*JSMap of */ modules, 28 | String placeholder, 29 | bool readOnly, 30 | String theme}); 31 | } 32 | 33 | @anonymous 34 | @JS() 35 | abstract class BoundsStatic { 36 | external num get left; 37 | external set left(num v); 38 | external num get top; 39 | external set top(num v); 40 | external num get height; 41 | external set height(num v); 42 | external num get width; 43 | external set width(num v); 44 | external factory BoundsStatic({num left, num top, num height, num width}); 45 | } 46 | 47 | @anonymous 48 | @JS() 49 | abstract class DeltaStatic { 50 | external List get ops; 51 | external set ops(List v); 52 | external dynamic get retain; 53 | external set retain(dynamic v); 54 | external dynamic get delete; 55 | external set delete(dynamic v); 56 | external dynamic get insert; 57 | external set insert(dynamic v); 58 | external dynamic get attributes; 59 | external set attributes(dynamic v); 60 | external factory DeltaStatic( 61 | {List ops, 62 | dynamic retain, 63 | dynamic delete, 64 | dynamic insert, 65 | dynamic attributes}); 66 | } 67 | 68 | @anonymous 69 | @JS() 70 | abstract class RangeStatic { 71 | // Constructors on anonymous interfaces are not yet supported. 72 | /*external factory RangeStatic();*/ 73 | external num get index; 74 | external set index(num v); 75 | external num get length; 76 | external set length(num v); 77 | } 78 | 79 | /*type sourceType = "api" | "user" | "silent";*/ 80 | @anonymous 81 | @JS() 82 | abstract class formatsType { 83 | /* Index signature is not yet supported by JavaScript interop. */ 84 | } 85 | 86 | @JS("Quill") 87 | abstract class QuillStatic { 88 | external factory QuillStatic(dynamic /*String|Element*/ container, 89 | [QuillOptionsStatic options]); 90 | external void deleteText(num start, num end, 91 | [String /*'api'|'user'|'silent'*/ source]); 92 | external void disable(); 93 | external void enable([bool enabled]); 94 | external DeltaStatic getContents([num start, num end]); 95 | external num getLength(); 96 | external String getText([num start, num end]); 97 | external void insertEmbed(num index, String type, String url, 98 | [String /*'api'|'user'|'silent'*/ source]); 99 | /*external void insertText(num index, String text, ['api'|'user'|'silent' source]);*/ 100 | /*external void insertText(num index, String text, String format, String value, ['api'|'user'|'silent' source]);*/ 101 | /*external void insertText(num index, String text, formatsType formats, ['api'|'user'|'silent' source]);*/ 102 | external void insertText(num index, String text, 103 | [String /*'api'|'user'|'silent'|String*/ source_format_formats, 104 | String /*String|'api'|'user'|'silent'*/ value_source, 105 | String /*'api'|'user'|'silent'*/ source]); 106 | /*external String pasteHTML(num index, String html, ['api'|'user'|'silent' source]);*/ 107 | /*external String pasteHTML(String html, ['api'|'user'|'silent' source]);*/ 108 | external String pasteHTML(dynamic /*num|String*/ index_html, 109 | [String /*String|'api'|'user'|'silent'*/ html_source, 110 | String /*'api'|'user'|'silent'*/ source]); 111 | external void setContents(DeltaStatic delta, 112 | [String /*'api'|'user'|'silent'*/ source]); 113 | external void setText(String text, [String /*'api'|'user'|'silent'*/ source]); 114 | external void update([String source]); 115 | external void updateContents(DeltaStatic delta, 116 | [String /*'api'|'user'|'silent'*/ source]); 117 | external void format(String name, dynamic value, 118 | [String /*'api'|'user'|'silent'*/ source]); 119 | /*external void formatLine(num index, num length, ['api'|'user'|'silent' source]);*/ 120 | /*external void formatLine(num index, num length, String format, dynamic value, ['api'|'user'|'silent' source]);*/ 121 | /*external void formatLine(num index, num length, formatsType formats, ['api'|'user'|'silent' source]);*/ 122 | external void formatLine(num index, num length, 123 | [String /*'api'|'user'|'silent'|String*/ source_format_formats, 124 | dynamic /*dynamic|'api'|'user'|'silent'*/ value_source, 125 | String /*'api'|'user'|'silent'*/ source]); 126 | /*external void formatText(num index, num length, ['api'|'user'|'silent' source]);*/ 127 | /*external void formatText(num index, num length, String format, dynamic value, ['api'|'user'|'silent' source]);*/ 128 | /*external void formatText(num index, num length, formatsType formats, ['api'|'user'|'silent' source]);*/ 129 | external void formatText(num index, num length, 130 | [String /*'api'|'user'|'silent'|String*/ source_format_formats, 131 | dynamic /*dynamic|'api'|'user'|'silent'*/ value_source, 132 | String /*'api'|'user'|'silent'*/ source]); 133 | /*external formatsType getFormat([RangeStatic range]);*/ 134 | /*external formatsType getFormat(num index, [num length]);*/ 135 | external getFormat([dynamic /*RangeStatic|num*/ range_index, num length]); 136 | external void removeFormat(num index, num length, 137 | [String /*'api'|'user'|'silent'*/ source]); 138 | external void blur(); 139 | external void focus(); 140 | external BoundsStatic getBounds(num index, [num length]); 141 | external RangeStatic getSelection([bool focus]); 142 | external bool hasFocus(); 143 | /*external void setSelection(num index, num length, ['api'|'user'|'silent' source]);*/ 144 | /*external void setSelection(RangeStatic range, ['api'|'user'|'silent' source]);*/ 145 | external void setSelection(dynamic /*num|RangeStatic*/ index_range, 146 | [dynamic /*num|'api'|'user'|'silent'*/ length_source, 147 | String /*'api'|'user'|'silent'*/ source]); 148 | external QuillStatic on(String eventName, 149 | dynamic /*VoidFunc3|(name: string, ...args: any[]) => void*/ callback); 150 | external QuillStatic once( 151 | String eventName, void callback(DeltaStatic delta, String source)); 152 | external QuillStatic off(String eventName, dynamic callback); 153 | external void debug(String level); 154 | external dynamic JS$import(String path); 155 | /*external void register(String path, dynamic def, [bool suppressWarning]);*/ 156 | /*external void register(formatsType defs, [bool suppressWarning]);*/ 157 | external void register(String path_defs, 158 | [dynamic /*dynamic|bool*/ def_suppressWarning, bool suppressWarning]); 159 | external dynamic addContainer(String className, [dynamic refNode]); 160 | external dynamic getModule(String name); 161 | } 162 | 163 | // End module QuillJS 164 | @JS() 165 | external QuillStatic get Quill; 166 | @JS() 167 | external set Quill(QuillStatic v); 168 | // Module quill 169 | /* WARNING: export assignment not yet supported. */ 170 | 171 | // End module quill 172 | -------------------------------------------------------------------------------- /lib/src/quill/quill_component.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:html' show Element; 3 | import 'dart:js_util' show jsify; 4 | 5 | import 'package:ngdart/angular.dart'; 6 | import 'package:ngforms/ngforms.dart'; 7 | import "package:js/js.dart" show allowInterop; 8 | 9 | import 'quill.dart' as quill; 10 | 11 | @Directive(selector: 'quill[ngModel]', providers: const [ 12 | const Provider(ngValueAccessor, useExisting: QuillValueAccessor) 13 | ]) 14 | class QuillValueAccessor implements ControlValueAccessor, OnDestroy { 15 | final QuillComponent _quill; 16 | late StreamSubscription _blurSub; 17 | late StreamSubscription _inputSub; 18 | 19 | TouchFunction onTouched = () {}; 20 | ChangeFunction onChange = (String _, {String rawValue=''}) {}; 21 | 22 | QuillValueAccessor(this._quill) { 23 | _inputSub = _quill.input.listen(_onInput); 24 | _blurSub = _quill.blur.listen(_onBlur); 25 | } 26 | 27 | @override 28 | ngOnDestroy() { 29 | _blurSub.cancel(); 30 | _inputSub.cancel(); 31 | } 32 | 33 | /// Write a new value to the element. 34 | @override 35 | void writeValue(String obj) { 36 | _quill.value = obj; 37 | } 38 | 39 | void _onBlur(_) { 40 | onTouched(); 41 | } 42 | 43 | void _onInput(_) { 44 | onChange(_quill.value); 45 | } 46 | 47 | /// Set the function to be called when the control receives a change event. 48 | @override 49 | void registerOnChange(ChangeFunction fn) { 50 | this.onChange = fn; 51 | } 52 | 53 | /// Set the function to be called when the control receives a touch event. 54 | @override 55 | void registerOnTouched(TouchFunction fn) { 56 | onTouched = fn; 57 | } 58 | 59 | @override 60 | void onDisabledChanged(bool isDisabled) { 61 | _quill.disabled = isDisabled; 62 | } 63 | } 64 | 65 | @Component( 66 | selector: 'quill', 67 | templateUrl: 'quill_component.html', 68 | ) 69 | class QuillComponent implements AfterContentInit, OnDestroy { 70 | quill.QuillStatic? quillEditor; 71 | 72 | @ViewChild('editor') 73 | Element? editor; 74 | 75 | String _initialValue = ''; 76 | String get value { 77 | final ed = editor!; 78 | if (ed.children.isEmpty != false) { 79 | return ''; 80 | } 81 | return ed.children.first.innerHtml ?? ''; 82 | } 83 | 84 | @Input() 85 | set value(String v) { 86 | if (quillEditor == null) { 87 | _initialValue = v; 88 | return; 89 | } 90 | quillEditor!.pasteHTML(v); 91 | } 92 | 93 | @Input() 94 | String placeholder = ''; 95 | 96 | @Input() 97 | dynamic modules = {}; 98 | 99 | bool _disabled = false; 100 | bool get disabled => _disabled; 101 | @Input() 102 | set disabled(bool v) { 103 | _disabled = v; 104 | // The editor may not have been created yet 105 | if (quillEditor != null) { 106 | quillEditor!.enable(!v); 107 | } 108 | } 109 | 110 | final StreamController _blur = new StreamController.broadcast(); 111 | @Output() 112 | Stream get blur => _blur.stream; 113 | 114 | final StreamController _focus = new StreamController(); 115 | @Output() 116 | Stream get focus => _focus.stream; 117 | 118 | final StreamController _input = new StreamController.broadcast(); 119 | @Output() 120 | Stream get input => _input.stream; 121 | 122 | var _selectionChangeSub; 123 | var _textChangeSub; 124 | 125 | @override 126 | ngAfterContentInit() { 127 | final newEditor = new quill.QuillStatic(editor, 128 | new quill.QuillOptionsStatic( 129 | theme: 'snow', 130 | placeholder: placeholder, 131 | modules: jsify(modules) 132 | ) 133 | ); 134 | 135 | _textChangeSub = allowInterop(_onTextChange); 136 | _selectionChangeSub = allowInterop(_onSelectionChange); 137 | newEditor.on('text-change', _textChangeSub); 138 | newEditor.on('selection-change', _selectionChangeSub); 139 | 140 | newEditor.enable(!_disabled); 141 | newEditor.pasteHTML(_initialValue); 142 | 143 | quillEditor = newEditor; 144 | } 145 | 146 | @override 147 | ngOnDestroy() { 148 | quillEditor!.off('text-change', _textChangeSub); 149 | quillEditor!.off('selection-change', _selectionChangeSub); 150 | 151 | // quill docs say no explicit destroy call is required. 152 | } 153 | 154 | /// Emitted when a user or API causes the selection to change, with a range representing the selection boundaries. 155 | /// 156 | /// When range changes from null value to non-null value, it indicates focus lost so we emit [blur] event. 157 | /// When range changes from non-null value to null value, it indicates gain of focus so we emit [focus] event. 158 | void _onSelectionChange(range, oldRange, String source) { 159 | if (oldRange != null && range == null) { 160 | // null range indicates blur event 161 | _blur.add(null); 162 | } else if (oldRange == null && range != null) { 163 | // change from null to non-null range indicates focus event 164 | _focus.add(null); 165 | } 166 | } 167 | 168 | /// Emitted when the contents of Quill have changed. Details of the change, representation of the editor contents 169 | /// before the change, along with the source of the change are provided. The source will be "user" if it originates from the users 170 | void _onTextChange(delta, oldDelta, source) { 171 | _input.add(value); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /lib/src/quill/quill_component.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: angular_quill 2 | description: Angular dart component for the Quill rich text editor. Quill is a free, open source WYSIWYG editor built for the modern web. 3 | version: 0.2.1 4 | homepage: https://github.com/adamlofts/angular_quill 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | 9 | dependencies: 10 | ngdart: ^8.0.0-dev.1 11 | ngforms: 12 | js: ^0.6.3 13 | 14 | dev_dependencies: 15 | -------------------------------------------------------------------------------- /test/app_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | @Tags(const ['aot']) 3 | @TestOn('browser') 4 | import 'dart:async'; 5 | 6 | 7 | import 'package:angular2/angular2.dart'; 8 | import 'package:angular_test/angular_test.dart'; 9 | import 'package:pageloader/objects.dart'; 10 | import 'package:test/test.dart'; 11 | 12 | import '../example/app_component.dart'; 13 | 14 | NgTestFixture fixture; 15 | AppPO appPO; 16 | 17 | @AngularEntrypoint() 18 | void main() { 19 | final testBed = new NgTestBed(); 20 | 21 | setUp(() async { 22 | fixture = await testBed.create(); 23 | appPO = await fixture.resolvePageObject(AppPO); 24 | }); 25 | 26 | tearDown(disposeAnyRunningTest); 27 | 28 | test('title', () async { 29 | expect(await appPO.title, 'My First AngularDart App'); 30 | }); 31 | 32 | // Testing info: https://webdev.dartlang.org/angular/guide/testing 33 | } 34 | 35 | class AppPO { 36 | @ByTagName('h1') 37 | PageLoaderElement _title; 38 | 39 | Future get title => _title.visibleText; 40 | } 41 | */ --------------------------------------------------------------------------------