├── LICENSE.md ├── README.md ├── composer.json └── src ├── EditorJsWidget.php ├── JsonToHtml.php ├── RenderBlock.php ├── actions └── UploadImageAction.php ├── assets ├── EditorJsAsset.php ├── EditorJsCdnAsset.php └── editorjs │ ├── code │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── delimiter │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── editor │ ├── editor.js │ ├── editor.js.LICENSE │ ├── editor.licenses.txt │ └── sprite.svg │ ├── embed │ ├── LICENSE.md │ ├── README.md │ └── bundle.js │ ├── header │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── image │ ├── README.md │ └── bundle.js │ ├── inline-code │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── list │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── paragraph │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── quote │ ├── LICENSE │ ├── README.md │ └── bundle.js │ ├── table │ ├── README.md │ └── bundle.js │ └── warning │ ├── LICENSE │ ├── README.md │ └── bundle.js └── behaviors └── JsonToHtmlBehavior.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2020 by Andrey Zakurdaev All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | Neither the name of Yii Software LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Editor.js Widget for Yii 2 2 | 3 | `Editor.js Widget` is a wrapper for [Editor.js](https://github.com/codex-team/editor.js), next generation block styled editor. 4 | 5 | ## Install 6 | 7 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 8 | 9 | Either run 10 | 11 | ```bash 12 | $ php composer.phar require --prefer-dist zakurdaev/yii2-editorjs-widget "*" 13 | ``` 14 | 15 | or add 16 | 17 | ```json 18 | "zakurdaev/yii2-editorjs-widget": "*" 19 | ``` 20 | 21 | to the `require` section of your `composer.json` file. 22 | 23 | 24 | ## Usage 25 | 26 | Once the extension is installed, simply use it in your code: 27 | 28 | ### Like a widget 29 | 30 | ```php 31 | echo \zakurdaev\editorjs\EditorJsWidget::widget([ 32 | 'selector' => 'redactor' 33 | ]); 34 | ``` 35 | 36 | ### Like an ActiveForm widget 37 | 38 | ```php 39 | use \zakurdaev\editorjs\EditorJsWidget; 40 | 41 | echo $form->field($model, 'content_json')->widget(EditorJsWidget::class, [ 42 | 'selectorForm' => $form->id 43 | ])->label(); 44 | ``` 45 | ### Supported block 46 | The plugin is able to support all blocks for Editor.js. You can use the standard Asset or use Asset CDN or write your own. 47 | 48 | #### EditorJsAsset 49 | Include: 50 | * editorjs/header v2.4.1 51 | * editorjs/paragraph v2.6.1 52 | * editorjs/image v2.3.4 53 | * editorjs/list v1.4.0 54 | * editorjs/table v1.2.2 55 | * editorjs/quote v2.3.0 56 | * editorjs/warning v1.1.1 57 | * editorjs/code v2.4.1 58 | * editorjs/embed v2.3.1 59 | * editorjs/delimiter v1.1.0 60 | * editorjs/inline-code v1.3.1 61 | 62 | #### Custom Asset 63 | ```php 64 | use \zakurdaev\editorjs\EditorJsWidget; 65 | 66 | echo $form->field($model, 'content_json')->widget(EditorJsWidget::class, [ 67 | 'selectorForm' => $form->id, 68 | 'assetClass' => 'YOUR/PATH/TO/ASSET' 69 | ])->label(); 70 | ``` 71 | 72 | 73 | ### Upload image by file and url 74 | 75 | Widget supports image loading for [Editor.js Image Block](https://github.com/editor-js/image). 76 | 77 | ```php 78 | // SiteController.php 79 | public function actions() 80 | { 81 | return [ 82 | 'upload-file' => [ 83 | 'class' => UploadImageAction::class, 84 | 'mode' => UploadImageAction::MODE_FILE, 85 | 'url' => 'https://example.com/upload_dir/', 86 | 'path' => '@app/web/upload_dir', 87 | 'validatorOptions' => [ 88 | 'maxWidth' => 1000, 89 | 'maxHeight' => 1000 90 | ] 91 | ], 92 | 'fetch-url' => [ 93 | 'class' => UploadImageAction::class, 94 | 'mode' => UploadImageAction::MODE_URL, 95 | 'url' => 'https://example.com/upload_dir/', 96 | 'path' => '@app/web/upload_dir' 97 | ] 98 | ]; 99 | } 100 | 101 | // view.php 102 | echo \zakurdaev\editorjs\EditorJsWidget::widget([ 103 | 'selector' => 'redactor', 104 | 'endpoints' => [ 105 | 'uploadImageByFile' => Url::to(['/site/upload-file']), 106 | 'uploadImageByUrl' => Url::to(['/site/fetch-url']), 107 | ], 108 | ]); 109 | ``` 110 | 111 | ## License 112 | The BSD License (BSD).Please see [License File](LICENSE.md) for more information. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zakurdaev/yii2-editorjs-widget", 3 | "description": "Use editor.js in form. Module for Yii2", 4 | "type": "yii2-extension", 5 | "license": "BSD-3-Clause", 6 | "version": "1.0.0", 7 | "homepage": "https://github.com/zakurdaev/yii2-editorjs-widget", 8 | "authors": [ 9 | { 10 | "name": "Andrey Zakurdaev", 11 | "email": "andrey@zakurdaev.pro" 12 | } 13 | ], 14 | "keywords": [ 15 | "editor.js", 16 | "redactor", 17 | "wysiwyg", 18 | "yii2", 19 | "yii 2", 20 | "yii2 widget" 21 | ], 22 | "support": { 23 | "issues": "https://github.com/zakurdaev/yii2-editorjs-widget/issues?state=open", 24 | "source": "https://github.com/zakurdaev/yii2-editorjs-widget" 25 | }, 26 | "require": { 27 | "php": ">=7.0", 28 | "yiisoft/yii2": "~2.0.0", 29 | "codex-team/editor.js": "*" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "zakurdaev\\editorjs\\": "src" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/EditorJsWidget.php: -------------------------------------------------------------------------------- 1 | 25 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 26 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 27 | */ 28 | class EditorJsWidget extends Widget 29 | { 30 | const ASSET_CLASS = 'zakurdaev\editorjs\assets\EditorJsAsset'; 31 | const ASSET_CDN_CLASS = 'zakurdaev\editorjs\assets\EditorJsCdnAsset'; 32 | 33 | /** 34 | * @var Model|null The data model that this widget is associated with. 35 | */ 36 | public $model; 37 | 38 | /** 39 | * @var string|null The model attribute that this widget is associated with. 40 | */ 41 | public $attribute; 42 | 43 | /** 44 | * @var string|null The input name. This must be set if `model` and `attribute` are not set. 45 | */ 46 | public $name; 47 | 48 | /** 49 | * @var string|null The input value. 50 | */ 51 | public $value; 52 | 53 | /** 54 | * @var string|null Selector pointing to textarea to initialize redactor for. 55 | * Defaults to `null` meaning that textarea does not exist yet and will be rendered by this widget. 56 | */ 57 | public $selector; 58 | 59 | /** 60 | * @var string|null Selector Form 61 | * Defaults to `null` means that the widget is launched outside the form and will have a separate save button 62 | */ 63 | public $selectorForm; 64 | 65 | /** 66 | * @var string|null Url to save editor data 67 | * $endpoints = [ 68 | 'saveJson' => '', 69 | 'uploadImageByFile' => '', 70 | 'uploadImageFetchUrl' => '' 71 | ] 72 | */ 73 | public $endpoints = []; 74 | 75 | /** 76 | * @var array The HTML attribute options for the input tag. 77 | * 78 | * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. 79 | */ 80 | public $options = []; 81 | 82 | /** 83 | * @var array {@link https://editorjs.io/configuration EditorJS Configuration} description of plug-in units. 84 | */ 85 | public $plugins = []; 86 | 87 | /** 88 | * @var array Default plugins that will be merged with {@link $plugins}. 89 | * Set Yii::$app->params['editorjs-widget/plugins'] to array in your application config params.php. 90 | * If the variable is not set, standard values will be used. 91 | */ 92 | protected $defaultPlugins; 93 | 94 | /** 95 | * @var string Asset class name 96 | */ 97 | public $assetClass = self::ASSET_CLASS; 98 | 99 | /** 100 | * @var EditorJsAsset|AssetBundle AssetBundle 101 | */ 102 | protected $assetBundle; 103 | 104 | /** 105 | * @var string String used at the beginning of tag classes and identifiers 106 | */ 107 | public $tag_prefix = 'editorjs-'; 108 | 109 | /** 110 | * @var boolean Whether to render the `textarea` or not. 111 | */ 112 | protected $renderTextarea = true; 113 | 114 | /** 115 | * @var object Set of generated HTML tags options 116 | */ 117 | protected $tags; 118 | 119 | protected function generateDefaultPlugins() 120 | { 121 | $plugins = ArrayHelper::getValue(Yii::$app->params, 'editorjs-widget/plugins'); 122 | if (is_array($plugins)) { 123 | return $plugins; 124 | } 125 | 126 | return [ 127 | 'header' => [ 128 | 'repository' => 'editorjs/header', 129 | 'class' => new JsExpression('Header'), 130 | 'inlineToolbar' => true, 131 | 'config' => ['placeholder' => 'Header', 'levels' => [2, 3, 4, 5]], 132 | 'shortcut' => 'CMD+SHIFT+H' 133 | ], 134 | 'paragraph' => [ 135 | 'repository' => 'editorjs/paragraph', 136 | 'class' => new JsExpression('Paragraph'), 137 | 'inlineToolbar' => true, 138 | ], 139 | 'image' => [ 140 | 'repository' => 'editorjs/image', 141 | 'class' => new JsExpression('ImageTool'), 142 | 'config' => [ 143 | 'field' => 'image', 144 | 'additionalRequestHeaders' => [], 145 | 'endpoints' => [ 146 | ] 147 | ] 148 | ], 149 | 'list' => [ 150 | 'repository' => 'editorjs/list', 151 | 'class' => new JsExpression('List'), 152 | 'inlineToolbar' => true, 153 | 'shortcut' => 'CMD+SHIFT+L' 154 | ], 155 | 'table' => [ 156 | 'repository' => 'editorjs/table', 157 | 'class' => new JsExpression('Table'), 158 | 'inlineToolbar' => true, 159 | 'shortcut' => 'CMD+ALT+T' 160 | ], 161 | 'quote' => [ 162 | 'repository' => 'editorjs/quote', 163 | 'class' => new JsExpression('Quote'), 164 | 'inlineToolbar' => true, 165 | 'config' => ['quotePlaceholder' => 'Quote', 'captionPlaceholder' => 'Author'], 166 | 'shortcut' => 'CMD+SHIFT+O' 167 | ], 168 | 'warning' => [ 169 | 'repository' => 'editorjs/warning', 170 | 'class' => new JsExpression('Warning'), 171 | 'inlineToolbar' => true, 172 | 'config' => ['titlePlaceholder' => 'Title', 'messagePlaceholder' => 'Description'], 173 | 'shortcut' => 'CMD+SHIFT+W' 174 | ], 175 | 'code' => [ 176 | 'repository' => 'editorjs/code', 177 | 'class' => new JsExpression('CodeTool'), 178 | 'shortcut' => 'CMD+SHIFT+C' 179 | ], 180 | 'embed' => [ 181 | 'repository' => 'editorjs/embed', 182 | 'class' => new JsExpression('Embed') 183 | ], 184 | 'delimiter' => [ 185 | 'repository' => 'editorjs/delimiter', 186 | 'class' => new JsExpression('Delimiter') 187 | ], 188 | 'inline-code' => [ 189 | 'repository' => 'editorjs/inline-code', 190 | 'class' => new JsExpression('InlineCode'), 191 | 'shortcut' => 'CMD+SHIFT+C' 192 | ] 193 | ]; 194 | } 195 | 196 | /** 197 | * @inheritdoc 198 | * @throws InvalidConfigException 199 | */ 200 | public function init() 201 | { 202 | if (!$this->hasModel() && $this->selector === null && $this->name === null) { 203 | throw new InvalidConfigException("Either 'name', or 'selector', or 'model' and 'attribute' properties must be specified."); 204 | } elseif ($this->hasModel() && ($this->selector !== null || $this->name !== null)) { 205 | throw new InvalidConfigException("'selector' or 'name' parameters cannot be used with parameters 'model' and 'attribute'"); 206 | } elseif ($this->selector !== null && ($this->hasModel() || $this->name !== null)) { 207 | throw new InvalidConfigException("'name' or 'model' or 'attribute' parameters cannot be used with parameter 'selector'"); 208 | } elseif ($this->name !== null && ($this->hasModel() || $this->selector !== null)) { 209 | throw new InvalidConfigException("'selector' or 'model' or 'attribute' parameters cannot be used with parameter 'name'"); 210 | } 211 | 212 | try { 213 | $this->assetBundle = Yii::$container->get($this->assetClass); 214 | } catch (InvalidConfigException $e) { 215 | throw new InvalidConfigException("'assetClass' does not contain a class name"); 216 | } 217 | 218 | $this->renderTextarea = $this->hasModel() || $this->selector === null; 219 | 220 | if ($this->hasModel()) { 221 | $this->value = JSON::decode(Html::getAttributeValue($this->model, $this->attribute)); 222 | $this->selector = Html::getInputId($this->model, $this->attribute); 223 | } 224 | 225 | if ($this->selector === null) { 226 | $this->selector = $this->getId(); 227 | } 228 | $this->options['id'] = $this->selector; 229 | 230 | $this->defaultPlugins = $this->generateDefaultPlugins(); 231 | if (empty($this->plugins)) { 232 | $this->plugins = $this->defaultPlugins; 233 | } 234 | foreach ($this->plugins as $key => $config) { 235 | if (is_string($config)) { 236 | unset($this->plugins[$key]); 237 | $key = $config; 238 | $config = []; 239 | } 240 | $defaultConfig = ArrayHelper::getValue($this->defaultPlugins, $key, []); 241 | $this->plugins[$key] = $this->buildPluginConfig($config, $defaultConfig); 242 | } 243 | 244 | $this->tags = (object)[ 245 | 'form' => [ 246 | 'id' => $this->selectorForm, 247 | 'class' => '', 248 | ], 249 | 'textarea' => [ 250 | 'id' => $this->selector, 251 | 'class' => '', 252 | ], 253 | 'wrapper' => [ 254 | 'id' => $this->tag_prefix . 'wrap-' . $this->selector, 255 | 'class' => $this->tag_prefix . 'wrap', 256 | ], 257 | 'editor' => [ 258 | 'id' => $this->tag_prefix . $this->selector, 259 | 'class' => $this->tag_prefix . 'editor', 260 | ], 261 | 'saveButton' => [ 262 | 'id' => $this->tag_prefix . 'save-' . $this->selector, 263 | 'class' => $this->tag_prefix . 'save', 264 | ] 265 | ]; 266 | 267 | parent::init(); 268 | } 269 | 270 | /** 271 | * @inheritdoc 272 | */ 273 | public function run() 274 | { 275 | $this->registerClientScripts(); 276 | 277 | $redactor = Html::tag('div', '', $this->tags->editor); 278 | 279 | if ($this->selectorForm === null) { 280 | $redactor .= Html::tag('button', 'Save', $this->tags->saveButton); 281 | } 282 | 283 | $textarea = ''; 284 | if ($this->renderTextarea === true) { 285 | if ($this->hasModel()) { 286 | $textarea = Html::activeTextarea($this->model, $this->attribute, $this->options); 287 | } else { 288 | $textarea = Html::textarea($this->name, $this->value, $this->options); 289 | } 290 | $textarea = Html::tag('div', $textarea, ['style' => 'display:none']); 291 | } 292 | 293 | return Html::tag('div', $redactor, $this->tags->wrapper) . $textarea; 294 | } 295 | 296 | /** 297 | * @return boolean whether this widget is associated with a data model. 298 | */ 299 | protected function hasModel() 300 | { 301 | return $this->model instanceof Model && $this->attribute !== null; 302 | } 303 | 304 | protected function pluginRepositories(&$plugins, $remove = false) 305 | { 306 | $name = 'repository'; 307 | $result = []; 308 | foreach ($plugins as &$element) { 309 | $result[] = ArrayHelper::getValue($element, $name); 310 | if ($remove) { 311 | unset($element[$name]); 312 | } 313 | } 314 | 315 | return $result; 316 | } 317 | 318 | protected function buildPluginConfig($config, $defaultConfig) { 319 | $config = ArrayHelper::merge($defaultConfig, $config); 320 | $repository = ArrayHelper::getValue($config, 'repository'); 321 | 322 | if ($repository == 'editorjs/image') { 323 | if (($request = Yii::$app->getRequest())->enableCsrfValidation) { 324 | $additionalRequestData = ArrayHelper::getValue($config, ['config', 'additionalRequestHeaders'], []); 325 | if (!array_key_exists(Request::CSRF_HEADER, $additionalRequestData)) { 326 | $config['config']['additionalRequestHeaders'][Request::CSRF_HEADER] = $request->getCsrfToken(); 327 | } 328 | } 329 | if ($byFile = ArrayHelper::getValue($this->endpoints, 'uploadImageByFile')) { 330 | if (!is_array($config['config']['endpoints'])) { 331 | $config['config']['endpoints'] = []; 332 | } 333 | $config['config']['endpoints']['byFile'] = $byFile; 334 | } 335 | if ($byUrl = ArrayHelper::getValue($this->endpoints, 'uploadImageByUrl')) { 336 | if (!is_array($config['config']['endpoints'])) { 337 | $config['config']['endpoints'] = []; 338 | } 339 | $config['config']['endpoints']['byUrl'] = $byUrl; 340 | } 341 | } 342 | 343 | return $config; 344 | } 345 | 346 | /** 347 | * Register widget asset. 348 | */ 349 | protected function registerClientScripts() 350 | { 351 | $plugins = $this->plugins; 352 | $repositories = $this->pluginRepositories($plugins, true); 353 | 354 | $view = $this->getView(); 355 | $asset = $this->assetBundle::register($view); 356 | $asset->addPlugins($repositories); 357 | 358 | $plugins = !empty($this->plugins) ? Json::encode($plugins) : '{}'; 359 | 360 | $js = " 361 | const input = $('#" . $this->tags->textarea['id']. "'); 362 | const val = (input.length === 0 || input.val() === '') ? null : JSON.parse(input.val()); 363 | const editor = new EditorJS({ 364 | holder : '" . $this->tags->editor['id']. "', 365 | tools: " . $plugins . ", 366 | data: val 367 | });"; 368 | 369 | // todo: refine the situation with sending data somewhere 370 | if ($this->selectorForm !== null) { 371 | $js .= " 372 | const element = $('#" . $this->tags->form['id'] . "'); 373 | const event = 'beforeValidate'; 374 | "; 375 | } else { 376 | $js .= " 377 | const element = $('" . $this->tags->saveButton['id'] . "'); 378 | const event = 'click'; 379 | "; 380 | } 381 | $js .= " 382 | element.on(event, function (e) { 383 | return editor.save().then((outputData, valid) => { 384 | input.val(JSON.stringify(outputData, null)); 385 | return true; 386 | }).catch((error) => { 387 | alert('EditorJS error'); 388 | return false; 389 | }); 390 | }) 391 | "; 392 | $view->registerJs($js); 393 | } 394 | } -------------------------------------------------------------------------------- /src/JsonToHtml.php: -------------------------------------------------------------------------------- 1 | 16 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 17 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 18 | */ 19 | class JsonToHtml extends BaseObject 20 | { 21 | const RENDER_CLASS = 'zakurdaev\editorjs\RenderBlock'; 22 | 23 | /** 24 | * @var array|string raw data EditorJS blocks 25 | */ 26 | public $value; 27 | 28 | /** 29 | * @var array {@link https://github.com/editor-js/editorjs-php EditorJS PHP Configuration} validation rules for different types of Editor.js tools. 30 | * Set default value in Yii::$app->params['editorjs-widget/rules'] to array in your application config params.php and use global settings 31 | * If the variable is not set, standard values will be used. 32 | */ 33 | public $configuration; 34 | 35 | /** 36 | * @var string Render class name 37 | */ 38 | public $renderClass = self::RENDER_CLASS; 39 | 40 | public function init() 41 | { 42 | if (!is_string($this->value)) { 43 | $this->value = Json::encode($this->value); 44 | } 45 | if (empty($this->configuration)) { 46 | $this->configuration = ArrayHelper::getValue(Yii::$app->params, 'editorjs-widget/rules'); 47 | } 48 | if (!is_string($this->configuration) && !is_null($this->configuration)) { 49 | $this->configuration = Json::encode($this->configuration); 50 | } 51 | } 52 | 53 | public function getBlocks() 54 | { 55 | if (empty($this->configuration)) { 56 | return ArrayHelper::getValue(Json::decode($this->value), 'blocks', []); 57 | } 58 | return (new EditorJS($this->value, $this->configuration))->getBlocks(); 59 | } 60 | 61 | public function run() 62 | { 63 | $render = Yii::$container->get($this->renderClass); 64 | 65 | $html = ''; 66 | foreach ($this->blocks as $block) { 67 | $type = ArrayHelper::getValue($block, 'type', ''); 68 | $data = ArrayHelper::getValue($block, 'data', []); 69 | if (!method_exists($render, $type)) { 70 | continue; 71 | } 72 | 73 | $html .= $render::{$type}($data); 74 | } 75 | 76 | return $html; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/RenderBlock.php: -------------------------------------------------------------------------------- 1 | 11 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 12 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 13 | */ 14 | class RenderBlock 15 | { 16 | public static function header(array $data) 17 | { 18 | $level = (int)ArrayHelper::getValue($data, 'level', 2); 19 | $text = (string)ArrayHelper::getValue($data, 'text', ''); 20 | 21 | return Html::tag('h' . $level, $text); 22 | } 23 | 24 | public static function paragraph(array $data) 25 | { 26 | $text = (string)ArrayHelper::getValue($data, 'text', ''); 27 | 28 | return Html::tag('p', $text); 29 | } 30 | 31 | public static function image(array $data) 32 | { 33 | $stretched = (boolean)ArrayHelper::getValue($data, 'stretched', false); 34 | $withBorder = (boolean)ArrayHelper::getValue($data, 'withBorder', false); 35 | $withBackground = (boolean)ArrayHelper::getValue($data, 'withBackground', false); 36 | $caption = (string)ArrayHelper::getValue($data, 'caption', ''); 37 | $file = (object)ArrayHelper::getValue($data, 'file', ['url' => '']); 38 | 39 | $options = [ 40 | 'class' => 'image', 41 | 'alt' => $caption, 42 | 'title' => $caption 43 | ]; 44 | if ($stretched && !$withBackground) { 45 | $options['class'] .= ' stretched'; 46 | } 47 | if ($withBackground) { 48 | $options['class'] .= ' with-background'; 49 | } 50 | if ($withBorder) { 51 | $options['class'] .= ' with-border'; 52 | } 53 | 54 | if (isset($file->url)) { 55 | $options['src'] = $file->url; 56 | return Html::tag('img', '', $options); 57 | } 58 | return ''; 59 | } 60 | 61 | public static function list(array $data) 62 | { 63 | $style = (string)ArrayHelper::getValue($data, 'style', 'ordered'); 64 | $items = (array)ArrayHelper::getValue($data, 'items', []); 65 | $tag = $style == 'ordered' ? 'ol' : 'ul'; 66 | 67 | $content = ''; 68 | foreach ($items as $item) { 69 | $content .= Html::tag('li', $item); 70 | } 71 | return Html::tag($tag, $content); 72 | } 73 | 74 | public static function table(array $data) 75 | { 76 | $rows = (array)ArrayHelper::getValue($data, 'content', []); 77 | 78 | $content = ''; 79 | foreach ($rows as $row) { 80 | $temp = ''; 81 | foreach ($row as $cell) { 82 | $temp .= Html::tag('td', $cell); 83 | } 84 | $content .= Html::tag('tr', $temp); 85 | } 86 | return Html::tag('table', $content); 87 | } 88 | 89 | public static function quote(array $data) 90 | { 91 | $alignment = (string)ArrayHelper::getValue($data, 'alignment', ''); 92 | $caption = (string)ArrayHelper::getValue($data, 'caption', ''); 93 | $text = (string)ArrayHelper::getValue($data, 'text', ''); 94 | 95 | if ($caption) { 96 | $caption = Html::tag('cite', $caption); 97 | } 98 | $class = !empty($alignment) ? 'align-' . $alignment : ''; 99 | 100 | return Html::tag('blockquote', $text . $caption, ['class' => $class]); 101 | } 102 | 103 | 104 | public static function warning(array $data) 105 | { 106 | $title = (string)ArrayHelper::getValue($data, 'title', ''); 107 | $message = (string)ArrayHelper::getValue($data, 'message', ''); 108 | 109 | $message = Html::tag('div', $message, ['class' => 'message']); 110 | if (!empty($title)) { 111 | $title = Html::tag('div', $title, ['class' => 'title']); 112 | } 113 | 114 | return Html::tag('div', $title . $message, ['class' => 'alert']); 115 | } 116 | 117 | public static function code(array $data) 118 | { 119 | $code = (string)ArrayHelper::getValue($data, 'code', ''); 120 | return Html::tag('code', $code); 121 | } 122 | 123 | public static function embed(array $data) 124 | { 125 | $service = (string)ArrayHelper::getValue($data, 'service', ''); 126 | $caption = (string)ArrayHelper::getValue($data, 'caption', ''); 127 | $embed = (string)ArrayHelper::getValue($data, 'embed', ''); 128 | 129 | if (!empty($caption)) { 130 | $caption = Html::tag('div', $caption, ['class' => 'caption']); 131 | } 132 | $iframe = Html::tag('iframe', '', [ 133 | 'src' => $embed, 134 | 'allow' => 'autoplay', 135 | 'allowfullscreen' => 'allowfullscreen' 136 | ]); 137 | 138 | return Html::tag('div', $iframe . $caption, ['class' => 'embed ' . $service]); 139 | } 140 | 141 | public static function delimiter(array $data) 142 | { 143 | return Html::tag('div', '', ['class' => 'delimiter']); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/actions/UploadImageAction.php: -------------------------------------------------------------------------------- 1 | [ 29 | * 'class' => UploadImageAction::class, 30 | * 'mode' => UploadImageAction::MODE_FILE, 31 | * 'url' => 'https://example.com/upload_dir/', 32 | * 'path' => '@app/web/upload_dir', 33 | * 'validatorOptions' => [ 34 | * 'maxWidth' => 1000, 35 | * 'maxHeight' => 1000 36 | * ] 37 | * ], 38 | * 'fetch-url' => [ 39 | * 'class' => UploadImageAction::class, 40 | * 'mode' => UploadImageAction::MODE_URL, 41 | * 'url' => 'https://example.com/upload_dir/', 42 | * 'path' => '@app/web/upload_dir', 43 | * 'validatorOptions' => [ 44 | * 'maxWidth' => 1000, 45 | * 'maxHeight' => 1000 46 | * ] 47 | * ] 48 | * ]; 49 | * } 50 | * ``` 51 | * 52 | * @author Andrey Zakurdaev 53 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 54 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 55 | */ 56 | class UploadImageAction extends Action 57 | { 58 | const MODE_FILE = 'file'; 59 | const MODE_URL = 'url'; 60 | 61 | /** 62 | * @var string Path to directory where files will be uploaded. 63 | */ 64 | public $path; 65 | 66 | /** 67 | * @var string URL path to directory where files will be uploaded. 68 | */ 69 | public $url; 70 | 71 | /** 72 | * @var string Variable's name that EditorJs sent image upload. 73 | */ 74 | public $mode = self::MODE_FILE; 75 | 76 | /** 77 | * @var string Variable's name that EditorJs sent image upload. 78 | */ 79 | public $param; 80 | 81 | /** 82 | * @var boolean If `true` unique string will be added to the file name 83 | */ 84 | public $unique = true; 85 | 86 | /** 87 | * @var boolean If `true` file will be replaced 88 | */ 89 | public $replace = false; 90 | 91 | /** 92 | * @var array Model validator options. 93 | */ 94 | public $validatorOptions = []; 95 | 96 | /** 97 | * @inheritdoc 98 | * @throws InvalidConfigException|Exception 99 | */ 100 | public function init() 101 | { 102 | if ($this->url === null) { 103 | throw new InvalidConfigException('The "url" attribute must be set.'); 104 | } else { 105 | $this->url = rtrim($this->url, '/') . '/'; 106 | } 107 | if ($this->path === null) { 108 | throw new InvalidConfigException('The "path" attribute must be set.'); 109 | } else { 110 | $this->path = rtrim(Yii::getAlias($this->path), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 111 | 112 | if (!FileHelper::createDirectory($this->path)) { 113 | throw new InvalidCallException("Directory specified in 'path' attribute doesn't exist or cannot be created."); 114 | } 115 | } 116 | if ($this->param === null) { 117 | $this->param = $this->mode == self::MODE_URL ? 'url' : 'image'; 118 | } 119 | } 120 | 121 | public function run() 122 | { 123 | if (Yii::$app->request->isPost) { 124 | Yii::$app->response->format = Response::FORMAT_JSON; 125 | 126 | if ($this->mode == self::MODE_URL) { 127 | $body = Json::decode(Yii::$app->request->rawBody); 128 | $file = $this->uploadedFileByUrl(ArrayHelper::getValue($body, $this->param, '')); 129 | } else { 130 | $file = UploadedFile::getInstanceByName($this->param); 131 | } 132 | 133 | $model = new DynamicModel(['file' => $file]); 134 | $model 135 | ->addRule('file', 'required') 136 | ->addRule('file', 'image', $this->validatorOptions) 137 | ->validate(); 138 | 139 | if ($file->hasError) { 140 | return [ 141 | 'success' => 0, 142 | 'error' => 'File upload error' 143 | ]; 144 | } else if ($model->hasErrors()) { 145 | return [ 146 | 'success' => 0, 147 | 'error' => $model->getFirstError('file'), 148 | ]; 149 | } else { 150 | $originalFileName = $model->file->name; 151 | if ($model->file->extension) { 152 | $model->file->name = Inflector::slug($model->file->baseName) . '.' . $model->file->extension; 153 | if ($this->unique === true) { 154 | $model->file->name = uniqid() . '-' . $model->file->name; 155 | } 156 | } 157 | 158 | if (file_exists($this->path . $model->file->name) && $this->replace === false) { 159 | return [ 160 | 'success' => 0, 161 | 'error' => 'File already exist' 162 | ]; 163 | } 164 | 165 | if ($model->file->saveAs($this->path . $model->file->name)) { 166 | return [ 167 | 'success' => 1, 168 | 'file' => [ 169 | "url" => $this->url . $model->file->name, 170 | 'originalFileName' => $originalFileName 171 | ] 172 | ]; 173 | } 174 | } 175 | 176 | return [ 177 | 'success' => 0, 178 | 'error' => 'File can not upload' 179 | ]; 180 | } else { 181 | throw new BadRequestHttpException('Only POST is allowed'); 182 | } 183 | } 184 | 185 | protected function uploadedFileByUrl($url) 186 | { 187 | if (empty($url)) { 188 | $options['error'] = UPLOAD_ERR_NO_FILE; 189 | return new UploadedFile($options); 190 | } 191 | 192 | $parsed_url = parse_url($url); 193 | $headers = get_headers($url, 1); 194 | 195 | if (!$parsed_url || !$headers || !preg_match('/^(HTTP)(.*)(200)(.*)/i', $headers[0])) { 196 | $options['error'] = UPLOAD_ERR_NO_FILE; 197 | return new UploadedFile($options); 198 | } 199 | 200 | $options['name'] = isset($parsed_url['path']) ? pathinfo($parsed_url['path'], PATHINFO_BASENAME) : ''; 201 | $options['size'] = isset($headers['Content-Length']) ? $headers['Content-Length'] : 0; 202 | $options['type'] = isset($headers['Content-Type']) ? $headers['Content-Type'] : FileHelper::getMimeTypeByExtension($options['name']); 203 | 204 | $tempName = tempnam(sys_get_temp_dir(), 'php'); 205 | if (!$tempName) { 206 | $options['error'] = UPLOAD_ERR_NO_TMP_DIR; 207 | return new UploadedFile($options); 208 | } 209 | register_shutdown_function(function () use ($tempName) { 210 | if (file_exists($tempName)) { 211 | unlink($tempName); 212 | } 213 | }); 214 | 215 | $tempResource = fopen($tempName, 'r+'); 216 | $curl = curl_init($url); 217 | curl_setopt_array($curl, [ 218 | CURLOPT_FILE => $tempResource, 219 | CURLOPT_FAILONERROR => true, 220 | CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, 221 | ]); 222 | curl_exec($curl); 223 | curl_close($curl); 224 | 225 | $options['tempResource'] = $tempResource; 226 | $options['tempName'] = $tempName; 227 | 228 | return new UploadedFile($options); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/assets/EditorJsAsset.php: -------------------------------------------------------------------------------- 1 | 11 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 12 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 13 | */ 14 | class EditorJsAsset extends AssetBundle 15 | { 16 | public $sourcePath = __DIR__; 17 | 18 | protected $validPlugins = [ 19 | 'editorjs/header', 20 | 'editorjs/paragraph', 21 | 'editorjs/image', 22 | 'editorjs/list', 23 | 'editorjs/table', 24 | 'editorjs/quote', 25 | 'editorjs/warning', 26 | 'editorjs/code', 27 | 'editorjs/embed', 28 | 'editorjs/delimiter', 29 | 'editorjs/inline-code' 30 | ]; 31 | 32 | public $css = [ 33 | ]; 34 | 35 | public $js = [ 36 | 'editorjs/editor/editor.js', 37 | ]; 38 | 39 | public $depends = [ 40 | ]; 41 | 42 | public function addPlugins(array $plugins) 43 | { 44 | $plugins = array_intersect($this->validPlugins, $plugins); 45 | foreach ($plugins as $plugin) { 46 | $this->js[$plugin] = $plugin . '/bundle.js'; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/assets/EditorJsCdnAsset.php: -------------------------------------------------------------------------------- 1 | 11 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 12 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 13 | */ 14 | class EditorJsCdnAsset extends AssetBundle 15 | { 16 | public $css = [ 17 | ]; 18 | 19 | public $js = [ 20 | ]; 21 | 22 | public $depends = [ 23 | ]; 24 | 25 | public function addBlocks(array $plugins) 26 | { 27 | foreach ($plugins as $plugin) { 28 | $this->js[$plugin] = 'https://cdn.jsdelivr.net/npm/@' . $plugin . '@latest'; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/editorjs/code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/editorjs/code/README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # Code Tool for Editor.js 4 | 5 | Code Tool for the [Editor.js](https://ifmo.su/editor) allows to include code examples in your articles. 6 | 7 | ![](https://capella.pics/8df022f5-b4d5-4d30-a527-2a0efb63f291.jpg) 8 | 9 | ## Installation 10 | 11 | ### Install via NPM 12 | 13 | Get the package 14 | 15 | ```shell 16 | npm i --save-dev @editorjs/code 17 | ``` 18 | 19 | Include module at your application 20 | 21 | ```javascript 22 | const CodeTool = require('@editorjs/code'); 23 | ``` 24 | 25 | ### Download to your project's source dir 26 | 27 | 1. Upload folder `dist` from repository 28 | 2. Add `dist/bundle.js` file to your page. 29 | 30 | ### Load from CDN 31 | 32 | You can load specific version of package from [jsDelivr CDN](https://www.jsdelivr.com/package/npm/@editorjs/code). 33 | 34 | `https://cdn.jsdelivr.net/npm/@editorjs/code@2.0.0` 35 | 36 | Require this script on a page with Editor.js. 37 | 38 | ```html 39 | 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the Editor.js initial config. 45 | 46 | ```javascript 47 | var editor = EditorJS({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | code: CodeTool, 53 | } 54 | 55 | ... 56 | }); 57 | ``` 58 | 59 | ## Config Params 60 | 61 | | Field | Type | Description | 62 | | ----------- | -------- | -------------------------------| 63 | | placeholder | `string` | Code Tool's placeholder string | 64 | 65 | ## Output data 66 | 67 | This Tool returns code. 68 | 69 | ```json 70 | { 71 | "type" : "code", 72 | "data" : { 73 | "code": "body {\n font-size: 14px;\n line-height: 16px;\n}", 74 | } 75 | } 76 | ``` 77 | 78 | -------------------------------------------------------------------------------- /src/assets/editorjs/code/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodeTool=t():e.CodeTool=t()}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}([function(e,t,n){function r(e,t){for(var n=0;n ',title:"Code"}}},{key:"DEFAULT_PLACEHOLDER",get:function(){return"Enter code"}},{key:"pasteConfig",get:function(){return{tags:["pre"]}}}]),e}();e.exports=i},function(e,t,n){var r=n(2);"string"==typeof r&&(r=[[e.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(4)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(3)(!1)).push([e.i,".ce-code__textarea {\n min-height: 200px;\n font-family: Menlo, Monaco, Consolas, Courier New, monospace;\n color: #41314e;\n line-height: 1.6em;\n font-size: 12px;\n background: #f8f7fa;\n border: 1px solid #f1f1f4;\n box-shadow: none;\n white-space: pre;\n word-wrap: normal;\n overflow-x: auto;\n resize: vertical;\n}\n",""])},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=function(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"==typeof btoa){var o=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),i=r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"});return[n].concat(i).concat([o]).join("\n")}var a;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},o=0;o=0&&f.splice(t,1)}function b(e){var t=document.createElement("style");return void 0===e.attrs.type&&(e.attrs.type="text/css"),y(t,e.attrs),h(e,t),t}function y(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function m(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var a=u++;n=c||(c=b(t)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",y(t,e.attrs),h(e,t),t}(t),r=function(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=l(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,t),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=b(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=a()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=p(e,t);return d(n,t),function(e){for(var r=[],o=0;o 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the Editor.js initial config. 45 | 46 | ```javascript 47 | var editor = EditorJS({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | delimiter: Delimiter, 53 | } 54 | 55 | ... 56 | }); 57 | ``` 58 | 59 | ## Config Params 60 | 61 | This Tool has no config params 62 | 63 | ## Output data 64 | 65 | This Tool returns empty object. 66 | 67 | ```json 68 | { 69 | "type" : "delimiter", 70 | "data" : {} 71 | } 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /src/assets/editorjs/delimiter/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Delimiter=t():e.Delimiter=t()}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}([function(e,t,n){function r(e,t){for(var n=0;n',title:"Delimiter"}}}]),e}();e.exports=i},function(e,t,n){var r=n(2);"string"==typeof r&&(r=[[e.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(4)(r,o);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(3)(!1)).push([e.i,'.ce-delimiter {\n line-height: 1.6em;\n width: 100%;\n text-align: center;\n}\n\n.ce-delimiter:before {\n display: inline-block;\n content: "***";\n font-size: 30px;\n line-height: 65px;\n height: 30px;\n letter-spacing: 0.2em;\n}',""])},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=function(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"==typeof btoa){var o=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),i=r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"});return[n].concat(i).concat([o]).join("\n")}var a;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},o=0;o=0&&f.splice(t,1)}function b(e){var t=document.createElement("style");return void 0===e.attrs.type&&(e.attrs.type="text/css"),m(t,e.attrs),h(e,t),t}function m(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function y(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var a=c++;n=u||(u=b(t)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",m(t,e.attrs),h(e,t),t}(t),r=function(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=l(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,t),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=b(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=a()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=d(e,t);return p(n,t),function(e){for(var r=[],o=0;o 8 | * 9 | * @uses html-janitor 10 | * @licence Apache-2.0 (https://github.com/guardian/html-janitor/blob/master/LICENSE) 11 | */ 12 | 13 | /** 14 | * If developer uses editor's API, then he can customize sanitize restrictions. 15 | * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere 16 | * At least, if there is no config overrides, that API uses Default configuration 17 | * 18 | * @see {@link https://www.npmjs.com/package/html-janitor} 19 | * @license Apache-2.0 20 | * @see {@link https://github.com/guardian/html-janitor/blob/master/LICENSE} 21 | * 22 | * @param {SanitizerConfig} config - sanitizer extension 23 | */ 24 | 25 | /** 26 | * Editor.js 27 | * 28 | * Short Description (눈_눈;) 29 | * 30 | * @version 2.18.0 31 | * 32 | * @license Apache-2.0 33 | * @author CodeX-Team 34 | */ 35 | 36 | /** 37 | * Base Paragraph Block for the Editor.js. 38 | * Represents simple paragraph 39 | * 40 | * @author CodeX (team@codex.so) 41 | * @copyright CodeX 2018 42 | * @license The MIT License (MIT) 43 | */ 44 | 45 | /*! 46 | * Codex JavaScript Notification module 47 | * https://github.com/codex-team/js-notifier 48 | */ 49 | 50 | /*! 51 | * Library for handling keyboard shortcuts 52 | * @copyright CodeX (https://codex.so) 53 | * @license MIT 54 | * @author CodeX (https://codex.so) 55 | * @version 1.1.1 56 | */ 57 | 58 | /*! 59 | * CodeX.Tooltips 60 | * 61 | * @version 1.0.0 62 | * 63 | * @licence MIT 64 | * @author CodeX 65 | * 66 | * 67 | */ 68 | -------------------------------------------------------------------------------- /src/assets/editorjs/editor/sprite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/assets/editorjs/embed/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/editorjs/embed/README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # Embed Tool 4 | 5 | Provides Block tool for embedded content for the [Editor.js](https://editorjs.io). 6 | Tool uses Editor.js pasted patterns handling and inserts iframe with embedded content. 7 | 8 | ## Installation 9 | 10 | ### Install via NPM 11 | 12 | Get the package 13 | 14 | ```shell 15 | npm i --save-dev @editorjs/embed 16 | ``` 17 | 18 | Include module at your application 19 | 20 | ```javascript 21 | const Embed = require('@editorjs/embed'); 22 | ``` 23 | 24 | ### Download to your project's source dir 25 | 26 | 1. Upload folder `dist` from repository 27 | 2. Add `dist/bundle.js` file to your page. 28 | 29 | ### Load from CDN 30 | You can load specific version of package from [jsDelivr CDN](https://www.jsdelivr.com/package/npm/@editorjs/embed). 31 | 32 | `https://cdn.jsdelivr.net/npm/@editorjs/embed@latest` 33 | 34 | Then require this script on page with Editor.js. 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | ## Usage 41 | 42 | Add a new Tool to the `tools` property of the Editor.js initial config. 43 | 44 | ```javascript 45 | var editor = EditorJS({ 46 | ... 47 | 48 | tools: { 49 | ... 50 | embed: Embed, 51 | }, 52 | 53 | ... 54 | }); 55 | ``` 56 | 57 | ## Available configuration 58 | 59 | Embed Tool supports some services by default (see the full list [here](docs/services.md)). You can specify services you would like to use: 60 | 61 | ```javascript 62 | var editor = EditorJS({ 63 | ... 64 | 65 | tools: { 66 | ... 67 | embed: { 68 | class: Embed, 69 | config: { 70 | services: { 71 | youtube: true, 72 | coub: true 73 | } 74 | } 75 | }, 76 | }, 77 | 78 | ... 79 | }); 80 | ``` 81 | 82 | > Note that if you pass services you want to use like in the example above, others will not be enabled. 83 | 84 | Also you can provide your own services using simple configuration. 85 | 86 | 87 | First of all you should create a Service configuration object. It contains following fields: 88 | 89 | | Field | Type | Description | 90 | | ---------- | ---------- | ----------- | 91 | | `regex` | `RegExp` | Pattern of pasted URLs. You should use regexp groups to extract resource id 92 | | `embedUrl` | `string` | Url of resource\`s embed page. Use `<%= remote_id %>` to substitute resource identifier 93 | | `html` | `string` | HTML code of iframe with embedded content. `embedUrl` will be set as iframe `src` 94 | | `height` | `number` | _Optional_. Height of inserted iframe 95 | | `width` | `number` | _Optional_. Width of inserted iframe 96 | | `id` | `Function` | _Optional_. If your id is complex you can provide function to make the id from extraced regexp groups 97 | 98 | Example: 99 | 100 | ```javascript 101 | { 102 | regex: /https?:\/\/codepen.io\/([^\/\?\&]*)\/pen\/([^\/\?\&]*)/, 103 | embedUrl: 'https://codepen.io/<%= remote_id %>?height=300&theme-id=0&default-tab=css,result&embed-version=2', 104 | html: "", 105 | height: 300, 106 | width: 600, 107 | id: (groups) => groups.join('/embed/') 108 | } 109 | ``` 110 | 111 | When you create a Service configuration object, you can provide it with Tool\`s configuration: 112 | 113 | ```javascript 114 | var editor = EditorJS({ 115 | ... 116 | 117 | tools: { 118 | ... 119 | embed: { 120 | class: Embed, 121 | config: { 122 | services: { 123 | youtube: true, 124 | coub: true, 125 | codepen: { 126 | regex: /https?:\/\/codepen.io\/([^\/\?\&]*)\/pen\/([^\/\?\&]*)/, 127 | embedUrl: 'https://codepen.io/<%= remote_id %>?height=300&theme-id=0&default-tab=css,result&embed-version=2', 128 | html: "", 129 | height: 300, 130 | width: 600, 131 | id: (groups) => groups.join('/embed/') 132 | } 133 | } 134 | } 135 | }, 136 | }, 137 | 138 | ... 139 | }); 140 | ``` 141 | 142 | #### Inline Toolbar 143 | Editor.js provides useful inline toolbar. You can allow it\`s usage in the Embed Tool caption by providing `inlineToolbar: true`. 144 | 145 | ```javascript 146 | var editor = EditorJS({ 147 | ... 148 | 149 | tools: { 150 | ... 151 | embed: { 152 | class: Embed, 153 | inlineToolbar: true 154 | }, 155 | }, 156 | 157 | ... 158 | }); 159 | ``` 160 | 161 | ## Output data 162 | 163 | | Field | Type | Description 164 | | ------- | -------- | ----------- 165 | | service | `string` | service unique name 166 | | source | `string` | source URL 167 | | embed | `string` | URL for source embed page 168 | | width | `number` | embedded content width 169 | | height | `number` | embedded content height 170 | | caption | `string` | content caption 171 | 172 | 173 | ```json 174 | { 175 | "type" : "embed", 176 | "data" : { 177 | "service" : "coub", 178 | "source" : "https://coub.com/view/1czcdf", 179 | "embed" : "https://coub.com/embed/1czcdf", 180 | "width" : 580, 181 | "height" : 320, 182 | "caption" : "My Life" 183 | } 184 | } 185 | ``` 186 | 187 | -------------------------------------------------------------------------------- /src/assets/editorjs/embed/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Embed=t():e.Embed=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=14)}([function(e,t,n){var r=n(5),i=n(6),o=n(7),a=n(9);e.exports=function(e,t){return r(e)||i(e,t)||o(e,t)||a()}},function(e,t){function n(t){return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?e.exports=n=function(e){return typeof e}:e.exports=n=function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(t)}e.exports=n},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t){function n(e,t){for(var n=0;n=0?r=setTimeout(c,t-s):(r=null,n||(l=e.apply(o,i),o=i=null))}null==t&&(t=100);var s=function(){o=this,i=arguments,a=Date.now();var s=n&&!r;return r||(r=setTimeout(c,t)),s&&(l=e.apply(o,i),o=i=null),l};return s.clear=function(){r&&(clearTimeout(r),r=null)},s.flush=function(){r&&(l=e.apply(o,i),o=i=null,clearTimeout(r),r=null)},s}n.debounce=n,e.exports=n},function(e,t){e.exports=function(e){if(Array.isArray(e))return e}},function(e,t){e.exports=function(e,t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e)){var n=[],r=!0,i=!1,o=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(i)throw o}}return n}}},function(e,t,n){var r=n(8);e.exports=function(e,t){if(e){if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(n):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(e,t):void 0}}},function(e,t){e.exports=function(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n?title=0&byline=0",html:'',height:320,width:580},youtube:{regex:/(?:https?:\/\/)?(?:www\.)?(?:(?:youtu\.be\/)|(?:youtube\.com)\/(?:v\/|u\/\w\/|embed\/|watch))(?:(?:\?v=)?([^#&?=]*))?((?:[?&]\w*=\w*)*)/,embedUrl:"https://www.youtube.com/embed/<%= remote_id %>",html:'',height:320,width:580,id:function(e){var t=a()(e,2),n=t[0],r=t[1];if(!r&&n)return n;var i={start:"start",end:"end",t:"start",time_continue:"start",list:"list"};return r=r.slice(1).split("&").map((function(e){var t=e.split("="),r=a()(t,2),o=r[0],l=r[1];if(n||"v"!==o){if(i[o])return"".concat(i[o],"=").concat(l)}else n=l})).filter((function(e){return!!e})),n+"?"+r.join("&")}},coub:{regex:/https?:\/\/coub\.com\/view\/([^\/\?\&]+)/,embedUrl:"https://coub.com/embed/<%= remote_id %>",html:'',height:320,width:580},vine:{regex:/https?:\/\/vine\.co\/v\/([^\/\?\&]+)/,embedUrl:"https://vine.co/v/<%= remote_id %>/embed/simple/",html:'',height:320,width:580},imgur:{regex:/https?:\/\/(?:i\.)?imgur\.com.*\/([a-zA-Z0-9]+)(?:\.gifv)?/,embedUrl:"http://imgur.com/<%= remote_id %>/embed",html:'',height:500,width:540},gfycat:{regex:/https?:\/\/gfycat\.com(?:\/detail)?\/([a-zA-Z]+)/,embedUrl:"https://gfycat.com/ifr/<%= remote_id %>",html:"",height:436,width:580},"twitch-channel":{regex:/https?:\/\/www\.twitch\.tv\/([^\/\?\&]*)\/?$/,embedUrl:"https://player.twitch.tv/?channel=<%= remote_id %>",html:'',height:366,width:600},"twitch-video":{regex:/https?:\/\/www\.twitch\.tv\/(?:[^\/\?\&]*\/v|videos)\/([0-9]*)/,embedUrl:"https://player.twitch.tv/?video=v<%= remote_id %>",html:'',height:366,width:600},"yandex-music-album":{regex:/https?:\/\/music\.yandex\.ru\/album\/([0-9]*)\/?$/,embedUrl:"https://music.yandex.ru/iframe/#album/<%= remote_id %>/",html:'',height:400,width:540},"yandex-music-track":{regex:/https?:\/\/music\.yandex\.ru\/album\/([0-9]*)\/track\/([0-9]*)/,embedUrl:"https://music.yandex.ru/iframe/#track/<%= remote_id %>/",html:'',height:100,width:540,id:function(e){return e.join("/")}},"yandex-music-playlist":{regex:/https?:\/\/music\.yandex\.ru\/users\/([^\/\?\&]*)\/playlists\/([0-9]*)/,embedUrl:"https://music.yandex.ru/iframe/#playlist/<%= remote_id %>/show/cover/description/",html:'',height:400,width:540,id:function(e){return e.join("/")}},codepen:{regex:/https?:\/\/codepen\.io\/([^\/\?\&]*)\/pen\/([^\/\?\&]*)/,embedUrl:"https://codepen.io/<%= remote_id %>?height=300&theme-id=0&default-tab=css,result&embed-version=2",html:"",height:300,width:600,id:function(e){return e.join("/embed/")}},instagram:{regex:/https?:\/\/www\.instagram\.com\/p\/([^\/\?\&]+)\/?/,embedUrl:"https://www.instagram.com/p/<%= remote_id %>/embed",html:'',height:505,width:400},twitter:{regex:/^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)(?:\/.*)?$/,embedUrl:"https://twitframe.com/show?url=https://twitter.com/<%= remote_id %>",html:'',height:300,width:600,id:function(e){return e.join("/status/")}}},h=(n(10),n(4)),f=function(){function e(t){var n=t.data,r=t.api;c()(this,e),this.api=r,this._data={},this.element=null,this.data=n}return d()(e,[{key:"render",value:function(){var t=this;if(!this.data.service){var n=document.createElement("div");return this.element=n,n}var r=e.services[this.data.service].html,i=document.createElement("div"),o=document.createElement("div"),a=document.createElement("template"),l=this.createPreloader();i.classList.add(this.CSS.baseClass,this.CSS.container,this.CSS.containerLoading),o.classList.add(this.CSS.input,this.CSS.caption),i.appendChild(l),o.contentEditable=!0,o.dataset.placeholder="Enter a caption",o.innerHTML=this.data.caption||"",a.innerHTML=r,a.content.firstChild.setAttribute("src",this.data.embed),a.content.firstChild.classList.add(this.CSS.content);var c=this.embedIsReady(i);return i.appendChild(a.content.firstChild),i.appendChild(o),c.then((function(){i.classList.remove(t.CSS.containerLoading)})),this.element=i,i}},{key:"createPreloader",value:function(){var e=document.createElement("preloader"),t=document.createElement("div");return t.textContent=this.data.source,e.classList.add(this.CSS.preloader),t.classList.add(this.CSS.url),e.appendChild(t),e}},{key:"save",value:function(){return this.data}},{key:"onPaste",value:function(t){var n=t.detail,r=n.key,i=n.data,o=e.services[r],a=o.regex,l=o.embedUrl,c=o.width,s=o.height,d=o.id,u=void 0===d?function(e){return e.shift()}:d,h=a.exec(i).slice(1),f=l.replace(/<\%\= remote\_id \%\>/g,u(h));this.data={service:r,source:i,embed:f,width:c,height:s}}},{key:"embedIsReady",value:function(e){var t=null;return new Promise((function(n,r){(t=new MutationObserver(Object(h.debounce)(n,450))).observe(e,{childList:!0,subtree:!0})})).then((function(){t.disconnect()}))}},{key:"data",set:function(e){if(!(e instanceof Object))throw Error("Embed Tool data should be object");var t=e.service,n=e.source,r=e.embed,i=e.width,o=e.height,a=e.caption,l=void 0===a?"":a;this._data={service:t||this.data.service,source:n||this.data.source,embed:r||this.data.embed,width:i||this.data.width,height:o||this.data.height,caption:l||this.data.caption||""};var c=this.element;c&&c.parentNode.replaceChild(this.render(),c)},get:function(){if(this.element){var e=this.element.querySelector(".".concat(this.api.styles.input));this._data.caption=e?e.innerHTML:""}return this._data}},{key:"CSS",get:function(){return{baseClass:this.api.styles.block,input:this.api.styles.input,container:"embed-tool",containerLoading:"embed-tool--loading",preloader:"embed-tool__preloader",caption:"embed-tool__caption",url:"embed-tool__url",content:"embed-tool__content"}}}],[{key:"prepare",value:function(t){var n=t.config,r=(void 0===n?{}:n).services,o=void 0===r?{}:r,l=Object.entries(u),c=Object.entries(o).filter((function(e){var t=a()(e,2),n=(t[0],t[1]);return"boolean"==typeof n&&!0===n})).map((function(e){return a()(e,1)[0]})),s=Object.entries(o).filter((function(e){var t=a()(e,2),n=(t[0],t[1]);return"object"===i()(n)})).filter((function(t){var n=a()(t,2),r=(n[0],n[1]);return e.checkServiceConfig(r)})).map((function(e){var t=a()(e,2),n=t[0],r=t[1];return[n,{regex:r.regex,embedUrl:r.embedUrl,html:r.html,height:r.height,width:r.width,id:r.id}]}));c.length&&(l=l.filter((function(e){var t=a()(e,1)[0];return c.includes(t)}))),l=l.concat(s),e.services=l.reduce((function(e,t){var n=a()(t,2),r=n[0],i=n[1];return r in e?(e[r]=Object.assign({},e[r],i),e):(e[r]=i,e)}),{}),e.patterns=l.reduce((function(e,t){var n=a()(t,2),r=n[0],i=n[1];return e[r]=i.regex,e}),{})}},{key:"checkServiceConfig",value:function(e){var t=e.regex,n=e.embedUrl,r=e.html,i=e.height,o=e.width,a=e.id,l=t&&t instanceof RegExp&&n&&"string"==typeof n&&r&&"string"==typeof r;return l=(l=(l=l&&(void 0===a||a instanceof Function))&&(void 0===i||Number.isFinite(i)))&&(void 0===o||Number.isFinite(o))}},{key:"pasteConfig",get:function(){return{patterns:e.patterns}}}]),e}()}]).default})); -------------------------------------------------------------------------------- /src/assets/editorjs/header/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/editorjs/header/README.md: -------------------------------------------------------------------------------- 1 | # Heading Tool 2 | 3 | ![Version of EditorJS that the plugin is compatible with](https://badgen.net/badge/Editor.js/v2.0/blue) 4 | 5 | Provides Headings Blocks for the [Editor.js](https://ifmo.su/editor). 6 | 7 | ## Installation 8 | 9 | ### Install via NPM 10 | 11 | Get the package 12 | 13 | ```shell 14 | npm i --save-dev @editorjs/header 15 | ``` 16 | 17 | Include module at your application 18 | 19 | ```javascript 20 | const Header = require('@editorjs/header'); 21 | ``` 22 | 23 | ### Download to your project's source dir 24 | 25 | 1. Upload folder `dist` from repository 26 | 2. Add `dist/bundle.js` file to your page. 27 | 28 | ### Load from CDN 29 | 30 | You can load specific version of package from [jsDelivr CDN](https://www.jsdelivr.com/package/npm/@editorjs/header). 31 | 32 | `https://cdn.jsdelivr.net/npm/@editorjs/header@latest` 33 | 34 | Then require this script on page with Editor.js. 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | ## Usage 41 | 42 | Add a new Tool to the `tools` property of the Editor.js initial config. 43 | 44 | ```javascript 45 | var editor = EditorJS({ 46 | ... 47 | 48 | tools: { 49 | ... 50 | header: Header, 51 | }, 52 | 53 | ... 54 | }); 55 | ``` 56 | 57 | ## Shortcut 58 | 59 | You can insert this Block by a useful shortcut. Set it up with the `tools[].shortcut` property of the Editor's initial config. 60 | 61 | ```javascript 62 | var editor = EditorJS({ 63 | ... 64 | 65 | tools: { 66 | ... 67 | header: { 68 | class: Header, 69 | shortcut: 'CMD+SHIFT+H', 70 | }, 71 | }, 72 | 73 | ... 74 | }); 75 | ``` 76 | 77 | ## Config Params 78 | 79 | All properties are optional. 80 | 81 | | Field | Type | Description | 82 | | ------------ | ---------- | --------------------------- | 83 | | placeholder | `string` | header's placeholder string | 84 | | levels | `number[]` | enabled heading levels | 85 | | defaultLevel | `number` | default heading level | 86 | 87 | ```javascript 88 | var editor = EditorJS({ 89 | ... 90 | 91 | tools: { 92 | ... 93 | header: { 94 | class: Header, 95 | config: { 96 | placeholder: 'Enter a header', 97 | levels: [2, 3, 4], 98 | defaultLevel: 3 99 | } 100 | } 101 | } 102 | 103 | ... 104 | }); 105 | ``` 106 | 107 | ## Tool's settings 108 | 109 | ![An image showing the header block tool](https://capella.pics/634ad545-08d7-4cb7-8409-f01289e0e5e1.jpg) 110 | 111 | You can select one of six levels for heading. 112 | 113 | ## Output data 114 | 115 | | Field | Type | Description | 116 | | ----- | -------- | ------------------------------------------------ | 117 | | text | `string` | header's text | 118 | | level | `number` | level of header: 1 for H1, 2 for H2 ... 6 for H6 | 119 | 120 | ```json 121 | { 122 | "type": "header", 123 | "data": { 124 | "text": "Why Telegram is the best messenger", 125 | "level": 2 126 | } 127 | } 128 | ``` 129 | -------------------------------------------------------------------------------- /src/assets/editorjs/header/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Header=t():e.Header=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}([function(e,t,n){function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n'},{number:2,tag:"H2",svg:''},{number:3,tag:"H3",svg:''},{number:4,tag:"H4",svg:''},{number:5,tag:"H5",svg:''},{number:6,tag:"H6",svg:''}];return this._settings.levels?t.filter((function(t){return e._settings.levels.includes(t.number)})):t}}])&&i(t.prototype,a),o&&i(t,o),e}();e.exports=a},function(e,t,n){var r=n(2);"string"==typeof r&&(r=[[e.i,r,""]]);var i={hmr:!0,transform:void 0,insertInto:void 0};n(4)(r,i);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(3)(!1)).push([e.i,"/**\n * Plugin styles\n */\n.ce-header {\n padding: 1em 0;\n margin: 0;\n margin-bottom: -0.9em;\n line-height: 1.5em;\n outline: none;\n}\n\n.ce-header p,\n.ce-header div{\n padding: 0 !important;\n margin: 0 !important;\n}\n\n/**\n * Styles for Plugin icon in Toolbar\n */\n.ce-header__icon {}\n\n.ce-header[contentEditable=true][data-placeholder]::before{\n position: absolute;\n content: attr(data-placeholder);\n color: #707684;\n font-weight: normal;\n display: none;\n}\n\n.ce-header[contentEditable=true][data-placeholder]:empty::before {\n display: block;\n}\n\n.ce-header[contentEditable=true][data-placeholder]:empty:focus::before {\n display: none;\n}\n",""])},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=function(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"==typeof btoa){var i=(o=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */"),a=r.sources.map((function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"}));return[n].concat(a).concat([i]).join("\n")}var o;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n})).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},i=0;i=0&&f.splice(t,1)}function m(e){var t=document.createElement("style");return void 0===e.attrs.type&&(e.attrs.type="text/css"),b(t,e.attrs),p(e,t),t}function b(e,t){Object.keys(t).forEach((function(n){e.setAttribute(n,t[n])}))}function y(e,t){var n,r,i,a;if(t.transform&&e.css){if(!(a=t.transform(e.css)))return function(){};e.css=a}if(t.singleton){var o=u++;n=l||(l=m(t)),r=L.bind(null,n,o,!1),i=L.bind(null,n,o,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",b(t,e.attrs),p(e,t),t}(t),r=_.bind(null,n,t),i=function(){g(n),n.href&&URL.revokeObjectURL(n.href)}):(n=m(t),r=H.bind(null,n),i=function(){g(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else i()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=o()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=v(e,t);return h(n,t),function(e){for(var r=[],i=0;i` tag. 50 | 51 | ## Usage 52 | 53 | Add a new Tool to the `tools` property of the Editor.js initial config. 54 | 55 | ```javascript 56 | import ImageTool from '@editorjs/image'; 57 | 58 | // or if you inject ImageTool via standalone script 59 | const ImageTool = window.ImageTool; 60 | 61 | var editor = EditorJS({ 62 | ... 63 | 64 | tools: { 65 | ... 66 | image: { 67 | class: ImageTool, 68 | config: { 69 | endpoints: { 70 | byFile: 'http://localhost:8008/uploadFile', // Your backend file uploader endpoint 71 | byUrl: 'http://localhost:8008/fetchUrl', // Your endpoint that provides uploading by Url 72 | } 73 | } 74 | } 75 | } 76 | 77 | ... 78 | }); 79 | ``` 80 | 81 | ## Config Params 82 | 83 | Image Tool supports these configuration parameters: 84 | 85 | | Field | Type | Description | 86 | | ----- | -------- | ------------------ | 87 | | endpoints | `{byFile: string, byUrl: string}` | Endpoints for file uploading.
Contains 2 fields:
__byFile__ - for file uploading
__byUrl__ - for uploading by URL | 88 | | field | `string` | (default: `image`) Name of uploaded image field in POST request | 89 | | types | `string` | (default: `image/*`) Mime-types of files that can be [accepted with file selection](https://github.com/codex-team/ajax#accept-string).| 90 | | additionalRequestData | `object` | Object with any data you want to send with uploading requests | 91 | | additionalRequestHeaders | `object` | Object with any custom headers which will be added to request. [See example](https://github.com/codex-team/ajax/blob/e5bc2a2391a18574c88b7ecd6508c29974c3e27f/README.md#headers-object) | 92 | | captionPlaceholder | `string` | (default: `Caption`) Placeholder for Caption input | 93 | | buttonContent | `string` | Allows to override HTML content of «Select file» button | 94 | | uploader | `{{uploadByFile: function, uploadByUrl: function}}` | Optional custom uploading methods. See details below. | 95 | 96 | Note that if you don't implement your custom uploader methods, the `endpoints` param is required. 97 | 98 | ## Tool's settings 99 | 100 | ![](https://capella.pics/c74cdeec-3405-48ac-a960-f784188cf9b4.jpg) 101 | 102 | 1. Add border 103 | 104 | 2. Stretch to full-width 105 | 106 | 3. Add background 107 | 108 | ## Output data 109 | 110 | This Tool returns `data` with following format 111 | 112 | | Field | Type | Description | 113 | | -------------- | --------- | ------------------------------- | 114 | | file | `object` | Uploaded file data. Any data got from backend uploader. Always contain the `url` property | 115 | | caption | `string` | image's caption | 116 | | withBorder | `boolean` | add border to image | 117 | | withBackground | `boolean` | need to add background | 118 | | stretched | `boolean` | stretch image to screen's width | 119 | 120 | 121 | ```json 122 | { 123 | "type" : "image", 124 | "data" : { 125 | "file": { 126 | "url" : "https://www.tesla.com/tesla_theme/assets/img/_vehicle_redesign/roadster_and_semi/roadster/hero.jpg" 127 | }, 128 | "caption" : "Roadster // tesla.com", 129 | "withBorder" : false, 130 | "withBackground" : false, 131 | "stretched" : true 132 | } 133 | } 134 | ``` 135 | 136 | ## Backend response format 137 | 138 | This Tool works by one of the following schemes: 139 | 140 | 1. Uploading files from the device 141 | 2. Uploading by URL (handle image-like URL's pasting) 142 | 3. Uploading by drag-n-drop file 143 | 4. Uploading by pasting from Clipboard 144 | 145 | ### Uploading files from device 146 | 147 | Scenario: 148 | 149 | 1. User select file from the device 150 | 2. Tool sends it to **your** backend (on `config.endpoint.byFile` route) 151 | 3. Your backend should save file and return file data with JSON at specified format. 152 | 4. Image tool shows saved image and stores server answer 153 | 154 | So, you can implement backend for file saving by your own way. It is a specific and trivial task depending on your 155 | environment and stack. 156 | 157 | Response of your uploader **should** cover following format: 158 | 159 | ```json5 160 | { 161 | "success" : 1, 162 | "file": { 163 | "url" : "https://www.tesla.com/tesla_theme/assets/img/_vehicle_redesign/roadster_and_semi/roadster/hero.jpg", 164 | // ... and any additional fields you want to store, such as width, height, color, extension, etc 165 | } 166 | } 167 | ``` 168 | 169 | **success** - uploading status. 1 for successful, 0 for failed 170 | 171 | **file** - uploaded file data. **Must** contain an `url` field with full public path to the uploaded image. 172 | Also, can contain any additional fields you want to store. For example, width, height, id etc. 173 | All additional fields will be saved at the `file` object of output data. 174 | 175 | ### Uploading by pasted URL 176 | 177 | Scenario: 178 | 179 | 1. User pastes an URL of the image file to the Editor 180 | 2. Editor pass pasted string to the Image Tool 181 | 3. Tool sends it to **your** backend (on `config.endpoint.byUrl` route) via 'url' POST-parameter 182 | 3. Your backend should accept URL, **download and save the original file by passed URL** and return file data with JSON at specified format. 183 | 4. Image tool shows saved image and stores server answer 184 | 185 | Response of your uploader should be at the same format as described at «[Uploading files from device](#from-device)» section 186 | 187 | 188 | ### Uploading by drag-n-drop or from Clipboard 189 | 190 | Your backend will accept file as FormData object in field name, specified by `config.field` (by default, «`image`»). 191 | You should save it and return the same response format as described above. 192 | 193 | ## Providing custom uploading methods 194 | 195 | As mentioned at the Config Params section, you have an ability to provide own custom uploading methods. 196 | It is a quite simple: implement `uploadByFile` and `uploadByUrl` methods and pass them via `uploader` config param. 197 | Both methods must return a Promise that resolves with response in format that described at the [backend response format](#server-format) section. 198 | 199 | 200 | | Method | Arguments | Return value | Description | 201 | | -------------- | --------- | -------------| ------------| 202 | | uploadByFile | `File` | `{Promise.<{success, file: {url}}>}` | Upload file to the server and return an uploaded image data | 203 | | uploadByUrl | `string` | `{Promise.<{success, file: {url}}>}` | Send URL-string to the server, that should load image by this URL and return an uploaded image data | 204 | 205 | Example: 206 | 207 | ```js 208 | import ImageTool from '@editorjs/image'; 209 | 210 | var editor = EditorJS({ 211 | ... 212 | 213 | tools: { 214 | ... 215 | image: { 216 | class: ImageTool, 217 | config: { 218 | /** 219 | * Custom uploader 220 | */ 221 | uploader: { 222 | /** 223 | * Upload file to the server and return an uploaded image data 224 | * @param {File} file - file selected from the device or pasted by drag-n-drop 225 | * @return {Promise.<{success, file: {url}}>} 226 | */ 227 | uploadByFile(file){ 228 | // your own uploading logic here 229 | return MyAjax.upload(file).then(() => { 230 | return { 231 | success: 1, 232 | file: { 233 | url: 'https://codex.so/upload/redactor_images/o_80beea670e49f04931ce9e3b2122ac70.jpg', 234 | // any other image data you want to store, such as width, height, color, extension, etc 235 | } 236 | }; 237 | }); 238 | }, 239 | 240 | /** 241 | * Send URL-string to the server. Backend should load image by this URL and return an uploaded image data 242 | * @param {string} url - pasted image URL 243 | * @return {Promise.<{success, file: {url}}>} 244 | */ 245 | uploadByUrl(url){ 246 | // your ajax request for uploading 247 | return MyAjax.upload(file).then(() => { 248 | return { 249 | success: 1, 250 | file: { 251 | url: 'https://codex.so/upload/redactor_images/o_e48549d1855c7fc1807308dd14990126.jpg',, 252 | // any other image data you want to store, such as width, height, color, extension, etc 253 | } 254 | } 255 | }) 256 | } 257 | } 258 | } 259 | } 260 | } 261 | 262 | ... 263 | }); 264 | ``` 265 | -------------------------------------------------------------------------------- /src/assets/editorjs/inline-code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/editorjs/inline-code/README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # InlineCode Tool 4 | 5 | Inline Tool for marking code-fragments for the [Editor.js](https://ifmo.su/editor). 6 | 7 | ![](assets/example.gif) 8 | 9 | ## Installation 10 | 11 | ### Install via NPM 12 | 13 | Get the package 14 | 15 | ```shell 16 | npm i --save-dev @editorjs/inline-code 17 | ``` 18 | 19 | Include module at your application 20 | 21 | ```javascript 22 | const InlineCode = require('@editorjs/inline-code'); 23 | ``` 24 | 25 | ### Download to your project's source dir 26 | 27 | 1. Upload folder `dist` from repository 28 | 2. Add `dist/bundle.js` file to your page. 29 | 30 | ### Load from CDN 31 | 32 | You can load specific version of package from [jsDelivr CDN](https://www.jsdelivr.com/package/npm/@editorjs/inline-code). 33 | 34 | `https://cdn.jsdelivr.net/npm/@editorjs/inline-code@1.0.1` 35 | 36 | Require this script on a page with Editor.js. 37 | 38 | ```html 39 | 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the Editor.js initial config. 45 | 46 | ```javascript 47 | var editor = EditorJS({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | inlineCode: { 53 | class: InlineCode, 54 | shortcut: 'CMD+SHIFT+M', 55 | }, 56 | }, 57 | 58 | ... 59 | }); 60 | ``` 61 | 62 | ## Config Params 63 | 64 | This Tool has no config params 65 | 66 | ## Output data 67 | 68 | Marked text will be wrapped with a `span` tag with an `inline-code` class. 69 | 70 | ```json 71 | { 72 | "type" : "text", 73 | "data" : { 74 | "text" : "Create a directory for your module, enter it and run npm init command." 75 | } 76 | } 77 | ``` 78 | 79 | -------------------------------------------------------------------------------- /src/assets/editorjs/inline-code/bundle.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.InlineCode=e():t.InlineCode=e()}(window,function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=0)}([function(t,e,n){function r(t,e){for(var n=0;n=0&&f.splice(e,1)}function b(t){var e=document.createElement("style");return void 0===t.attrs.type&&(t.attrs.type="text/css"),y(e,t.attrs),h(t,e),e}function y(t,e){Object.keys(e).forEach(function(n){t.setAttribute(n,e[n])})}function g(t,e){var n,r,o,i;if(e.transform&&t.css){if(!(i=e.transform(t.css)))return function(){};t.css=i}if(e.singleton){var a=c++;n=u||(u=b(e)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",y(e,t.attrs),h(t,e),e}(e),r=function(t,e,n){var r=n.css,o=n.sourceMap,i=void 0===e.convertToAbsoluteUrls&&o;(e.convertToAbsoluteUrls||i)&&(r=l(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=t.href;t.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,e),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=b(e),r=function(t,e){var n=e.css,r=e.media;r&&t.setAttribute("media",r);if(t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;r(t=e)}else o()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=a()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=d(t,e);return p(n,e),function(t){for(var r=[],o=0;o 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the Editor.js initial config. 45 | 46 | ```javascript 47 | var editor = EditorJS({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | list: { 53 | class: List, 54 | inlineToolbar: true, 55 | }, 56 | } 57 | 58 | ... 59 | }); 60 | ``` 61 | 62 | ## Config Params 63 | 64 | This Tool has no config params 65 | 66 | ## Tool's settings 67 | 68 | ![](https://capella.pics/bf5a42e4-1350-499d-a728-493b0fcaeda4.jpg) 69 | 70 | You can choose list`s type. 71 | 72 | ## Output data 73 | 74 | | Field | Type | Description | 75 | | ----- | ---------- | -------------------------------------- | 76 | | style | `string` | type of list: `ordered` or `unordered` | 77 | | items | `string[]` | array of list's items | 78 | 79 | 80 | ```json 81 | { 82 | "type" : "list", 83 | "data" : { 84 | "style" : "unordered", 85 | "items" : [ 86 | "This is a block-styled editor", 87 | "Clean output data", 88 | "Simple and powerful API" 89 | ] 90 | } 91 | }, 92 | ``` 93 | 94 | -------------------------------------------------------------------------------- /src/assets/editorjs/list/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.List=t():e.List=t()}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}([function(e,t,n){function r(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t ',default:!1},{name:"ordered",title:"Ordered",icon:'',default:!0}],this._data={style:this.settings.find(function(e){return!0===e.default}).name,items:[]},this.api=r,this.data=n}return o(e,null,[{key:"enableLineBreaks",get:function(){return!0}},{key:"toolbox",get:function(){return{icon:' ',title:"List"}}}]),o(e,[{key:"render",value:function(){var e=this,t="ordered"===this._data.style?this.CSS.wrapperOrdered:this.CSS.wrapperUnordered;return this._elements.wrapper=this._make("ul",[this.CSS.baseBlock,this.CSS.wrapper,t],{contentEditable:!0}),this._data.items.length?this._data.items.forEach(function(t){e._elements.wrapper.appendChild(e._make("li",e.CSS.item,{innerHTML:t}))}):this._elements.wrapper.appendChild(this._make("li",this.CSS.item)),this._elements.wrapper.addEventListener("keydown",function(t){switch(t.keyCode){case 13:e.getOutofList(t);break;case 8:e.backspace(t)}},!1),this._elements.wrapper}},{key:"save",value:function(){return this.data}},{key:"renderSettings",value:function(){var e=this,t=this._make("div",[this.CSS.settingsWrapper],{});return this.settings.forEach(function(n){var r=e._make("div",e.CSS.settingsButton,{innerHTML:n.icon});r.addEventListener("click",function(){e.toggleTune(n.name);var t=r.parentNode.querySelectorAll("."+e.CSS.settingsButton);Array.from(t).forEach(function(t){return t.classList.remove(e.CSS.settingsButtonActive)}),r.classList.toggle(e.CSS.settingsButtonActive)}),e._data.style===n.name&&r.classList.add(e.CSS.settingsButtonActive),t.appendChild(r)}),t}},{key:"onPaste",value:function(e){var t=e.detail.data;this.data=this.pasteHandler(t)}},{key:"toggleTune",value:function(e){this._elements.wrapper.classList.toggle(this.CSS.wrapperOrdered,"ordered"===e),this._elements.wrapper.classList.toggle(this.CSS.wrapperUnordered,"unordered"===e),this._data.style=e}},{key:"_make",value:function(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=document.createElement(e);Array.isArray(n)?(t=o.classList).add.apply(t,r(n)):n&&o.classList.add(n);for(var a in i)o[a]=i[a];return o}},{key:"getOutofList",value:function(e){var t=this._elements.wrapper.querySelectorAll("."+this.CSS.item);if(!(t.length<2)){var n=t[t.length-1],r=this.currentItem;r!==n||n.textContent.trim().length||(r.parentElement.removeChild(r),this.api.blocks.insertNewBlock(),e.preventDefault(),e.stopPropagation())}}},{key:"backspace",value:function(e){var t=this._elements.wrapper.querySelectorAll("."+this.CSS.item),n=t[0];n&&t.length<2&&!n.innerHTML.replace("
"," ").trim()&&e.preventDefault()}},{key:"selectItem",value:function(e){e.preventDefault();var t=window.getSelection(),n=t.anchorNode.parentNode.closest("."+this.CSS.item),r=new Range;r.selectNodeContents(n),t.removeAllRanges(),t.addRange(r)}},{key:"pasteHandler",value:function(e){var t,n=e.tagName;switch(n){case"OL":t="ordered";break;case"UL":case"LI":t="unordered"}var r={type:t,items:[]};if("LI"===n)r.items=[e.innerHTML];else{var i=Array.from(e.querySelectorAll("LI"));r.items=i.map(function(e){return e.innerHTML}).filter(function(e){return!!e.trim()})}return r}},{key:"CSS",get:function(){return{baseBlock:this.api.styles.block,wrapper:"cdx-list",wrapperOrdered:"cdx-list--ordered",wrapperUnordered:"cdx-list--unordered",item:"cdx-list__item",settingsWrapper:"cdx-list-settings",settingsButton:this.api.styles.settingsButton,settingsButtonActive:this.api.styles.settingsButtonActive}}},{key:"data",set:function(e){e||(e={}),this._data.style=e.style||this.settings.find(function(e){return!0===e.default}).name,this._data.items=e.items||[];var t=this._elements.wrapper;t&&t.parentNode.replaceChild(this.render(),t)},get:function(){this._data.items=[];for(var e=this._elements.wrapper.querySelectorAll(".".concat(this.CSS.item)),t=0;t"," ").trim()&&this._data.items.push(e[t].innerHTML)}return this._data}},{key:"currentItem",get:function(){var e=window.getSelection().anchorNode;return e.nodeType!==Node.ELEMENT_NODE&&(e=e.parentNode),e.closest(".".concat(this.CSS.item))}}],[{key:"conversionConfig",get:function(){return{export:function(e){return e.items.join(". ")},import:function(e){return{items:[e],style:"unordered"}}}}},{key:"sanitize",get:function(){return{style:{},items:{br:!0}}}},{key:"pasteConfig",get:function(){return{tags:["OL","UL","LI"]}}}]),e}();e.exports=a},function(e,t,n){var r=n(2);"string"==typeof r&&(r=[[e.i,r,""]]);var i={hmr:!0,transform:void 0,insertInto:void 0};n(4)(r,i);r.locals&&(e.exports=r.locals)},function(e,t,n){(e.exports=n(3)(!1)).push([e.i,".cdx-list {\n margin: 0;\n padding-left: 40px;\n outline: none;\n}\n\n .cdx-list__item {\n padding: 5.5px 0 5.5px 3px;\n line-height: 1.6em;\n }\n\n .cdx-list--unordered {\n list-style: disc;\n }\n\n .cdx-list--ordered {\n list-style: decimal;\n }\n\n .cdx-list-settings {\n display: flex;\n }\n\n .cdx-list-settings .cdx-settings-button {\n width: 50%;\n }\n",""])},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=function(e,t){var n=e[1]||"",r=e[3];if(!r)return n;if(t&&"function"==typeof btoa){var i=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),o=r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"});return[n].concat(o).concat([i]).join("\n")}var a;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var r={},i=0;i=0&&u.splice(t,1)}function v(e){var t=document.createElement("style");return void 0===e.attrs.type&&(e.attrs.type="text/css"),g(t,e.attrs),h(e,t),t}function g(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function y(e,t){var n,r,i,o;if(t.transform&&e.css){if(!(o=t.transform(e.css)))return function(){};e.css=o}if(t.singleton){var a=l++;n=c||(c=v(t)),r=S.bind(null,n,a,!1),i=S.bind(null,n,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",g(t,e.attrs),h(e,t),t}(t),r=function(e,t,n){var r=n.css,i=n.sourceMap,o=void 0===t.convertToAbsoluteUrls&&i;(t.convertToAbsoluteUrls||o)&&(r=f(r));i&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,t),i=function(){m(n),n.href&&URL.revokeObjectURL(n.href)}):(n=v(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),i=function(){m(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else i()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=a()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=p(e,t);return d(n,t),function(e){for(var r=[],i=0;i 38 | ``` 39 | 40 | ## Usage 41 | 42 | Add a new Tool to the `tools` property of the Editor.js initial config. 43 | 44 | ```javascript 45 | var editor = EditorJS({ 46 | ... 47 | 48 | tools: { 49 | ... 50 | paragraph: { 51 | class: Paragraph, 52 | inlineToolbar: true, 53 | }, 54 | } 55 | 56 | ... 57 | }); 58 | ``` 59 | 60 | ## Config Params 61 | 62 | This Tool has no config params 63 | 64 | ## Output data 65 | 66 | | Field | Type | Description | 67 | | ------ | -------- | ---------------- | 68 | | text | `string` | paragraph's text | 69 | 70 | 71 | ```json 72 | { 73 | "type" : "paragraph", 74 | "data" : { 75 | "text" : "Check out our projects on a GitHub page.", 76 | } 77 | } 78 | ``` 79 | 80 | -------------------------------------------------------------------------------- /src/assets/editorjs/paragraph/bundle.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Paragraph=t():e.Paragraph=t()}(window,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}([function(e,t,n){function r(e,t){for(var n=0;n=0&&f.splice(t,1)}function y(e){var t=document.createElement("style");return void 0===e.attrs.type&&(e.attrs.type="text/css"),b(t,e.attrs),h(e,t),t}function b(e,t){Object.keys(t).forEach(function(n){e.setAttribute(n,t[n])})}function m(e,t){var n,r,o,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var a=u++;n=c||(c=y(t)),r=w.bind(null,n,a,!1),o=w.bind(null,n,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(e){var t=document.createElement("link");return void 0===e.attrs.type&&(e.attrs.type="text/css"),e.attrs.rel="stylesheet",b(t,e.attrs),h(e,t),t}(t),r=function(e,t,n){var r=n.css,o=n.sourceMap,i=void 0===t.convertToAbsoluteUrls&&o;(t.convertToAbsoluteUrls||i)&&(r=l(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=e.href;e.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,t),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=y(t),r=function(e,t){var n=t.css,r=t.media;r&&e.setAttribute("media",r);if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;r(e=t)}else o()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=a()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var n=d(e,t);return p(n,t),function(e){for(var r=[],o=0;o 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the Editor.js initial config. 45 | 46 | ```javascript 47 | var editor = EditorJS({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | quote: Quote, 53 | }, 54 | 55 | ... 56 | }); 57 | ``` 58 | 59 | Or init Quote Tool with additional settings 60 | 61 | ```javascript 62 | var editor = EditorJS({ 63 | ... 64 | 65 | tools: { 66 | ... 67 | quote: { 68 | class: Quote, 69 | inlineToolbar: true, 70 | shortcut: 'CMD+SHIFT+O', 71 | config: { 72 | quotePlaceholder: 'Enter a quote', 73 | captionPlaceholder: 'Quote\'s author', 74 | }, 75 | }, 76 | }, 77 | 78 | ... 79 | }); 80 | ``` 81 | 82 | ## Config Params 83 | 84 | | Field | Type | Description | 85 | | ------------------ | -------- | ----------------------------| 86 | | quotePlaceholder | `string` | quote's placeholder string | 87 | | captionPlaceholder | `string` | caption's placeholder string| 88 | 89 | ## Tool's settings 90 | 91 | ![](https://capella.pics/0db5d4de-c431-4cc2-90bf-bb1f4feec5df.jpg) 92 | 93 | You can choose alignment for the quote. It takes no effect while editing, but saved the «alignment» param. 94 | 95 | ## Output data 96 | 97 | | Field | Type | Description | 98 | | --------- | -------- | -------------------- | 99 | | text | `string` | quote's text | 100 | | caption | `string` | caption or an author | 101 | | alignment | `string` | `left` or `center` | 102 | 103 | 104 | ```json 105 | { 106 | "type" : "quote", 107 | "data" : { 108 | "text" : "The unexamined life is not worth living.", 109 | "caption" : "Socrates", 110 | "alignment" : "left" 111 | } 112 | } 113 | ``` 114 | -------------------------------------------------------------------------------- /src/assets/editorjs/quote/bundle.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Quote=e():t.Quote=e()}(window,function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=0)}([function(t,e,n){function r(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e'},{name:"center",icon:''}]}}],[{key:"toolbox",get:function(){return{icon:'',title:"Quote"}}},{key:"contentless",get:function(){return!0}},{key:"enableLineBreaks",get:function(){return!0}},{key:"DEFAULT_QUOTE_PLACEHOLDER",get:function(){return"Enter a quote"}},{key:"DEFAULT_CAPTION_PLACEHOLDER",get:function(){return"Enter a caption"}},{key:"ALIGNMENTS",get:function(){return{left:"left",center:"center"}}},{key:"DEFAULT_ALIGNMENT",get:function(){return t.ALIGNMENTS.left}},{key:"conversionConfig",get:function(){return{import:"text",export:function(t){return t.caption?"".concat(t.text," — ").concat(t.caption):t.text}}}}]),i(t,[{key:"render",value:function(){var t=this._make("blockquote",[this.CSS.baseClass,this.CSS.wrapper]),e=this._make("div",[this.CSS.input,this.CSS.text],{contentEditable:!0,innerHTML:this.data.text}),n=this._make("div",[this.CSS.input,this.CSS.caption],{contentEditable:!0,innerHTML:this.data.caption});return e.dataset.placeholder=this.quotePlaceholder,n.dataset.placeholder=this.captionPlaceholder,t.appendChild(e),t.appendChild(n),t}},{key:"save",value:function(t){var e=t.querySelector(".".concat(this.CSS.text)),n=t.querySelector(".".concat(this.CSS.caption));return Object.assign(this.data,{text:e.innerHTML,caption:n.innerHTML})}},{key:"renderSettings",value:function(){var t=this,e=this._make("div",[this.CSS.settingsWrapper],{});return this.settings.map(function(n){var r,o=t._make("div",t.CSS.settingsButton,{innerHTML:n.icon,title:"".concat((r=n.name,r[0].toUpperCase()+r.substr(1))," alignment")});return o.classList.toggle(t.CSS.settingsButtonActive,n.name===t.data.alignment),e.appendChild(o),o}).forEach(function(e,n,r){e.addEventListener("click",function(){t._toggleTune(t.settings[n].name),r.forEach(function(e,n){var r=t.settings[n].name;e.classList.toggle(t.CSS.settingsButtonActive,r===t.data.alignment)})})}),e}},{key:"_toggleTune",value:function(t){this.data.alignment=t}},{key:"_make",value:function(t){var e,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=document.createElement(t);Array.isArray(n)?(e=i.classList).add.apply(e,r(n)):n&&i.classList.add(n);for(var a in o)i[a]=o[a];return i}}],[{key:"sanitize",get:function(){return{text:{br:!0},caption:{br:!0},alignment:{}}}}]),t}();t.exports=a},function(t,e,n){var r=n(2);"string"==typeof r&&(r=[[t.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(4)(r,o);r.locals&&(t.exports=r.locals)},function(t,e,n){(t.exports=n(3)(!1)).push([t.i,".cdx-quote-icon svg {\n transform: rotate(180deg);\n}\n\n.cdx-quote {\n margin: 0;\n}\n\n.cdx-quote__text {\n min-height: 158px;\n margin-bottom: 10px;\n}\n\n.cdx-quote__caption {}\n\n.cdx-quote [contentEditable=true][data-placeholder]::before{\n position: absolute;\n content: attr(data-placeholder);\n color: #707684;\n font-weight: normal;\n opacity: 0;\n}\n\n.cdx-quote [contentEditable=true][data-placeholder]:empty::before {\n opacity: 1;\n}\n\n.cdx-quote [contentEditable=true][data-placeholder]:empty:focus::before {\n opacity: 0;\n}\n\n\n.cdx-quote-settings {\n display: flex;\n}\n\n.cdx-quote-settings .cdx-settings-button {\n width: 50%;\n}\n",""])},function(t,e){t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=function(t,e){var n=t[1]||"",r=t[3];if(!r)return n;if(e&&"function"==typeof btoa){var o=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),i=r.sources.map(function(t){return"/*# sourceURL="+r.sourceRoot+t+" */"});return[n].concat(i).concat([o]).join("\n")}var a;return[n].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n}).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var r={},o=0;o=0&&l.splice(e,1)}function g(t){var e=document.createElement("style");return void 0===t.attrs.type&&(t.attrs.type="text/css"),m(e,t.attrs),h(t,e),e}function m(t,e){Object.keys(e).forEach(function(n){t.setAttribute(n,e[n])})}function y(t,e){var n,r,o,i;if(e.transform&&t.css){if(!(i=e.transform(t.css)))return function(){};t.css=i}if(e.singleton){var a=u++;n=c||(c=g(e)),r=w.bind(null,n,a,!1),o=w.bind(null,n,a,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",m(e,t.attrs),h(t,e),e}(e),r=function(t,e,n){var r=n.css,o=n.sourceMap,i=void 0===e.convertToAbsoluteUrls&&o;(e.convertToAbsoluteUrls||i)&&(r=f(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=t.href;t.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,e),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=g(e),r=function(t,e){var n=e.css,r=e.media;r&&t.setAttribute("media",r);if(t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;r(t=e)}else o()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=a()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=d(t,e);return p(n,e),function(t){for(var r=[],o=0;o=0&&h.splice(e,1)}function b(t){var e=document.createElement("style");if(void 0===t.attrs.type&&(t.attrs.type="text/css"),void 0===t.attrs.nonce){var n=function(){0;return o.nc}();n&&(t.attrs.nonce=n)}return v(e,t.attrs),p(t,e),e}function v(t,e){Object.keys(e).forEach(function(o){t.setAttribute(o,e[o])})}function g(t,e){var o,n,i,r;if(e.transform&&t.css){if(!(r="function"==typeof e.transform?e.transform(t.css):e.transform.default(t.css)))return function(){};t.css=r}if(e.singleton){var l=c++;o=a||(a=b(e)),n=w.bind(null,o,l,!1),i=w.bind(null,o,l,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(o=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",v(e,t.attrs),p(t,e),e}(e),n=function(t,e,o){var n=o.css,i=o.sourceMap,r=void 0===e.convertToAbsoluteUrls&&i;(e.convertToAbsoluteUrls||r)&&(n=d(n));i&&(n+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(i))))+" */");var l=new Blob([n],{type:"text/css"}),s=t.href;t.href=URL.createObjectURL(l),s&&URL.revokeObjectURL(s)}.bind(null,o,e),i=function(){_(o),o.href&&URL.revokeObjectURL(o.href)}):(o=b(e),n=function(t,e){var o=e.css,n=e.media;n&&t.setAttribute("media",n);if(t.styleSheet)t.styleSheet.cssText=o;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(o))}}.bind(null,o),i=function(){_(o)});return n(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;n(t=e)}else i()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=l()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var o=f(t,e);return u(o,e),function(t){for(var n=[],i=0;i'},function(t,e,o){const n=o(12).TableConstructor,i=o(11),r={input:"tc-table__inp"};t.exports=class{static get enableLineBreaks(){return!0}static get toolbox(){return{icon:i,title:"Table"}}constructor({data:t,config:e,api:o}){this.api=o,this._tableConstructor=new n(t,e,o)}render(){return this._tableConstructor.htmlElement}save(t){const e=[],o=t.querySelector("table").rows;for(let t=0;tt.querySelector("."+r.input));i.every(this._isEmpty)||e.push(i.map(t=>t.innerHTML))}return{content:e}}_isEmpty(t){return!t.textContent.trim()}}},function(t,e,o){var n=o(5);"string"==typeof n&&(n=[[t.i,n,""]]);var i={hmr:!0,transform:void 0,insertInto:void 0};o(1)(n,i);n.locals&&(t.exports=n.locals)},function(t,e,o){(t.exports=o(0)(!1)).push([t.i,".tc-editor{padding:10px;position:relative;box-sizing:content-box;width:100%;left:-10px}",""])},function(t,e){t.exports=function(t){var e="undefined"!=typeof window&&window.location;if(!e)throw new Error("fixUrls requires window.location");if(!t||"string"!=typeof t)return t;var o=e.protocol+"//"+e.host,n=o+e.pathname.replace(/\/[^\/]*$/,"/");return t.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,function(t,e){var i,r=e.trim().replace(/^"(.*)"$/,function(t,e){return e}).replace(/^'(.*)'$/,function(t,e){return e});return/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(r)?t:(i=0===r.indexOf("//")?r:0===r.indexOf("/")?o+r:n+r.replace(/^\.\//,""),"url("+JSON.stringify(i)+")")})}},function(t,e,o){var n=o(8);"string"==typeof n&&(n=[[t.i,n,""]]);var i={hmr:!0,transform:void 0,insertInto:void 0};o(1)(n,i);n.locals&&(t.exports=n.locals)},function(t,e,o){(t.exports=o(0)(!1)).push([t.i,".tc-toolbar{background:#368be6;}.tc-toolbar--hidden{visibility:hidden}.tc-toolbar--hor{width:100%;height:21px;flex-direction:row;left:0;top:1px}.tc-toolbar--hor,.tc-toolbar--ver{display:flex;align-items:center;position:absolute;z-index:100}.tc-toolbar--ver{height:100%;width:21px;flex-direction:column;top:0;left:-1px}.tc-toolbar__plus{height:21px;width:21px;margin-top:0;}.tc-toolbar__plus--hor{margin-left:-10px}.tc-toolbar__plus--ver{margin-top:-10px}.tc-toolbar__shine-line--hor{min-height:1px;width:100%}.tc-toolbar__shine-line--ver{min-width:1px;height:100%}",""])},function(t,e,o){var n=o(10);"string"==typeof n&&(n=[[t.i,n,""]]);var i={hmr:!0,transform:void 0,insertInto:void 0};o(1)(n,i);n.locals&&(t.exports=n.locals)},function(t,e,o){(t.exports=o(0)(!1)).push([t.i,".tc-table{width:100%;height:100%;border-collapse:collapse;table-layout:fixed;}.tc-table__wrap{border:1px solid #dbdbe2;border-radius:3px;position:relative;height:100%;width:100%;box-sizing:border-box}.tc-table__cell{border:1px solid #dbdbe2;padding:0;vertical-align:top}.tc-table__area{padding:10px;height:100%}.tc-table__inp{outline:none;flex-grow:100;min-height:1.5em;height:100%;overflow:hidden}.tc-table tbody tr:first-child td{border-top:none}.tc-table tbody tr:last-child td{border-bottom:none}.tc-table tbody tr td:last-child{border-right:none}.tc-table tbody tr td:first-child{border-left:none}",""])},function(t,e){t.exports=''},function(t,e,o){"use strict";o.r(e);o(4);function n(t){return!(null==t)}function i(t,e=null,o=null,i=null){const r=document.createElement(t);if(n(e))for(let t=0;t=-1&&e-t.x1<=11&&(n="left"),t.x2-e>=-1&&t.x2-e<=11&&(n="right"),o-t.y1>=-1&&o-t.y1<=11&&(n="top"),t.y2-o>=-1&&t.y2-o<=11&&(n="bottom"),n}o(7);var s=o(2),a=o.n(s);const c={highlightingLine:"tc-toolbar",hidden:"tc-toolbar--hidden",horizontalToolBar:"tc-toolbar--hor",horizontalHighlightingLine:"tc-toolbar__shine-line--hor",verticalToolBar:"tc-toolbar--ver",verticalHighlightingLine:"tc-toolbar__shine-line--ver",plusButton:"tc-toolbar__plus",horizontalPlusButton:"tc-toolbar__plus--hor",verticalPlusButton:"tc-toolbar__plus--ver",area:"tc-table__area"};class h{constructor(){this._plusButton=this._generatePlusButton(),this._highlightingLine=this._generateHighlightingLine(),this._toolbar=this._generateToolBar([this._plusButton,this._highlightingLine])}hide(){this._toolbar.classList.add(c.hidden)}show(){this._toolbar.classList.remove(c.hidden),this._highlightingLine.classList.remove(c.hidden)}hideLine(){this._highlightingLine.classList.add(c.hidden)}get htmlElement(){return this._toolbar}_generatePlusButton(){const t=i("div",[c.plusButton]);return t.innerHTML=a.a,t.addEventListener("click",t=>{t.stopPropagation();const e=new CustomEvent("click",{detail:{x:t.pageX,y:t.pageY},bubbles:!0});this._toolbar.dispatchEvent(e)}),t}_generateHighlightingLine(){const t=i("div",[c.highlightingLine]);return t.addEventListener("click",t=>{t.stopPropagation();const e=new CustomEvent("click",{bubbles:!0});this._toolbar.dispatchEvent(e)}),t}_generateToolBar(t){const e=i("div",[c.hidden],null,t);return e.addEventListener("mouseleave",t=>{this._recalcMousePos(t)}),e}_recalcMousePos(t){this.hide();const e=document.elementFromPoint(t.pageX,t.pageY);if(null!==e&&e.classList.contains(c.area)){const o=new MouseEvent("mouseover",{clientX:t.pageX,clientY:t.pageY});e.dispatchEvent(o)}}}class d extends h{constructor(){super(),this._toolbar.classList.add(c.horizontalToolBar),this._plusButton.classList.add(c.horizontalPlusButton),this._highlightingLine.classList.add(c.horizontalHighlightingLine)}showIn(t){const e=Math.floor(Number.parseInt(window.getComputedStyle(this._toolbar).height)/2);this._toolbar.style.top=t-e+"px",this.show()}}class u extends h{constructor(){super(),this._toolbar.classList.add(c.verticalToolBar),this._plusButton.classList.add(c.verticalPlusButton),this._highlightingLine.classList.add(c.verticalHighlightingLine)}showIn(t){const e=Math.floor(Number.parseInt(window.getComputedStyle(this._toolbar).width)/2);this._toolbar.style.left=t-e+"px",this.show()}}o(9);const f={table:"tc-table",inputField:"tc-table__inp",cell:"tc-table__cell",wrapper:"tc-table__wrap",area:"tc-table__area"};class p{constructor(){this._numberOfColumns=0,this._numberOfRows=0,this._element=this._createTableWrapper(),this._table=this._element.querySelector("table"),this._hangEvents()}addColumn(t=-1){this._numberOfColumns++;const e=this._table.rows;for(let o=0;o{this._focusEditField(t)},!0),this._table.addEventListener("blur",t=>{this._blurEditField(t)},!0),this._table.addEventListener("keydown",t=>{this._pressedEnterInEditField(t)}),this._table.addEventListener("click",t=>{this._clickedOnCell(t)}),this._table.addEventListener("mouseover",t=>{this._mouseEnterInDetectArea(t),t.stopPropagation()},!0)}_focusEditField(t){t.target.classList.contains(f.inputField)&&(this._selectedCell=t.target.closest("."+f.cell))}_blurEditField(t){t.target.classList.contains(f.inputField)&&(this._selectedCell=null)}_pressedEnterInEditField(t){t.target.classList.contains(f.inputField)&&(13!==t.keyCode||t.shiftKey||t.preventDefault())}_clickedOnCell(t){if(!t.target.classList.contains(f.cell))return;t.target.querySelector("."+f.inputField).focus()}_mouseEnterInDetectArea(t){if(!t.target.classList.contains(f.area))return;const e=l(r(t.target.closest("TD")),t.pageX,t.pageY);t.target.dispatchEvent(new CustomEvent("mouseInActivatingArea",{detail:{side:e},bubbles:!0}))}}o.d(e,"TableConstructor",function(){return b});const _={editor:"tc-editor",toolBarHor:"tc-toolbar--hor",toolBarVer:"tc-toolbar--ver",inputField:"tc-table__inp"};class b{constructor(t,e,o){this._table=new p;const n=this._resizeTable(t,e);this._fillTable(t,n),this._container=i("div",[_.editor,o.styles.block],null,[this._table.htmlElement]),this._verticalToolBar=new u,this._horizontalToolBar=new d,this._table.htmlElement.appendChild(this._horizontalToolBar.htmlElement),this._table.htmlElement.appendChild(this._verticalToolBar.htmlElement),this._hoveredCell=null,this._activatedToolBar=null,this._hoveredCellSide=null,this._plusButDelay=null,this._toolbarShowDelay=null,this._hangEvents()}get htmlElement(){return this._container}_fillTable(t,e){if(void 0!==t.content)for(let o=0;o0?l:void 0,c=!isNaN(s)&&s>0?s:void 0,h=i||a||2,d=r||c||2;for(let t=0;t{this._toolbarCalling(t)}),this._container.addEventListener("click",t=>{this._clickToolbar(t)}),this._container.addEventListener("input",()=>{this._hideToolBar()}),this._container.addEventListener("keydown",t=>{this._containerKeydown(t)}),this._container.addEventListener("mouseout",t=>{this._leaveDetectArea(t)}),this._container.addEventListener("mouseover",t=>{this._mouseEnterInDetectArea(t)})}_mouseInActivatingAreaListener(t){this._hoveredCellSide=t.detail.side;const e=r(t.target),o=r(this._table.htmlElement);if(this._hoveredCell=t.target.closest("TD"),null===this._hoveredCell){const t=11;this._hoveredCell=this._container,e.x1+=t,e.y1+=t,e.x2-=t,e.y2-=t}"top"===this._hoveredCellSide&&this._showToolBar(this._horizontalToolBar,e.y1-o.y1-2),"bottom"===this._hoveredCellSide&&this._showToolBar(this._horizontalToolBar,e.y2-o.y1-1),"left"===this._hoveredCellSide&&this._showToolBar(this._verticalToolBar,e.x1-o.x1-2),"right"===this._hoveredCellSide&&this._showToolBar(this._verticalToolBar,e.x2-o.x1-1)}_isToolbar(t){return!(!t.closest("."+_.toolBarHor)&&!t.closest("."+_.toolBarVer))}_leaveDetectArea(t){this._isToolbar(t.relatedTarget)||(clearTimeout(this._toolbarShowDelay),this._hideToolBar())}_toolbarCalling(t){this._isToolbar(t.target)||(clearTimeout(this._toolbarShowDelay),this._toolbarShowDelay=setTimeout(()=>{this._mouseInActivatingAreaListener(t)},125))}_clickToolbar(t){if(!this._isToolbar(t.target))return;let e;if(this._activatedToolBar===this._horizontalToolBar?(this._addRow(),e="y"):(this._addColumn(),e="x"),isNaN(t.detail)&&null!==t.detail){const o=r(this._table.htmlElement);let n;n="x"===e?t.detail.x-o.x1:t.detail.y-o.y1,this._delayAddButtonForMultiClickingNearMouse(n)}else this._hideToolBar()}_containerKeydown(t){13===t.keyCode&&this._containerEnterPressed(t)}_delayAddButtonForMultiClickingNearMouse(t){this._showToolBar(this._activatedToolBar,t),this._activatedToolBar.hideLine(),clearTimeout(this._plusButDelay),this._plusButDelay=setTimeout(()=>{this._hideToolBar()},500)}_getHoveredSideOfContainer(){return this._hoveredCell===this._container?this._isBottomOrRight()?0:-1:1}_isBottomOrRight(){return"bottom"===this._hoveredCellSide||"right"===this._hoveredCellSide}_addRow(){const t=this._hoveredCell.closest("TR");let e=this._getHoveredSideOfContainer();1===e&&(e=t.sectionRowIndex,e+=this._isBottomOrRight()),this._table.addRow(e)}_addColumn(){let t=this._getHoveredSideOfContainer();1===t&&(t=this._hoveredCell.cellIndex,t+=this._isBottomOrRight()),this._table.addColumn(t)}_containerEnterPressed(t){if(null===this._table.selectedCell||t.shiftKey)return;const e=this._table.selectedCell.closest("TR");let o=this._getHoveredSideOfContainer();1===o&&(o=e.sectionRowIndex+1),this._table.addRow(o).cells[0].click()}_mouseEnterInDetectArea(t){let e=l(r(this._container),t.pageX,t.pageY);t.target.dispatchEvent(new CustomEvent("mouseInActivatingArea",{detail:{side:e},bubbles:!0}))}}}])}); -------------------------------------------------------------------------------- /src/assets/editorjs/warning/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/assets/editorjs/warning/README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/CodeX%20Editor/v2.0/blue) 2 | 3 | # Warning Tool 4 | 5 | Provides Warning Block for the [CodeX Editor](https://ifmo.su/editor). Block has title and message. It can be used, for example, for editorials notifications or appeals. 6 | 7 | ![](https://capella.pics/2d7b7bc1-ac46-4020-89c9-390d1a7297e2.jpg) 8 | 9 | ## Installation 10 | 11 | ### Install via NPM 12 | 13 | Get the package 14 | 15 | ```shell 16 | npm i --save-dev @editorjs/warning 17 | ``` 18 | 19 | Include module at your application 20 | 21 | ```javascript 22 | const Warning = require('@editorjs/warning'); 23 | ``` 24 | 25 | ### Download to your project's source dir 26 | 27 | 1. Upload folder `dist` from repository 28 | 2. Add `dist/bundle.js` file to your page. 29 | 30 | ### Load from CDN 31 | 32 | You can load specific version of package from [jsDelivr CDN](https://www.jsdelivr.com/package/npm/@editorjs/warning). 33 | 34 | `https://cdn.jsdelivr.net/npm/@editorjs/warning@latest` 35 | 36 | Then require this script on page with CodeX Editor. 37 | 38 | ```html 39 | 40 | ``` 41 | 42 | ## Usage 43 | 44 | Add a new Tool to the `tools` property of the CodeX Editor initial config. 45 | 46 | ```javascript 47 | var editor = CodexEditor({ 48 | ... 49 | 50 | tools: { 51 | ... 52 | warning: Warning, 53 | }, 54 | 55 | ... 56 | }); 57 | ``` 58 | 59 | Or init Warning Tool with additional settings 60 | 61 | ```javascript 62 | var editor = CodexEditor({ 63 | ... 64 | 65 | tools: { 66 | ... 67 | warning: { 68 | class: Warning, 69 | inlineToolbar: true, 70 | shortcut: 'CMD+SHIFT+W', 71 | config: { 72 | titlePlaceholder: 'Title', 73 | messagePlaceholder: 'Message', 74 | }, 75 | }, 76 | }, 77 | 78 | ... 79 | }); 80 | ``` 81 | 82 | ## Config Params 83 | 84 | | Field | Type | Description | 85 | | ------------------ | -------- | ----------------------------------| 86 | | titlePlaceholder | `string` | Warning Tool's title placeholder | 87 | | messagePlaceholder | `string` | Warning Tool's message placeholder| 88 | 89 | ## Output data 90 | 91 | | Field | Type | Description | 92 | | --------- | -------- | -----------------| 93 | | title | `string` | warning's title | 94 | | message | `string` | warning's message| 95 | 96 | ```json 97 | { 98 | "type" : "warning", 99 | "data" : { 100 | "title" : "Note:", 101 | "message" : "Avoid using this method just for lulz. It can be very dangerous opposite your daily fun stuff." 102 | } 103 | } 104 | ``` 105 | -------------------------------------------------------------------------------- /src/assets/editorjs/warning/bundle.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Warning=e():t.Warning=e()}(window,function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=1)}([function(t,e){t.exports=''},function(t,e,n){"use strict";n.r(e),n.d(e,"default",function(){return c});var r=n(0),o=n.n(r);function i(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=document.createElement(t);Array.isArray(n)?(e=o.classList).add.apply(e,i(n)):n&&o.classList.add(n);for(var a in r)o[a]=r[a];return o}}],[{key:"sanitize",get:function(){return{title:{},message:{}}}}]),t}()},function(t,e,n){var r=n(3);"string"==typeof r&&(r=[[t.i,r,""]]);var o={hmr:!0,transform:void 0,insertInto:void 0};n(5)(r,o);r.locals&&(t.exports=r.locals)},function(t,e,n){(t.exports=n(4)(!1)).push([t.i,".cdx-warning {\n position: relative;\n}\n\n.cdx-warning [contentEditable=true][data-placeholder]::before{\n position: absolute;\n content: attr(data-placeholder);\n color: #707684;\n font-weight: normal;\n opacity: 0;\n}\n\n.cdx-warning [contentEditable=true][data-placeholder]:empty::before {\n opacity: 1;\n}\n\n.cdx-warning [contentEditable=true][data-placeholder]:empty:focus::before {\n opacity: 0;\n}\n\n\n.cdx-warning::before {\n content: '';\n background-image: url(\"data:image/svg+xml,%3Csvg width='16' height='17' viewBox='0 0 320 294' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cpath fill='%237B7E89' d='M160.5 97c12.426 0 22.5 10.074 22.5 22.5v28c0 12.426-10.074 22.5-22.5 22.5S138 159.926 138 147.5v-28c0-12.426 10.074-22.5 22.5-22.5zm0 83c14.636 0 26.5 11.864 26.5 26.5S175.136 233 160.5 233 134 221.136 134 206.5s11.864-26.5 26.5-26.5zm-.02-135c-6.102 0-14.05 8.427-23.842 25.28l-74.73 127.605c-12.713 21.444-17.806 35.025-15.28 40.742 2.527 5.717 8.519 9.175 17.974 10.373h197.255c5.932-1.214 10.051-4.671 12.357-10.373 2.307-5.702-1.812-16.903-12.357-33.603L184.555 70.281C174.608 53.427 166.583 45 160.48 45zm154.61 165.418c2.216 6.027 3.735 11.967 4.393 18.103.963 8.977.067 18.035-3.552 26.98-7.933 19.612-24.283 33.336-45.054 37.586l-4.464.913H61.763l-2.817-.357c-10.267-1.3-19.764-4.163-28.422-9.16-11.051-6.377-19.82-15.823-25.055-27.664-4.432-10.03-5.235-19.952-3.914-29.887.821-6.175 2.486-12.239 4.864-18.58 3.616-9.64 9.159-20.55 16.718-33.309L97.77 47.603c6.469-11.125 12.743-20.061 19.436-27.158 4.62-4.899 9.562-9.07 15.206-12.456C140.712 3.01 150.091 0 160.481 0c10.358 0 19.703 2.99 27.989 7.933 5.625 3.356 10.563 7.492 15.193 12.354 6.735 7.072 13.08 15.997 19.645 27.12l.142.24 76.986 134.194c6.553 10.46 11.425 19.799 14.654 28.577z'/%3E%3C/svg%3E\");\n width: 18px;\n height: 18px;\n background-size: 18px 18px;\n position: absolute;\n margin-top: 12px;\n left: -30px;\n}\n\n@media all and (max-width: 735px) {\n .cdx-warning::before {\n display: none;\n }\n}\n\n.cdx-warning__message {\n min-height: 85px;\n}\n\n.cdx-warning__title {\n margin-bottom: 6px;\n}\n",""])},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map(function(e){var n=function(t,e){var n=t[1]||"",r=t[3];if(!r)return n;if(e&&"function"==typeof btoa){var o=(a=r,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),i=r.sources.map(function(t){return"/*# sourceURL="+r.sourceRoot+t+" */"});return[n].concat(i).concat([o]).join("\n")}var a;return[n].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n}).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var r={},o=0;o=0&&u.splice(e,1)}function g(t){var e=document.createElement("style");if(void 0===t.attrs.type&&(t.attrs.type="text/css"),void 0===t.attrs.nonce){var r=function(){0;return n.nc}();r&&(t.attrs.nonce=r)}return m(e,t.attrs),h(t,e),e}function m(t,e){Object.keys(e).forEach(function(n){t.setAttribute(n,e[n])})}function b(t,e){var n,r,o,i;if(e.transform&&t.css){if(!(i="function"==typeof e.transform?e.transform(t.css):e.transform.default(t.css)))return function(){};t.css=i}if(e.singleton){var a=l++;n=c||(c=g(e)),r=x.bind(null,n,a,!1),o=x.bind(null,n,a,!0)}else t.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(n=function(t){var e=document.createElement("link");return void 0===t.attrs.type&&(t.attrs.type="text/css"),t.attrs.rel="stylesheet",m(e,t.attrs),h(t,e),e}(e),r=function(t,e,n){var r=n.css,o=n.sourceMap,i=void 0===e.convertToAbsoluteUrls&&o;(e.convertToAbsoluteUrls||i)&&(r=f(r));o&&(r+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */");var a=new Blob([r],{type:"text/css"}),s=t.href;t.href=URL.createObjectURL(a),s&&URL.revokeObjectURL(s)}.bind(null,n,e),o=function(){v(n),n.href&&URL.revokeObjectURL(n.href)}):(n=g(e),r=function(t,e){var n=e.css,r=e.media;r&&t.setAttribute("media",r);if(t.styleSheet)t.styleSheet.cssText=n;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(n))}}.bind(null,n),o=function(){v(n)});return r(t),function(e){if(e){if(e.css===t.css&&e.media===t.media&&e.sourceMap===t.sourceMap)return;r(t=e)}else o()}}t.exports=function(t,e){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(e=e||{}).attrs="object"==typeof e.attrs?e.attrs:{},e.singleton||"boolean"==typeof e.singleton||(e.singleton=a()),e.insertInto||(e.insertInto="head"),e.insertAt||(e.insertAt="bottom");var n=p(t,e);return d(n,e),function(t){for(var r=[],o=0;o 16 | * @link https://github.com/zakurdaev/yii2-editorjs-widget 17 | * @license https://github.com/zakurdaev/yii2-editorjs-widget/blob/master/LICENSE.md 18 | */ 19 | class JsonToHtmlBehavior extends Behavior 20 | { 21 | /** 22 | * @var string|array the attribute or list of attributes whose value will be converted into a html 23 | */ 24 | public $jsonAttribute = 'content_json'; 25 | 26 | /** 27 | * @var string|array the attribute or list attributes that will receive the generated html 28 | */ 29 | public $htmlAttribute = 'content'; 30 | 31 | /** 32 | * @var array {@link https://github.com/editor-js/editorjs-php EditorJS PHP Configuration} description of plug-in units. 33 | * Set default value in Yii::$app->params['editorjs-widget/rules'] to array in your application config params.php and use global settings 34 | * If the variable is not set, standard values will be used. 35 | */ 36 | public $convertConfiguration; 37 | 38 | /** 39 | * @var string Render class name 40 | */ 41 | public $renderClass = JsonToHtml::RENDER_CLASS; 42 | 43 | public function events() 44 | { 45 | return [ 46 | ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeSave', 47 | ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave', 48 | ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave', 49 | ]; 50 | } 51 | 52 | /** 53 | * @param $event 54 | * @throws ServerErrorHttpException 55 | */ 56 | public function beforeSave($event) 57 | { 58 | /** @var ActiveRecord $owner */ 59 | $owner = $this->owner; 60 | 61 | foreach ((array)$this->jsonAttribute as $i => $attribute) { 62 | $targetAttribute = ArrayHelper::getValue((array)$this->htmlAttribute, $i); 63 | try { 64 | $converter = new JsonToHtml([ 65 | 'value' => $owner->{$attribute}, 66 | 'configuration' => $this->convertConfiguration, 67 | 'renderClass' => $this->renderClass 68 | ]); 69 | $owner->{$targetAttribute} = $converter->run(); 70 | } catch (EditorJSException $e) { 71 | throw new ServerErrorHttpException($attribute . ' could not convert before saving'); 72 | } 73 | } 74 | } 75 | } 76 | --------------------------------------------------------------------------------