diff --git a/motorradig/app/Http/Controllers/UserController.php b/motorradig/app/Http/Controllers/UserController.php index 67f893b..138a77f 100644 --- a/motorradig/app/Http/Controllers/UserController.php +++ b/motorradig/app/Http/Controllers/UserController.php @@ -102,22 +102,17 @@ class UserController extends Controller if ($breite>$hoehe) { Image::make($request->bild) ->widen(1200) - ->save(public_path().'/img/user/'.$user->id.'_gross.jpg') - ->save(storage_path().'/img/user/'.$user->id.'_gross.jpg'); + ->save(storage_path().'/img_storage/user/'.$user->id.'_gross.jpg'); Image::make($request->bild) ->widen(64) - ->save(public_path().'/img/user/'.$user->id.'.jpg') - ->save(storage_path().'/img/user/'.$user->id.'.jpg'); + ->save(storage_path().'/img_storage/user/'.$user->id.'.jpg'); }else { Image::make($request->bild) ->heighten(900) - ->save(public_path().'/img/user/'.$user->id.'_gross.jpg') - ->save(storage_path().'/img/user/'.$user->id.'_gross.jpg'); + ->save(storage_path().'/img_storage/user/'.$user->id.'_gross.jpg'); Image::make($request->bild) ->widen(96) - ->save(public_path().'/img/user/'.$user->id.'.jpg') - ->save(storage_path().'/img/user/'.$user->id.'.jpg'); - + ->save(storage_path().'/img_storage/user/'.$user->id.'.jpg'); } } diff --git a/motorradig/package-lock.json b/motorradig/package-lock.json index 9b8a310..a265057 100644 --- a/motorradig/package-lock.json +++ b/motorradig/package-lock.json @@ -8596,6 +8596,11 @@ } } }, + "suneditor": { + "version": "2.36.4", + "resolved": "https://registry.npmjs.org/suneditor/-/suneditor-2.36.4.tgz", + "integrity": "sha512-xOB96cQWzt8PQ8fSF6Q5NzxMPpOFTeaQBbHTx+ZuUt6s7hxh2LE8bh0yU+hLmeoXfBCTtV/A0zb+e7sLy2G0BA==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/motorradig/package.json b/motorradig/package.json index db2c0f4..248b8c8 100644 --- a/motorradig/package.json +++ b/motorradig/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@fortawesome/fontawesome-free": "^5.14.0", - "lightbox2": "^2.11.3" + "lightbox2": "^2.11.3", + "suneditor": "^2.36.4" } } diff --git a/motorradig/public/img/user/1.jpg b/motorradig/public/img/user/1.jpg deleted file mode 100644 index 1866ed6..0000000 Binary files a/motorradig/public/img/user/1.jpg and /dev/null differ diff --git a/motorradig/public/img/user/1_gross.jpg b/motorradig/public/img/user/1_gross.jpg deleted file mode 100644 index 8c5f2be..0000000 Binary files a/motorradig/public/img/user/1_gross.jpg and /dev/null differ diff --git a/motorradig/public/js/app.js b/motorradig/public/js/app.js index ecb1293..7a6a240 100644 --- a/motorradig/public/js/app.js +++ b/motorradig/public/js/app.js @@ -6386,6 +6386,112 @@ module.exports = { //# sourceMappingURL=bootstrap.js.map +/***/ }), + +/***/ "./node_modules/css-loader/index.js?!./node_modules/postcss-loader/src/index.js?!./node_modules/suneditor/dist/css/suneditor.min.css": +/*!*******************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader??ref--6-1!./node_modules/postcss-loader/src??ref--6-2!./node_modules/suneditor/dist/css/suneditor.min.css ***! + \*******************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sun-editor{width:auto;height:auto;box-sizing:border-box;font-family:Helvetica Neue,sans-serif;border:1px solid #dadada;background-color:#fff;color:#000;user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.sun-editor *{box-sizing:border-box;-webkit-user-drag:none;overflow:visible}.sun-editor-common button,.sun-editor-common input,.sun-editor-common select,.sun-editor-common textarea{font-size:14px;line-height:1.5}.sun-editor-common blockquote,.sun-editor-common body,.sun-editor-common button,.sun-editor-common code,.sun-editor-common dd,.sun-editor-common div,.sun-editor-common dl,.sun-editor-common dt,.sun-editor-common fieldset,.sun-editor-common form,.sun-editor-common h1,.sun-editor-common h2,.sun-editor-common h3,.sun-editor-common h4,.sun-editor-common h5,.sun-editor-common h6,.sun-editor-common input,.sun-editor-common legend,.sun-editor-common li,.sun-editor-common ol,.sun-editor-common p,.sun-editor-common pre,.sun-editor-common select,.sun-editor-common td,.sun-editor-common textarea,.sun-editor-common th,.sun-editor-common ul{margin:0;padding:0;border:0}.sun-editor-common dl,.sun-editor-common li,.sun-editor-common menu,.sun-editor-common ol,.sun-editor-common ul{list-style:none!important}.sun-editor-common hr{margin:6px 0!important}.sun-editor textarea{resize:none;border:0;padding:0}.sun-editor button{border:0;background-color:transparent;touch-action:manipulation;cursor:pointer;outline:none}.sun-editor button,.sun-editor input,.sun-editor select,.sun-editor textarea{vertical-align:middle}.sun-editor button span{display:block;margin:0;padding:0}.sun-editor button .txt{display:block;margin-top:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sun-editor button *{pointer-events:none;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden}.sun-editor .se-svg,.sun-editor button>svg{width:16px;height:16px;margin:auto;fill:currentColor;display:block;text-align:center;float:none}.sun-editor .close>svg,.sun-editor .se-dialog-close>svg{width:10px;height:10px}.sun-editor .se-btn-select>svg{float:right;width:10px;height:10px}.sun-editor .se-btn-list>.se-list-icon{display:inline-block;width:16px;height:16px;margin:-1px 10px 0 0;vertical-align:middle}.sun-editor .se-line-breaker>button>svg{width:24px;height:24px}.sun-editor button>i:before{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;font-size:15px;line-height:2}.sun-editor button>[class=se-icon-text]{font-size:20px;line-height:1}.sun-editor .se-arrow,.sun-editor .se-arrow:after{position:absolute;display:block;width:0;height:0;border:11px solid transparent}.sun-editor .se-arrow.se-arrow-up{top:-11px;left:20px;margin-left:-11px;border-top-width:0;border-bottom-color:#dadada}.sun-editor .se-arrow.se-arrow-up:after{top:1px;margin-left:-11px;content:\" \";border-top-width:0;border-bottom-color:#fff}.sun-editor .se-toolbar .se-arrow.se-arrow-up:after{border-bottom-color:#fafafa}.sun-editor .se-arrow.se-arrow-down{top:0;left:0;margin-left:-11px;border-bottom-width:0;border-top-color:#dadada}.sun-editor .se-arrow.se-arrow-down:after{top:-12px;margin-left:-11px;content:\" \";border-bottom-width:0;border-top-color:#fff}.sun-editor .se-toolbar .se-arrow.se-arrow-down:after{border-top-color:#fafafa}.sun-editor .se-container{position:relative;width:100%;height:100%}.sun-editor button{color:#000}.sun-editor .se-btn{float:left;width:34px;height:34px;border:0;border-radius:4px;margin:1px!important;padding:0;font-size:12px;line-height:27px}.sun-editor .se-btn:enabled:focus,.sun-editor .se-btn:enabled:hover{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-btn:enabled:active{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-btn-primary{color:#000;background-color:#c7deff;border:1px solid #80bdff;border-radius:4px}.sun-editor .se-btn-primary:focus,.sun-editor .se-btn-primary:hover{color:#000;background-color:#80bdff;border-color:#3f9dff;outline:0 none}.sun-editor .se-btn-primary:active{color:#fff;background-color:#3f9dff;border-color:#4592ff;box-shadow:inset 0 3px 5px #4592ff}.sun-editor input,.sun-editor select,.sun-editor textarea{color:#000;border:1px solid #ccc;border-radius:4px}.sun-editor input:focus,.sun-editor select:focus,.sun-editor textarea:focus{border:1px solid #80bdff;outline:0;box-shadow:0 0 0 .2rem #c7deff;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.sun-editor .se-btn:enabled.active{color:#4592ff;outline:0 none}.sun-editor .se-btn:enabled.active:focus,.sun-editor .se-btn:enabled.active:hover{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-btn:enabled.active:active{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-btn:enabled.on{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-btn:enabled.on:focus,.sun-editor .se-btn:enabled.on:hover{background-color:#d1d1d1;border-color:#c1c1c1;outline:0 none}.sun-editor .se-btn:enabled.on:active{background-color:#c1c1c1;border-color:#b1b1b1;box-shadow:inset 0 3px 5px #b1b1b1}.sun-editor .se-btn-list:disabled,.sun-editor .se-btn:disabled,.sun-editor button:disabled{cursor:not-allowed;background-color:inherit;color:#bdbdbd}.sun-editor .se-loading-box{position:absolute;display:none;width:100%;height:100%;top:0;left:0;background-color:#fff;opacity:.7;filter:alpha(opacity=70);z-index:2147483647}.sun-editor .se-loading-box .se-loading-effect{position:absolute;display:block;top:50%;left:50%;height:25px;width:25px;border-top:2px solid #07d;border-right:2px solid transparent;border-radius:50%;-webkit-animation:spinner .8s linear infinite;animation:spinner .8s linear infinite;margin:-25px 0 0 -25px}.sun-editor .se-line-breaker{position:absolute;display:none;width:100%;height:1px;cursor:text;border-top:1px solid #3288ff;z-index:7}.sun-editor .se-line-breaker>button.se-btn{position:relative;display:inline-block;width:30px;height:30px;top:-15px;float:none;left:-50%;background-color:#fff;border:1px solid #0c2240;opacity:.6;cursor:pointer}.sun-editor .se-line-breaker>button.se-btn:hover{opacity:.9;background-color:#fff;border-color:#041b39}.sun-editor .se-line-breaker-component{position:absolute;display:none;width:24px;height:24px;background-color:#fff;border:1px solid #0c2240;opacity:.6;border-radius:4px;cursor:pointer;z-index:7}.sun-editor .se-line-breaker-component:hover{opacity:.9}.sun-editor .se-toolbar{display:block;position:relative;height:auto;width:100%;overflow:visible;padding:0;margin:0;background-color:#fafafa;outline:1px solid #dadada;z-index:5}.sun-editor .se-toolbar-cover{position:absolute;display:none;font-size:36px;width:100%;height:100%;top:0;left:0;background-color:#fefefe;opacity:.5;filter:alpha(opacity=50);cursor:not-allowed;z-index:4}.sun-editor .se-toolbar-separator-vertical{display:inline-block;height:0;width:0;margin:1px;vertical-align:top}.sun-editor .se-toolbar.se-toolbar-balloon,.sun-editor .se-toolbar.se-toolbar-inline{display:none;position:absolute;box-shadow:0 3px 9px rgba(0,0,0,.5);-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5)}.sun-editor .se-toolbar.se-toolbar-balloon{z-index:2147483647;width:auto}.sun-editor .se-toolbar.se-toolbar-sticky{position:fixed;top:0}.sun-editor .se-toolbar-sticky-dummy{display:none;position:static;z-index:-1}.sun-editor .se-btn-module{display:inline-block}.sun-editor .se-btn-module-border{border:1px solid #dadada;border-radius:4px}.sun-editor .se-btn-module-enter{display:block;width:100%;height:1px;margin-bottom:5px;background-color:transparent}.sun-editor .se-toolbar-more-layer{margin:0 -3px;background-color:#fafafa}.sun-editor .se-toolbar-more-layer .se-more-layer{display:none;border-top:1px solid #dadada}.sun-editor .se-toolbar-more-layer .se-more-layer .se-more-form{display:inline-block;width:100%;height:auto;padding:4px 3px 0}.sun-editor .se-btn-module .se-btn-more.se-btn-more-text{width:auto;padding:0 4px}.sun-editor .se-btn-module .se-btn-more:focus,.sun-editor .se-btn-module .se-btn-more:hover{color:#000;background-color:#d1d1d1;border-color:#c1c1c1;outline:0 none}.sun-editor .se-btn-module .se-btn-more.on{color:#333;background-color:#d1d1d1;border-color:#c1c1c1;outline:0 none}.sun-editor .se-btn-module .se-btn-more.on:hover{color:#000;background-color:#c1c1c1;border-color:#b1b1b1;outline:0 none}.sun-editor .se-menu-list,.sun-editor .se-menu-list li{float:left;padding:0;margin:0}.sun-editor .se-menu-list li{position:relative}.sun-editor .se-btn-select{width:auto;display:flex;padding:4px 6px}.sun-editor .se-btn-select .txt{flex:auto;text-align:left}.sun-editor.se-rtl .se-btn-select svg{margin:auto 1px}.sun-editor .se-btn-select.se-btn-tool-font{width:100px}.sun-editor .se-btn-select.se-btn-tool-format{width:82px}.sun-editor .se-btn-select.se-btn-tool-size{width:78px}.sun-editor .se-btn-tray{position:relative;width:100%;height:auto;padding:4px 3px 0;margin:0}.sun-editor .se-menu-tray{position:absolute;top:0;left:0;width:100%;height:0}.sun-editor .se-submenu{overflow-x:hidden;overflow-y:auto}.sun-editor .se-list-layer{display:none;position:absolute;top:0;left:0;height:auto;z-index:5;border:1px solid #bababa;border-radius:4px;padding:6px 0;background-color:#fff;box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0 none}.sun-editor .se-list-layer .se-list-inner{padding:0;margin:0;overflow-x:initial;overflow-y:initial;overflow:visible}.sun-editor .se-list-layer button{margin:0;width:100%}.sun-editor .se-list-inner ul{width:100%;padding:0}.sun-editor .se-list-inner li>button{min-width:100%;width:-webkit-max-content;width:-moz-max-content;width:max-content}.sun-editor .se-list-inner .se-list-basic li{width:100%}.sun-editor .se-list-inner .se-list-basic li button.active{background-color:#80bdff;border:1px solid #3f9dff;border-left:0;border-right:0}.sun-editor .se-list-inner .se-list-basic li button.active:hover{background-color:#3f9dff;border:1px solid #4592ff;border-left:0;border-right:0}.sun-editor .se-list-inner .se-list-basic li button.active:active{background-color:#4592ff;border:1px solid #407dd1;border-left:0;border-right:0;box-shadow:inset 0 3px 5px #407dd1}.sun-editor .se-list-inner .se-list-checked li button>.se-svg{float:left;padding:6px 6px 0 0}.sun-editor .se-list-inner .se-list-checked li button>.se-svg>svg{display:none}.sun-editor .se-list-inner .se-list-checked li button.se-checked{color:#4592ff}.sun-editor .se-list-inner .se-list-checked li button.se-checked>.se-svg>svg{display:block}.sun-editor .se-btn-list{width:100%;height:auto;min-height:32px;padding:0 14px;cursor:pointer;font-size:12px;line-height:normal;text-indent:0;text-decoration:none;text-align:left}.sun-editor .se-btn-list.default_value{background-color:#f3f3f3;border-top:1px dotted #b1b1b1;border-bottom:1px dotted #b1b1b1}.sun-editor .se-btn-list:focus,.sun-editor .se-btn-list:hover{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-btn-list:active{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-list-layer.se-list-font-size{min-width:140px;max-height:300px}.sun-editor .se-list-layer.se-list-font-family{min-width:156px}.sun-editor .se-list-layer.se-list-font-family .default{border-bottom:1px solid #ccc}.sun-editor .se-list-layer.se-list-line{width:125px}.sun-editor .se-list-layer.se-list-align .se-list-inner{left:9px;width:125px}.sun-editor .se-list-layer.se-list-format{min-width:156px}.sun-editor .se-list-layer.se-list-format li{padding:0;width:100%}.sun-editor .se-list-layer.se-list-format ul .se-btn-list{line-height:100%}.sun-editor .se-list-layer.se-list-format ul .se-btn-list[data-value=h1]{height:40px}.sun-editor .se-list-layer.se-list-format ul .se-btn-list[data-value=h2]{height:34px}.sun-editor .se-list-layer.se-list-format ul p{font-size:13px}.sun-editor .se-list-layer.se-list-format ul div{font-size:13px;padding:4px 2px}.sun-editor .se-list-layer.se-list-format ul h1{font-size:2em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul h2{font-size:1.5em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul h3{font-size:1.17em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul h4{font-size:1em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul h5{font-size:.83em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul h6{font-size:.67em;font-weight:700;color:#333}.sun-editor .se-list-layer.se-list-format ul blockquote{font-size:13px;color:#999;height:22px;margin:0;background-color:transparent;line-height:1.5;border-color:#b1b1b1;padding:0 0 0 7px;border-left:5px #b1b1b1;border-style:solid}.sun-editor .se-list-layer.se-list-format ul pre{font-size:13px;color:#666;padding:4px 11px;margin:0;background-color:#f9f9f9;border:1px solid #e1e1e1;border-radius:4px}.sun-editor .se-selector-table{display:none;position:absolute;top:34px;left:1px;z-index:5;padding:5px 0;float:left;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border-radius:4px;box-shadow:0 6px 12px rgba(0,0,0,.175)}.sun-editor .se-selector-table .se-table-size{font-size:18px;padding:0 5px}.sun-editor .se-selector-table .se-table-size-picker{position:absolute!important;z-index:3;font-size:18px;width:10em;height:10em;cursor:pointer}.sun-editor .se-selector-table .se-table-size-highlighted{position:absolute!important;z-index:2;font-size:18px;width:1em;height:1em;background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAADJmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4QTZCNzMzN0I3RUYxMUU4ODcwQ0QwMjM1NTgzRTJDNyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4QTZCNzMzNkI3RUYxMUU4ODcwQ0QwMjM1NTgzRTJDNyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MzYyNEUxRUI3RUUxMUU4ODZGQzgwRjNBODgyNTdFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MzYyNEUxRkI3RUUxMUU4ODZGQzgwRjNBODgyNTdFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl0yAuwAAABBSURBVDhPY/wPBAxUAGCDGvdBeWSAeicIDTfIXREiQArYeR9hEBOEohyMGkQYjBpEGAxjg6ib+yFMygCVvMbAAABj0hwMTNeKJwAAAABJRU5ErkJggg==\") repeat}.sun-editor .se-selector-table .se-table-size-unhighlighted{position:relative!important;z-index:1;font-size:18px;width:10em;height:10em;background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC\") repeat}.sun-editor .se-selector-table .se-table-size-display{padding-left:5px}.sun-editor .se-list-layer.se-table-split{top:36px}.sun-editor .se-list-layer .se-selector-color{display:flex;width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:270px;height:auto;padding:0;margin:auto}.sun-editor .se-list-layer .se-selector-color .se-color-pallet{width:100%;height:100%;padding:0}.sun-editor .se-list-layer .se-selector-color .se-color-pallet li{display:flex;float:left;position:relative;margin:0}.sun-editor .se-list-layer .se-selector-color .se-color-pallet button{display:block;cursor:default;width:30px;height:30px;text-indent:-9999px}.sun-editor .se-list-layer .se-selector-color .se-color-pallet button.active,.sun-editor .se-list-layer .se-selector-color .se-color-pallet button:focus,.sun-editor .se-list-layer .se-selector-color .se-color-pallet button:hover{border:3px solid #fff}.sun-editor .se-form-group{display:flex;width:100%;min-height:40px;height:auto;padding:4px}.sun-editor .se-form-group input{flex:auto;display:inline-block;width:auto;height:33px;font-size:12px;margin:1px 0;padding:0;border-radius:.25rem;border:1px solid #ccc}.sun-editor .se-form-group button,.sun-editor .se-submenu-form-group button{float:right;width:34px;height:34px;margin:0 2px!important}.sun-editor .se-form-group button.se-btn{border:1px solid #ccc}.sun-editor .se-form-group>div{position:relative}.sun-editor .se-form-group label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}.sun-editor .se-form-group-label{width:100%;height:auto;padding:0 4px}.sun-editor .se-form-group-label label{font-size:13px;font-weight:700}.sun-editor .se-submenu .se-form-group input{width:auto;height:33px;color:#555}.sun-editor .se-submenu .se-form-group .se-color-input{width:72px;text-transform:uppercase;border:none;border-bottom:2px solid #b1b1b1;outline:none}.sun-editor .se-submenu .se-form-group .se-color-input:focus{border-bottom:3px solid #b1b1b1}.sun-editor .se-wrapper{position:relative!important;width:100%;height:auto;overflow:hidden;z-index:1}.sun-editor .se-wrapper .se-wrapper-inner{width:100%;height:100%;min-height:65px;overflow-y:auto;overflow-x:auto;-webkit-overflow-scrolling:touch;user-select:auto;-o-user-select:auto;-moz-user-select:auto;-khtml-user-select:auto;-webkit-user-select:auto;-ms-user-select:auto}.sun-editor .se-wrapper .se-wrapper-inner:focus{outline:none}.sun-editor .se-wrapper .se-wrapper-code{background-color:#191919;color:#fff;font-size:13px;word-break:break-all;padding:4px;margin:0;resize:none!important}.sun-editor .se-wrapper .se-wrapper-wysiwyg{background-color:#fff;display:block}.sun-editor .se-wrapper .se-wrapper-code-mirror{font-size:13px}.sun-editor .se-wrapper .se-placeholder{position:absolute;display:none;white-space:nowrap;text-overflow:ellipsis;z-index:1;color:#b1b1b1;font-size:13px;line-height:1.5;top:0;left:0;right:0;overflow:hidden;margin-top:0;padding-top:16px;padding-left:16px;margin-left:0;padding-right:16px;margin-right:0;pointer-events:none;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden}.sun-editor .se-resizing-bar{display:flex;width:auto;height:auto;min-height:16px;border-top:1px solid #dadada;padding:0 4px;background-color:#fafafa;cursor:ns-resize}.sun-editor .se-resizing-bar.se-resizing-none{cursor:default}.sun-editor .se-resizing-back{position:absolute;display:none;cursor:default;top:0;left:0;width:100%;height:100%;z-index:2147483647}.sun-editor .se-resizing-bar .se-navigation{flex:auto;position:relative;width:auto;height:auto;color:#666;margin:0;padding:0;font-size:10px;font-weight:700;line-height:1.5;background:transparent}.sun-editor .se-resizing-bar .se-char-counter-wrapper{flex:none;position:relative;display:block;width:auto;height:auto;margin:0;padding:0;color:#999;font-size:13px;background:transparent}.sun-editor .se-resizing-bar .se-char-counter-wrapper.se-blink{color:#b94a48;-webkit-animation:blinker .2s linear infinite;animation:blinker .2s linear infinite}.sun-editor .se-resizing-bar .se-char-counter-wrapper .se-char-label{margin-right:4px}.sun-editor .se-dialog{position:absolute;display:none;top:0;left:0;width:100%;height:100%;z-index:2147483647}.sun-editor .se-dialog button,.sun-editor .se-dialog input,.sun-editor .se-dialog label{font-size:14px;line-height:1.5;color:#111;margin:0}.sun-editor .se-dialog .se-dialog-back{background-color:#222;opacity:.5}.sun-editor .se-dialog .se-dialog-back,.sun-editor .se-dialog .se-dialog-inner{position:absolute;width:100%;height:100%;top:0;left:0}.sun-editor .se-dialog .se-dialog-inner .se-dialog-content{position:relative;width:auto;max-width:500px;margin:1.75rem auto;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:4px;outline:0;box-shadow:0 3px 9px rgba(0,0,0,.5)}@media screen and (max-width:509px){.sun-editor .se-dialog .se-dialog-inner .se-dialog-content{width:100%}}.sun-editor .se-dialog .se-dialog-inner .se-dialog-content label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}.sun-editor .se-dialog .se-dialog-inner .se-dialog-content .se-btn-primary{display:inline-block;padding:6px 12px;margin:0 0 10px!important;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;touch-action:manipulation;border-radius:4px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-header{height:50px;padding:6px 15px;border-bottom:1px solid #e5e5e5}.sun-editor .se-dialog .se-dialog-inner .se-dialog-header .se-dialog-close{float:right;font-weight:700;text-shadow:0 1px 0 #fff;-webkit-appearance:none;filter:alpha(opacity=100);opacity:1}.sun-editor .se-dialog .se-dialog-inner .se-dialog-header .se-modal-title{float:left;font-size:14px;font-weight:700;margin:0;padding:0;line-height:2.5}.sun-editor .se-dialog .se-dialog-inner .se-dialog-body{position:relative;padding:15px 15px 5px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form{margin-bottom:10px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form-footer{margin-top:10px;margin-bottom:0}.sun-editor .se-dialog .se-dialog-inner input:disabled{background-color:#f3f3f3}.sun-editor .se-dialog .se-dialog-inner .se-dialog-size-text{width:100%}.sun-editor .se-dialog .se-dialog-inner .se-dialog-size-text .size-h,.sun-editor .se-dialog .se-dialog-inner .se-dialog-size-text .size-w{width:70px;text-align:center}.sun-editor .se-dialog .se-dialog-inner .se-dialog-size-x{margin:0 8px;width:25px;text-align:center}.sun-editor .se-dialog .se-dialog-inner .se-dialog-footer{height:auto;min-height:55px;padding:10px 15px 0;text-align:right;border-top:1px solid #e5e5e5}.sun-editor .se-dialog .se-dialog-inner .se-dialog-footer>div{float:left}.sun-editor .se-dialog .se-dialog-inner .se-dialog-footer>div>label{margin:0 5px 0 0}.sun-editor .se-dialog .se-dialog-inner .se-dialog-btn-radio{margin-left:12px;margin-right:6px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-btn-check{margin-left:12px;margin-right:4px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form-footer .se-dialog-btn-check{margin-left:0;margin-right:4px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form-footer label:first-child{margin-right:16px;margin-left:0}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files{position:relative;display:flex;align-items:center}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files>input{flex:auto}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files .se-dialog-files-edge-button{flex:auto;opacity:.8;border:1px solid #ccc}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files .se-dialog-files-edge-button.se-file-remove>svg{width:8px;height:8px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files .se-dialog-files-edge-button:hover{background-color:#f0f0f0;outline:0 none}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-dialog-form-files .se-dialog-files-edge-button:active{background-color:#e9e9e9;box-shadow:inset 0 3px 5px #d6d6d6}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-select{display:inline-block;width:auto;height:34px;font-size:14px;text-align:center;line-height:1.42857143}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-control{display:inline-block;width:70px;height:34px;font-size:14px;text-align:center;line-height:1.42857143}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-form{display:block;width:100%;height:34px;font-size:14px;line-height:1.42857143;padding:0 4px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-form.se-input-url{direction:ltr}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-form.se-input-url:disabled{text-decoration:line-through;color:#999}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-video-ratio{width:70px;margin-left:4px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form a{color:#004cff}.sun-editor .se-dialog .se-dialog-inner .se-dialog-btn-revert{border:1px solid #ccc}.sun-editor .se-dialog .se-dialog-inner .se-dialog-btn-revert:hover{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-dialog .se-dialog-inner .se-dialog-btn-revert:active{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-dialog-tabs{width:100%;height:25px;border-bottom:1px solid #e5e5e5}.sun-editor .se-dialog-tabs button{background-color:#e5e5e5;border-right:1px solid #e5e5e5;float:left;outline:none;padding:2px 13px;transition:.3s}.sun-editor .se-dialog-tabs button:hover{background-color:#fff}.sun-editor .se-dialog-tabs button.active{background-color:#fff;border-bottom:0}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-form.se-math-exp{resize:vertical;height:4rem;border:1px solid #ccc;font-size:13px;padding:4px;direction:ltr}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-input-select.se-math-size{width:6em;height:28px;margin-left:1em}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-math-preview{font-size:13px}.sun-editor .se-dialog .se-dialog-inner .se-dialog-form .se-math-preview>span{display:inline-block;box-shadow:0 0 0 .1rem #c7deff}.sun-editor .se-dialog .se-dialog-inner .se-link-preview{display:block;height:auto;max-height:18px;font-size:13px;font-weight:400;font-family:inherit;color:#666;background-color:transparent;overflow:hidden;text-overflow:ellipsis;word-break:break-all;white-space:pre}.sun-editor .se-dialog .se-dialog-inner .se-anchor-preview-form{width:100%;display:flex;margin-top:4px}.sun-editor .se-dialog .se-dialog-inner .se-anchor-preview-form .se-svg.se-anchor-preview-icon{flex:unset;display:none;line-height:1.5;color:#4592ff}.sun-editor .se-dialog .se-dialog-inner .se-anchor-preview-form .se-link-preview{flex:auto;margin:0}.sun-editor .se-dialog .se-dialog-inner .se-anchor-rel{height:34px}.sun-editor .se-dialog .se-dialog-inner .se-anchor-rel-btn{width:46px;color:#3f9dff}.sun-editor .se-dialog .se-dialog-inner .se-anchor-rel-wrapper{display:flex;line-height:1.5;padding-top:6px}.sun-editor .se-dialog .se-dialog-inner .se-anchor-rel-preview{text-align:left}.sun-editor .se-controller .se-arrow.se-arrow-up{border-bottom-color:rgba(0,0,0,.25)}.sun-editor .se-controller{position:absolute;display:none;overflow:visible;z-index:6;border:1px solid rgba(0,0,0,.25);border-radius:4px;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.sun-editor .se-controller .se-btn-group{position:relative;display:flex;vertical-align:middle;padding:2px;top:0;left:0}.sun-editor .se-controller .se-btn-group .se-btn-group-sub{left:50%;min-width:auto;width:-webkit-max-content;width:-moz-max-content;width:max-content;display:none}.sun-editor .se-controller .se-btn-group .se-btn-group-sub button{margin:0;min-width:72px}.sun-editor .se-controller .se-btn-group button{position:relative;min-height:34px;height:auto;border:none;border-radius:4px;margin:1px;padding:5px 10px;font-size:12px;line-height:1.5;display:inline-block;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;touch-action:manipulation}.sun-editor .se-controller .se-btn-group button:focus:enabled,.sun-editor .se-controller .se-btn-group button:hover:enabled{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-controller .se-btn-group button:active:enabled{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-controller .se-btn-group button span{display:block;padding:0;margin:0}.sun-editor .se-controller .se-btn-group button:enabled.active{color:#4592ff;outline:0 none}.sun-editor .se-controller .se-btn-group button:enabled.active:focus,.sun-editor .se-controller .se-btn-group button:enabled.active:hover{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-controller .se-btn-group button:enabled.active:active{background-color:#d1d1d1;border-color:#c1c1c1;box-shadow:inset 0 3px 5px #c1c1c1}.sun-editor .se-controller .se-btn-group button:enabled.on{background-color:#e1e1e1;border-color:#d1d1d1;outline:0 none}.sun-editor .se-controller .se-btn-group button:enabled.on:focus,.sun-editor .se-controller .se-btn-group button:enabled.on:hover{background-color:#d1d1d1;border-color:#c1c1c1;outline:0 none}.sun-editor .se-controller .se-btn-group button:enabled.on:active{background-color:#c1c1c1;border-color:#b1b1b1;box-shadow:inset 0 3px 5px #b1b1b1}.sun-editor .se-controller .se-form-group input{min-width:120px}.sun-editor .se-controller-resizing{margin-top:-50px!important;padding:0;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143}.sun-editor .se-controller-resizing .se-btn-group .se-btn-group-sub.se-resizing-align-list{width:74px}.sun-editor .se-resizing-container{position:absolute;display:none;outline:1px solid #3f9dff;background-color:transparent}.sun-editor .se-resizing-container .se-modal-resize{position:absolute;display:inline-block;background-color:#3f9dff;opacity:.3}.sun-editor .se-resizing-container .se-resize-dot{position:absolute;top:0;left:0;width:100%;height:100%}.sun-editor .se-resizing-container .se-resize-dot>span{position:absolute;width:7px;height:7px;background-color:#3f9dff;border:1px solid #4592ff}.sun-editor .se-resizing-container .se-resize-dot>span.tl{top:-5px;left:-5px;cursor:nw-resize}.sun-editor .se-resizing-container .se-resize-dot>span.tr{top:-5px;right:-5px;cursor:ne-resize}.sun-editor .se-resizing-container .se-resize-dot>span.bl{bottom:-5px;left:-5px;cursor:sw-resize}.sun-editor .se-resizing-container .se-resize-dot>span.br{right:-5px;bottom:-5px;cursor:se-resize}.sun-editor .se-resizing-container .se-resize-dot>span.lw{left:-7px;bottom:50%;cursor:w-resize}.sun-editor .se-resizing-container .se-resize-dot>span.th{left:50%;top:-7px;cursor:n-resize}.sun-editor .se-resizing-container .se-resize-dot>span.rw{right:-7px;bottom:50%;cursor:e-resize}.sun-editor .se-resizing-container .se-resize-dot>span.bh{right:50%;bottom:-7px;cursor:s-resize}.sun-editor .se-resizing-container .se-resize-display{position:absolute;right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:#fff;background-color:#333;border-radius:4px}.sun-editor .se-controller-table,.sun-editor .se-controller-table-cell{width:auto}.sun-editor .se-controller-link,.sun-editor .se-controller-table,.sun-editor .se-controller-table-cell{padding:0;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143}.sun-editor .se-controller-link:after,.sun-editor .se-controller-link:before{box-sizing:border-box}.sun-editor .se-controller-link .link-content{padding:0;margin:0}.sun-editor .se-controller-link .link-content a{display:inline-block;color:#4592ff;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle;margin-left:5px}.sun-editor .se-file-browser{position:absolute;display:none;top:0;left:0;width:100%;height:100%;z-index:2147483647}.sun-editor .se-file-browser button,.sun-editor .se-file-browser input,.sun-editor .se-file-browser label{font-size:14px;line-height:1.5;color:#111;margin:0}.sun-editor .se-file-browser .se-file-browser-back{background-color:#222;opacity:.5}.sun-editor .se-file-browser .se-file-browser-back,.sun-editor .se-file-browser .se-file-browser-inner{position:absolute;display:block;width:100%;height:100%;top:0;left:0}.sun-editor .se-file-browser .se-file-browser-inner .se-file-browser-content{position:relative;width:960px;max-width:100%;margin:20px auto;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:4px;outline:0;box-shadow:0 3px 9px rgba(0,0,0,.5)}.sun-editor .se-file-browser .se-file-browser-header{height:auto;min-height:50px;padding:6px 15px;border-bottom:1px solid #e5e5e5}.sun-editor .se-file-browser .se-file-browser-header .se-file-browser-close{float:right;font-weight:700;text-shadow:0 1px 0 #fff;-webkit-appearance:none;filter:alpha(opacity=100);opacity:1}.sun-editor .se-file-browser .se-file-browser-header .se-file-browser-close>svg{width:12px;height:12px}.sun-editor .se-file-browser .se-file-browser-header .se-file-browser-title{font-size:16px;font-weight:700;margin:0;padding:0;line-height:2.2}.sun-editor .se-file-browser .se-file-browser-tags{display:block;width:100%;padding:0;text-align:left;margin:0 -15px}.sun-editor .se-file-browser .se-file-browser-tags a{display:inline-block;background-color:#f5f5f5;padding:6px 12px;margin:8px 0 8px 8px;color:#333;text-decoration:none;border-radius:32px;-moz-border-radius:32px;-webkit-border-radius:32px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box;cursor:pointer}.sun-editor .se-file-browser .se-file-browser-tags a:hover{background-color:#e1e1e1}.sun-editor .se-file-browser .se-file-browser-tags a:active{background-color:#d1d1d1}.sun-editor .se-file-browser .se-file-browser-tags a.on{background-color:#ebf3fe;color:#4592ff}.sun-editor .se-file-browser .se-file-browser-tags a.on:hover{background-color:#d8e8fe}.sun-editor .se-file-browser .se-file-browser-tags a.on:active{background-color:#c7deff}.sun-editor .se-file-browser .se-file-browser-body{position:relative;height:auto;min-height:350px;padding:20px;overflow-y:auto}.sun-editor .se-file-browser .se-file-browser-body .se-file-browser-list{position:relative;width:100%}@media screen and (max-width:992px){.sun-editor .se-file-browser .se-file-browser-inner .se-file-browser-content{width:748px}}@media screen and (max-width:768px){.sun-editor .se-file-browser .se-file-browser-inner .se-file-browser-content{width:600px}}.sun-editor .se-file-browser .se-file-browser-list .se-file-item-column{position:relative;display:block;height:auto;float:left}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-column{width:calc(25% - 20px);margin:0 10px}@media screen and (max-width:992px){.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-column{width:calc(33% - 20px)}}@media screen and (max-width:768px){.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-column{width:calc(50% - 20px)}}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-img{position:relative;display:block;cursor:pointer;width:100%;height:auto;border-radius:4px;outline:0;margin:10px 0}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-img:hover{opacity:.8;box-shadow:0 0 0 .2rem #3288ff}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-img>img{position:relative;display:block;width:100%;border-radius:4px;outline:0;height:auto}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-img>.se-file-img-name{position:absolute;z-index:1;font-size:13px;color:#fff;left:0;bottom:0;padding:5px 10px;background-color:transparent;width:100%;height:30px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.sun-editor .se-file-browser .se-file-browser-list.se-image-list .se-file-item-img>.se-file-img-name.se-file-name-back{background-color:#333;opacity:.6}.sun-editor .se-notice{position:absolute;top:0;display:none;z-index:7;width:100%;height:auto;word-break:break-all;font-size:13px;color:#b94a48;background-color:#f2dede;padding:15px;margin:0;border:1px solid #eed3d7;user-select:auto;-o-user-select:auto;-moz-user-select:auto;-khtml-user-select:auto;-webkit-user-select:auto;-ms-user-select:auto}.sun-editor .se-notice button{float:right;padding:7px}.sun-editor .se-tooltip{position:relative;overflow:visible}.sun-editor .se-tooltip .se-tooltip-inner{visibility:hidden;position:absolute;display:block;width:auto;top:120%;left:50%;background:transparent;opacity:0;z-index:1;line-height:1.5;transition:opacity .5s;margin:0;padding:0;bottom:auto;float:none;pointer-events:none;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden}.sun-editor .se-tooltip .se-tooltip-inner .se-tooltip-text{position:relative;display:inline-block;width:auto;left:-50%;font-size:.9em;margin:0;padding:4px 6px;border-radius:2px;background-color:#333;color:#fff;text-align:center;line-height:unset;white-space:nowrap;cursor:auto}.sun-editor .se-tooltip .se-tooltip-inner .se-tooltip-text:after{content:\"\";position:absolute;bottom:100%;left:50%;margin-left:-5px;border:5px solid transparent;border-bottom-color:#333}.sun-editor .se-tooltip:hover .se-tooltip-inner{visibility:visible;opacity:1}.sun-editor .se-tooltip .se-tooltip-inner .se-tooltip-text .se-shortcut{display:block!important}.sun-editor .se-tooltip .se-tooltip-inner .se-tooltip-text .se-shortcut>.se-shortcut-key{display:inline;font-weight:700}.sun-editor.se-rtl .se-btn-tray{direction:rtl}.sun-editor.se-rtl .se-btn-select .txt{flex:auto;text-align:right;direction:rtl}.sun-editor.se-rtl .se-btn-list{text-align:right}.sun-editor.se-rtl .se-btn-list>.se-list-icon{margin:-1px 0 0 10px}.sun-editor.se-rtl .se-menu-list,.sun-editor.se-rtl .se-menu-list li{float:right}.sun-editor.se-rtl .se-list-layer *{direction:rtl}.sun-editor.se-rtl .se-list-layer.se-list-format ul blockquote{padding:0 7px 0 0;border-right-width:5px;border-left-width:0}.sun-editor.se-rtl .se-list-layer .se-selector-color .se-color-pallet li{float:right}.sun-editor.se-rtl .se-list-inner .se-list-checked li button>.se-svg{float:right;padding:6px 0 0 6px}.sun-editor.se-rtl .se-tooltip .se-tooltip-inner .se-tooltip-text,.sun-editor.se-rtl .se-wrapper .se-placeholder{direction:rtl}.sun-editor.se-rtl .se-tooltip .se-tooltip-inner .se-tooltip-text .se-shortcut{direction:ltr}.sun-editor.se-rtl .se-dialog *{direction:rtl}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-header .se-dialog-close{float:left}.sun-editor.se-rtl .se-dialog-tabs button,.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-header .se-modal-title{float:right}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-size-text{padding-right:34px}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-footer .se-btn-primary{float:left}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-footer>div{float:right}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-footer>div>label{margin:0 0 0 5px}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-dialog-form-footer label:first-child{margin-left:16px;margin-right:0}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-anchor-rel-preview{margin-left:4px;text-align:right}.sun-editor.se-rtl .se-dialog .se-dialog-inner .se-anchor-rel-btn{float:right}.sun-editor.se-rtl .se-file-browser *{direction:rtl}.sun-editor.se-rtl .se-file-browser .se-file-browser-tags{text-align:right}.sun-editor.se-rtl .se-file-browser .se-file-browser-tags a{margin:8px 8px 0}.sun-editor.se-rtl .se-file-browser .se-file-browser-header .se-file-browser-close{float:left}.sun-editor.se-rtl .se-controller .se-btn-group,.sun-editor.se-rtl .se-resizing-container .se-resize-display{direction:rtl}@-webkit-keyframes blinker{50%{opacity:0}}@keyframes blinker{50%{opacity:0}}@-webkit-keyframes spinner{to{transform:rotate(361deg)}}@keyframes spinner{to{transform:rotate(361deg)}}.sun-editor-editable{font-family:Helvetica Neue,sans-serif;font-size:13px;color:#333;line-height:1.5;background-color:#fff;word-break:normal;word-wrap:break-word;padding:16px;margin:0}.sun-editor-editable *{box-sizing:border-box;font-family:inherit;font-size:inherit;color:inherit}.sun-editor-editable.se-rtl *{direction:rtl}.sun-editor-editable audio,.sun-editor-editable figcaption,.sun-editor-editable figure,.sun-editor-editable iframe,.sun-editor-editable img,.sun-editor-editable td,.sun-editor-editable th,.sun-editor-editable video{position:relative}.sun-editor-editable .__se__float-left{float:left}.sun-editor-editable .__se__float-right{float:right}.sun-editor-editable .__se__float-center{float:center}.sun-editor-editable .__se__float-none{float:none}.sun-editor-editable span{display:inline;vertical-align:baseline;margin:0;padding:0}.sun-editor-editable span.katex{display:inline-block;direction:ltr}.sun-editor-editable a{color:#004cff;text-decoration:none}.sun-editor-editable span[style~=\"color:\"] a{color:inherit}.sun-editor-editable a:focus,.sun-editor-editable a:hover{cursor:pointer;color:#0093ff;text-decoration:underline}.sun-editor-editable a.on{color:#0093ff;background-color:#e8f7ff}.sun-editor-editable pre{display:block;padding:8px;margin:0 0 10px;font-family:monospace;color:#666;line-height:1.45;background-color:#f9f9f9;border:1px solid #e1e1e1;border-radius:2px;white-space:pre-wrap;word-wrap:break-word;overflow:visible}.sun-editor-editable ol{list-style-type:decimal}.sun-editor-editable ol,.sun-editor-editable ul{list-style-position:inside;display:block;-webkit-margin-before:1em;margin-block-start:1em;-webkit-margin-after:1em;margin-block-end:1em;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0;-webkit-padding-start:40px;padding-inline-start:40px}.sun-editor-editable ul{list-style-type:disc}.sun-editor-editable li{display:list-item;text-align:-webkit-match-parent;margin-bottom:5px}.sun-editor-editable ol ol,.sun-editor-editable ol ul,.sun-editor-editable ul ol,.sun-editor-editable ul ul{margin:0}.sun-editor-editable ol ol,.sun-editor-editable ul ol{list-style-type:lower-alpha}.sun-editor-editable ol ol ol,.sun-editor-editable ul ol ol,.sun-editor-editable ul ul ol{list-style-type:upper-roman}.sun-editor-editable ol ul,.sun-editor-editable ul ul{list-style-type:circle}.sun-editor-editable ol ol ul,.sun-editor-editable ol ul ul,.sun-editor-editable ul ul ul{list-style-type:square}.sun-editor-editable sub,.sun-editor-editable sup{font-size:75%;line-height:0}.sun-editor-editable sub{vertical-align:sub}.sun-editor-editable sup{vertical-align:super}.sun-editor-editable p{display:block;margin:0 0 10px}.sun-editor-editable div{display:block;margin:0;padding:0}.sun-editor-editable blockquote{display:block;font-family:inherit;font-size:inherit;color:#999;-webkit-margin-before:1em;margin-block-start:1em;-webkit-margin-after:1em;margin-block-end:1em;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0;padding:0 5px 0 20px;border:solid #b1b1b1;border-width:0 0 0 5px}.sun-editor-editable blockquote blockquote{border-color:#c1c1c1}.sun-editor-editable blockquote blockquote blockquote{border-color:#d1d1d1}.sun-editor-editable blockquote blockquote blockquote blockquote{border-color:#e1e1e1}.sun-editor-editable.se-rtl blockquote{padding-left:5px;padding-right:20px;border-left-width:0;border-right-width:5px}.sun-editor-editable h1{font-size:2em;-webkit-margin-before:.67em;margin-block-start:.67em;-webkit-margin-after:.67em;margin-block-end:.67em}.sun-editor-editable h1,.sun-editor-editable h2{display:block;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0;font-weight:700}.sun-editor-editable h2{font-size:1.5em;-webkit-margin-before:.83em;margin-block-start:.83em;-webkit-margin-after:.83em;margin-block-end:.83em}.sun-editor-editable h3{font-size:1.17em;-webkit-margin-before:1em;margin-block-start:1em;-webkit-margin-after:1em;margin-block-end:1em}.sun-editor-editable h3,.sun-editor-editable h4{display:block;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0;font-weight:700}.sun-editor-editable h4{font-size:1em;-webkit-margin-before:1.33em;margin-block-start:1.33em;-webkit-margin-after:1.33em;margin-block-end:1.33em}.sun-editor-editable h5{font-size:.83em;-webkit-margin-before:1.67em;margin-block-start:1.67em;-webkit-margin-after:1.67em;margin-block-end:1.67em}.sun-editor-editable h5,.sun-editor-editable h6{display:block;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0;font-weight:700}.sun-editor-editable h6{font-size:.67em;-webkit-margin-before:2.33em;margin-block-start:2.33em;-webkit-margin-after:2.33em;margin-block-end:2.33em}.sun-editor-editable hr{display:flex;border-width:1px 0 0;border-color:#000;-o-border-image:initial;border-image:initial;height:1px}.sun-editor-editable hr.__se__solid{border-style:solid none none}.sun-editor-editable hr.__se__dotted{border-style:dotted none none}.sun-editor-editable hr.__se__dashed{border-style:dashed none none}.sun-editor-editable table{display:table;table-layout:auto;border:1px solid #ccc;width:100%;max-width:100%;margin:0 0 10px;background-color:transparent;border-spacing:0;border-collapse:collapse}.sun-editor-editable.se-rtl table{margin:0 0 10px auto}.sun-editor-editable table thead{border-bottom:2px solid #333}.sun-editor-editable table tr{border:1px solid #efefef}.sun-editor-editable table th{background-color:#f3f3f3}.sun-editor-editable table td,.sun-editor-editable table th{border:1px solid #e1e1e1;padding:.4em;background-clip:padding-box}.sun-editor-editable table.se-table-size-auto{width:auto!important}.sun-editor-editable table.se-table-size-100{width:100%!important}.sun-editor-editable table.se-table-layout-auto{table-layout:auto!important}.sun-editor-editable table.se-table-layout-fixed{table-layout:fixed!important}.sun-editor-editable table td.se-table-selected-cell,.sun-editor-editable table th.se-table-selected-cell{border:1px double #4592ff;background-color:#f1f7ff}.sun-editor-editable.se-disabled *{user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none}.sun-editor-editable .se-component{display:flex;padding:1px;margin:0 0 10px}.sun-editor-editable[contenteditable=true] .se-component{outline:1px dashed #e1e1e1;min-width:16px;min-height:16px}.sun-editor-editable[contenteditable=true] .se-component.se-component-copy{box-shadow:0 0 0 .2rem #3f9dff;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.sun-editor-editable audio,.sun-editor-editable iframe,.sun-editor-editable img,.sun-editor-editable video{display:block;margin:0;padding:0;width:auto;height:auto;max-width:100%}.sun-editor-editable[contenteditable=true] figure:after{position:absolute;content:\"\";z-index:1;top:0;left:0;right:0;bottom:0;cursor:default;display:block;background:transparent}.sun-editor-editable[contenteditable=true] figure a,.sun-editor-editable[contenteditable=true] figure iframe,.sun-editor-editable[contenteditable=true] figure img,.sun-editor-editable[contenteditable=true] figure video{z-index:0}.sun-editor-editable[contenteditable=true] figure figcaption{display:block;z-index:2}.sun-editor-editable[contenteditable=true] figure figcaption:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #c7deff}.sun-editor-editable .se-image-container,.sun-editor-editable .se-video-container{width:auto;height:auto;max-width:100%}.sun-editor-editable figure{display:block;outline:none;margin:0;padding:0}.sun-editor-editable figure figcaption{padding:1em .5em;margin:0;background-color:#f9f9f9;outline:none}.sun-editor-editable figure figcaption p{line-height:2;margin:0}.sun-editor-editable .se-image-container a img{padding:1px;margin:1px;outline:1px solid #4592ff}.sun-editor-editable .se-video-container iframe,.sun-editor-editable .se-video-container video{outline:1px solid #9e9e9e;position:absolute;top:0;left:0;border:0;width:100%;height:100%}.sun-editor-editable .se-video-container figure{left:0;width:100%;max-width:100%}.sun-editor-editable audio{width:300px;height:54px}.sun-editor-editable audio.active{outline:2px solid #80bdff}.sun-editor-editable.se-show-block div,.sun-editor-editable.se-show-block h1,.sun-editor-editable.se-show-block h2,.sun-editor-editable.se-show-block h3,.sun-editor-editable.se-show-block h4,.sun-editor-editable.se-show-block h5,.sun-editor-editable.se-show-block h6,.sun-editor-editable.se-show-block li,.sun-editor-editable.se-show-block ol,.sun-editor-editable.se-show-block p,.sun-editor-editable.se-show-block pre,.sun-editor-editable.se-show-block ul{border:1px dashed #3f9dff!important;padding:14px 8px 8px!important}.sun-editor-editable.se-show-block ol,.sun-editor-editable.se-show-block ul{border:1px dashed #d539ff!important}.sun-editor-editable.se-show-block pre{border:1px dashed #27c022!important}.se-show-block p{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAPAQMAAAAF7dc0AAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAaSURBVAjXY/j/gwGCPvxg+F4BQiAGDP1HQQByxxw0gqOzIwAAAABJRU5ErkJggg==\") no-repeat}.se-show-block div{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAPAQMAAAAxlBYoAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAmSURBVAjXY/j//wcDDH+8XsHwDYi/hwNx1A8w/nYLKH4XoQYJAwCXnSgcl2MOPgAAAABJRU5ErkJggg==\") no-repeat}.se-show-block h1{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAPAQMAAAA4f7ZSAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAfSURBVAjXY/j/v4EBhr+9B+LzEPrDeygfhI8j1CBhAEhmJGY4Rf6uAAAAAElFTkSuQmCC\") no-repeat}.se-show-block h2{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAPAQMAAAA4f7ZSAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAmSURBVAjXY/j/v4EBhr+dB+LtQPy9geEDEH97D8T3gbgdoQYJAwA51iPuD2haEAAAAABJRU5ErkJggg==\") no-repeat}.se-show-block h3{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAPAQMAAAA4f7ZSAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAiSURBVAjXY/j/v4EBhr+dB+LtQPy9geHDeQgN5p9HqEHCADeWI+69VG2MAAAAAElFTkSuQmCC\") no-repeat}.se-show-block h4{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAPAQMAAADTSA1RAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAiSURBVAjXY/j//wADDH97DsTXIfjDdiDdDMTfIRhZHRQDAKJOJ6L+K3y7AAAAAElFTkSuQmCC\") no-repeat}.se-show-block h5{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAPAQMAAAA4f7ZSAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAlSURBVAjXY/j/v4EBhr+1A/F+IO5vYPiwHUh/B2IQfR6hBgkDABlWIy5uM+9GAAAAAElFTkSuQmCC\") no-repeat}.se-show-block h6{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAPAQMAAAA4f7ZSAAAABlBMVEWAgID////n1o2sAAAAAnRSTlP/AOW3MEoAAAAiSURBVAjXY/j/v4EBhr+dB+LtQLy/geFDP5S9HSKOrA6KAR9GIza1ptJnAAAAAElFTkSuQmCC\") no-repeat}.se-show-block li{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA7SURBVDhPYxgFcNDQ0PAfykQBIHEYhgoRB/BpwCfHBKWpBkaggYxQGgOgBzyQD1aLLA4TGwWDGjAwAACR3RcEU9Ui+wAAAABJRU5ErkJggg==\") no-repeat}.se-show-block ol{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABHSURBVDhPYxgFcNDQ0PAfhKFcFIBLHCdA1oBNM0kGEmMAPgOZoDTVANUNxAqQvURMECADRiiNAWCagDSGGhyW4DRrMAEGBgAu0SX6WpGgjAAAAABJRU5ErkJggg==\") no-repeat}.se-show-block ul{background:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAA1SURBVDhPYxgFDA0NDf+hTBSALI5LDQgwQWmqgVEDKQcsUBoF4ItFGEBXA+QzQpmDGjAwAAA8DQ4Lni6gdAAAAABJRU5ErkJggg==\") no-repeat}.sun-editor-editable .__se__p-bordered,.sun-editor .__se__p-bordered{border-top:1px solid #b1b1b1;border-bottom:1px solid #b1b1b1;padding:4px 0}.sun-editor-editable .__se__p-spaced,.sun-editor .__se__p-spaced{letter-spacing:1px}.sun-editor-editable .__se__p-neon,.sun-editor .__se__p-neon{font-weight:200;font-style:italic;background:#000;color:#fff;padding:6px 4px;border:2px solid #fff;border-radius:6px;text-transform:uppercase;-webkit-animation:neonFlicker 1.5s infinite alternate;animation:neonFlicker 1.5s infinite alternate}@-webkit-keyframes neonFlicker{0%,19%,21%,23%,25%,54%,56%,to{text-shadow:-.2rem -.2rem 1rem #fff,.2rem .2rem 1rem #fff,0 0 2px #f40,0 0 4px #f40,0 0 6px #f40,0 0 8px #f40,0 0 10px #f40;box-shadow:0 0 .5px #fff,inset 0 0 .5px #fff,0 0 2px #08f,inset 0 0 2px #08f,0 0 4px #08f,inset 0 0 4px #08f}20%,24%,55%{text-shadow:none;box-shadow:none}}@keyframes neonFlicker{0%,19%,21%,23%,25%,54%,56%,to{text-shadow:-.2rem -.2rem 1rem #fff,.2rem .2rem 1rem #fff,0 0 2px #f40,0 0 4px #f40,0 0 6px #f40,0 0 8px #f40,0 0 10px #f40;box-shadow:0 0 .5px #fff,inset 0 0 .5px #fff,0 0 2px #08f,inset 0 0 2px #08f,0 0 4px #08f,inset 0 0 4px #08f}20%,24%,55%{text-shadow:none;box-shadow:none}}.sun-editor-editable .__se__t-shadow,.sun-editor .__se__t-shadow{text-shadow:-.2rem -.2rem 1rem #fff,.2rem .2rem 1rem #fff,0 0 .2rem #999,0 0 .4rem #888,0 0 .6rem #777,0 0 .8rem #666,0 0 1rem #555}.sun-editor-editable .__se__t-code,.sun-editor .__se__t-code{font-family:monospace;color:#666;background-color:rgba(27,31,35,.05);border-radius:6px;padding:.2em .4em}", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/lib/css-base.js": +/*!*************************************************!*\ + !*** ./node_modules/css-loader/lib/css-base.js ***! + \*************************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +// css base code, injected by the css-loader +module.exports = function(useSourceMap) { + var list = []; + + // return the list of modules as css string + list.toString = function toString() { + return this.map(function (item) { + var content = cssWithMappingToString(item, useSourceMap); + if(item[2]) { + return "@media " + item[2] + "{" + content + "}"; + } else { + return content; + } + }).join(""); + }; + + // import a list of modules into the list + list.i = function(modules, mediaQuery) { + if(typeof modules === "string") + modules = [[null, modules, ""]]; + var alreadyImportedModules = {}; + for(var i = 0; i < this.length; i++) { + var id = this[i][0]; + if(typeof id === "number") + alreadyImportedModules[id] = true; + } + for(i = 0; i < modules.length; i++) { + var item = modules[i]; + // skip already imported module + // this implementation is not 100% perfect for weird media query combinations + // when a module is imported multiple times with different media queries. + // I hope this will never occur (Hey this way we have smaller bundles) + if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { + if(mediaQuery && !item[2]) { + item[2] = mediaQuery; + } else if(mediaQuery) { + item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; + } + list.push(item); + } + } + }; + return list; +}; + +function cssWithMappingToString(item, useSourceMap) { + var content = item[1] || ''; + var cssMapping = item[3]; + if (!cssMapping) { + return content; + } + + if (useSourceMap && typeof btoa === 'function') { + var sourceMapping = toComment(cssMapping); + var sourceURLs = cssMapping.sources.map(function (source) { + return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */' + }); + + return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); + } + + return [content].join('\n'); +} + +// Adapted from convert-source-map (MIT) +function toComment(sourceMap) { + // eslint-disable-next-line no-undef + var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + + return '/*# ' + data + ' */'; +} + + /***/ }), /***/ "./node_modules/jquery/dist/jquery.js": @@ -37868,6 +37974,21379 @@ process.chdir = function (dir) { process.umask = function() { return 0; }; +/***/ }), + +/***/ "./node_modules/style-loader/lib/addStyles.js": +/*!****************************************************!*\ + !*** ./node_modules/style-loader/lib/addStyles.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ + +var stylesInDom = {}; + +var memoize = function (fn) { + var memo; + + return function () { + if (typeof memo === "undefined") memo = fn.apply(this, arguments); + return memo; + }; +}; + +var isOldIE = memoize(function () { + // Test for IE <= 9 as proposed by Browserhacks + // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805 + // Tests for existence of standard globals is to allow style-loader + // to operate correctly into non-standard environments + // @see https://github.com/webpack-contrib/style-loader/issues/177 + return window && document && document.all && !window.atob; +}); + +var getTarget = function (target, parent) { + if (parent){ + return parent.querySelector(target); + } + return document.querySelector(target); +}; + +var getElement = (function (fn) { + var memo = {}; + + return function(target, parent) { + // If passing function in options, then use it for resolve "head" element. + // Useful for Shadow Root style i.e + // { + // insertInto: function () { return document.querySelector("#foo").shadowRoot } + // } + if (typeof target === 'function') { + return target(); + } + if (typeof memo[target] === "undefined") { + var styleTarget = getTarget.call(this, target, parent); + // Special case to return head of iframe instead of iframe itself + if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { + try { + // This will throw an exception if access to iframe is blocked + // due to cross-origin restrictions + styleTarget = styleTarget.contentDocument.head; + } catch(e) { + styleTarget = null; + } + } + memo[target] = styleTarget; + } + return memo[target] + }; +})(); + +var singleton = null; +var singletonCounter = 0; +var stylesInsertedAtTop = []; + +var fixUrls = __webpack_require__(/*! ./urls */ "./node_modules/style-loader/lib/urls.js"); + +module.exports = function(list, options) { + if (typeof DEBUG !== "undefined" && DEBUG) { + if (typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); + } + + options = options || {}; + + options.attrs = typeof options.attrs === "object" ? options.attrs : {}; + + // Force single-tag solution on IE6-9, which has a hard limit on the # of ' + + '' + + '' + contentsHTML + '' + + '' + ); + } else { + const links = _d.head.getElementsByTagName('link'); + const styles = _d.head.getElementsByTagName('style'); + let linkHTML = ''; + for (let i = 0, len = links.length; i < len; i++) { + linkHTML += links[i].outerHTML; + } + for (let i = 0, len = styles.length; i < len; i++) { + linkHTML += styles[i].outerHTML; + } + + windowObject.document.write('' + + '' + + '' + + '' + + '' + + '' + lang.toolbar.preview + '' + + linkHTML + + '' + + '' + contentsHTML + '' + + '' + ); + } + }, + + /** + * @description Sets the HTML string + * @param {String|undefined} html HTML string + */ + setContents: function (html) { + this.removeRange(); + + const convertValue = (html === null || html === undefined) ? '' : this.convertContentsForEditor(html); + this._resetComponents(); + + if (!this._variable.isCodeView) { + context.element.wysiwyg.innerHTML = convertValue; + // history stack + this.history.push(false); + } else { + const value = this.convertHTMLForCodeView(convertValue); + this._setCodeView(value); + } + }, + + /** + * @description Sets the contents of the iframe's head tag and body tag when using the "iframe" or "fullPage" option. + * @param {Object} ctx { head: HTML string, body: HTML string} + */ + setIframeContents: function (ctx) { + if (!options.iframe) return false; + if (ctx.head) this._wd.head.innerHTML = ctx.head.replace(/[\s\S]*<\/script>/gi, ''); + if (ctx.body) this._wd.body.innerHTML = this.convertContentsForEditor(ctx.body); + }, + + /** + * @description Gets the current contents + * @param {Boolean} onlyContents Return only the contents of the body without headers when the "fullPage" option is true + * @returns {Object} + */ + getContents: function (onlyContents) { + const contents = context.element.wysiwyg.innerHTML; + const renderHTML = util.createElement('DIV'); + renderHTML.innerHTML = contents; + + const figcaptions = util.getListChildren(renderHTML, function (current) { + return /FIGCAPTION/i.test(current.nodeName); + }); + + for (let i = 0, len = figcaptions.length; i < len; i++) { + figcaptions[i].removeAttribute('contenteditable'); + } + + if (options.fullPage && !onlyContents) { + const attrs = util.getAttributesToString(this._wd.body, ['contenteditable']); + return '' + this._wd.head.outerHTML + '' + renderHTML.innerHTML + ''; + } else { + return renderHTML.innerHTML; + } + }, + + /** + * @description Returns HTML string according to tag type and configuration. + * Use only "cleanHTML" + * @param {Node} node Node + * @param {Boolean} requireFormat If true, text nodes that do not have a format node is wrapped with the format tag. + * @private + */ + _makeLine: function (node, requireFormat) { + const defaultTag = options.defaultTag; + // element + if (node.nodeType === 1) { + if (util._disallowedTags(node)) return ''; + if (!requireFormat || (util.isFormatElement(node) || util.isRangeFormatElement(node) || util.isComponent(node) || util.isMedia(node) || (util.isAnchor(node) && util.isMedia(node.firstElementChild)))) { + return node.outerHTML; + } else { + return '<' + defaultTag + '>' + node.outerHTML + ''; + } + } + // text + if (node.nodeType === 3) { + if (!requireFormat) return node.textContent; + const textArray = node.textContent.split(/\n/g); + let html = ''; + for (let i = 0, tLen = textArray.length, text; i < tLen; i++) { + text = textArray[i].trim(); + if (text.length > 0) html += '<' + defaultTag + '>' + text + ''; + } + return html; + } + // comments + if (node.nodeType === 8 && this._allowHTMLComments) { + return ''; + } + + return ''; + }, + + /** + * @description Removes attribute values such as style and converts tags that do not conform to the "html5" standard. + * @param {String} text + * @returns {String} HTML string + * @private + */ + _tagConvertor: function (text) { + if (!this._disallowedTextTagsRegExp) return text; + + const ec = options._textTagsMap; + return text.replace(this._disallowedTextTagsRegExp, function (m, t, n) { + return t + (typeof ec[n] === 'string' ? ec[n] : n); + }); + }, + + /** + * @description Delete disallowed tags + * @param {String} html HTML string + * @returns {String} + * @private + */ + _deleteDisallowedTags: function (html) { + return html + .replace(/\n/g, '') + .replace(/<(script|style)[\s\S]*>[\s\S]*<\/(script|style)>/gi, '') + .replace(/<[a-z0-9]+\:[a-z0-9]+[^>^\/]*>[^>]*<\/[a-z0-9]+\:[a-z0-9]+>/gi, '') + .replace(this.editorTagsWhitelistRegExp, ''); + }, + + /** + * @description Tag and tag attribute check RegExp function. (used by "cleanHTML" and "convertContentsForEditor") + * @param {Boolean} rowLevelCheck Row level check + * @param {String} m RegExp value + * @param {String} t RegExp value + * @returns {String} + * @private + */ + _cleanTags: function (rowLevelCheck, m, t) { + if (/^<[a-z0-9]+\:[a-z0-9]+/i.test(m)) return m; + + let v = null; + const tAttr = this._attributesTagsWhitelist[t.match(/(?!<)[a-zA-Z0-9]+/)[0].toLowerCase()]; + if (tAttr) v = m.match(tAttr); + else v = m.match(this._attributesWhitelistRegExp); + + if ((rowLevelCheck || /]*(?=>)/g, this._cleanTags.bind(this, false)); + + const dom = _d.createRange().createContextualFragment(html); + try { + util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, options.allowStyles); + } catch (error) { + console.warn('[SUNEDITOR.cleanHTML.consistencyCheck.fail] ' + error); + } + + if (this.managedTagsInfo && this.managedTagsInfo.query) { + const textCompList = dom.querySelectorAll(this.managedTagsInfo.query); + for (let i = 0, len = textCompList.length, initMethod, classList; i < len; i++) { + classList = [].slice.call(textCompList[i].classList); + for (let c = 0, cLen = classList.length; c < cLen; c++) { + initMethod = this.managedTagsInfo.map[classList[c]]; + if (initMethod) { + initMethod(textCompList[i]); + break; + } + } + } + } + + const domTree = dom.childNodes; + let cleanHTML = ''; + let requireFormat = false; + + for (let i = 0, len = domTree.length, t; i < len; i++) { + t = domTree[i]; + if (t.nodeType === 1 && !util.isTextStyleElement(t) && !util.isBreak(t) && !util._disallowedTags(t)) { + requireFormat = true; + break; + } + } + + for (let i = 0, len = domTree.length; i < len; i++) { + cleanHTML += this._makeLine(domTree[i], requireFormat); + } + + cleanHTML = util.htmlRemoveWhiteSpace(cleanHTML); + return this._tagConvertor(!cleanHTML ? html : !whitelist ? cleanHTML : cleanHTML.replace(typeof whitelist === 'string' ? util.createTagsWhitelist(whitelist) : whitelist, '')); + }, + + /** + * @description Converts contents into a format that can be placed in an editor + * @param {String} contents contents + * @returns {String} + */ + convertContentsForEditor: function (contents) { + contents = this._deleteDisallowedTags(contents).replace(/(<[a-zA-Z0-9]+)[^>]*(?=>)/g, this._cleanTags.bind(this, true)); + + const dom = _d.createRange().createContextualFragment(this._deleteDisallowedTags(contents)); + + try { + util._consistencyCheckOfHTML(dom, this._htmlCheckWhitelistRegExp, options.allowStyles); + } catch (error) { + console.warn('[SUNEDITOR.convertContentsForEditor.consistencyCheck.fail] ' + error); + } + + if (this.managedTagsInfo && this.managedTagsInfo.query) { + const textCompList = dom.querySelectorAll(this.managedTagsInfo.query); + for (let i = 0, len = textCompList.length, initMethod, classList; i < len; i++) { + classList = [].slice.call(textCompList[i].classList); + for (let c = 0, cLen = classList.length; c < cLen; c++) { + initMethod = this.managedTagsInfo.map[classList[c]]; + if (initMethod) { + initMethod(textCompList[i]); + break; + } + } + } + } + + const domTree = dom.childNodes; + let cleanHTML = ''; + for (let i = 0, len = domTree.length; i < len; i++) { + cleanHTML += this._makeLine(domTree[i], true); + } + + if (cleanHTML.length === 0) return '<' + options.defaultTag + '>
'; + + cleanHTML = util.htmlRemoveWhiteSpace(cleanHTML); + return this._tagConvertor(cleanHTML); + }, + + /** + * @description Converts wysiwyg area element into a format that can be placed in an editor of code view mode + * @param {Element|String} html WYSIWYG element (context.element.wysiwyg) or HTML string. + * @returns {String} + */ + convertHTMLForCodeView: function (html) { + let returnHTML = ''; + const wRegExp = _w.RegExp; + const brReg = new wRegExp('^(BLOCKQUOTE|PRE|TABLE|THEAD|TBODY|TR|TH|TD|OL|UL|IMG|IFRAME|VIDEO|AUDIO|FIGURE|FIGCAPTION|HR|BR|CANVAS|SELECT)$', 'i'); + const isFormatElement = util.isFormatElement.bind(util); + const wDoc = typeof html === 'string' ? _d.createRange().createContextualFragment(html) : html; + + let indentSize = this._variable.codeIndent * 1; + indentSize = indentSize > 0 ? new _w.Array(indentSize + 1).join(' ') : ''; + + (function recursionFunc (element, indent, lineBR) { + const children = element.childNodes; + const elementRegTest = brReg.test(element.nodeName); + const elementIndent = (elementRegTest ? indent : ''); + + for (let i = 0, len = children.length, node, br, nodeRegTest; i < len; i++) { + node = children[i]; + nodeRegTest = brReg.test(node.nodeName); + br = nodeRegTest ? '\n' : ''; + lineBR = isFormatElement(node) && !elementRegTest && !/^(TH|TD)$/i.test(element.nodeName) ? '\n' : ''; + + if (node.nodeType === 8) { + returnHTML += '\n' + br; + continue; + } + if (node.nodeType === 3) { + returnHTML += util._HTMLConvertor((/^\n+$/.test(node.data) ? '' : node.data)); + continue; + } + if (node.childNodes.length === 0) { + returnHTML += (/^HR$/i.test(node.nodeName) ? '\n' : '') + elementIndent + node.outerHTML + br; + continue; + } + + node.innerHTML = node.innerHTML; + const tag = node.nodeName.toLowerCase(); + returnHTML += (lineBR || (elementRegTest ? '' : br)) + (elementIndent || nodeRegTest ? indent : '') + node.outerHTML.match(wRegExp('<' + tag + '[^>]*>', 'i'))[0] + br; + recursionFunc(node, indent + indentSize, ''); + returnHTML += (nodeRegTest ? indent : '') + '' + (lineBR || br || elementRegTest ? '\n' : false || /^(TH|TD)$/i.test(node.nodeName) ? '\n' : ''); + } + }(wDoc, '', '\n')); + + return returnHTML.trim() + '\n'; + }, + + /** + * @description Add an event to document. + * When created as an Iframe, the same event is added to the document in the Iframe. + * @param {String} type Event type + * @param {Function} listener Event listener + * @param {Boolean} useCapture Use event capture + */ + addDocEvent: function (type, listener, useCapture) { + _d.addEventListener(type, listener, useCapture); + if (options.iframe) { + this._wd.addEventListener(type, listener); + } + }, + + /** + * @description Remove events from document. +  * When created as an Iframe, the event of the document inside the Iframe is also removed. + * @param {String} type Event type + * @param {Function} listener Event listener + */ + removeDocEvent: function (type, listener) { + _d.removeEventListener(type, listener); + if (options.iframe) { + this._wd.removeEventListener(type, listener); + } + }, + + /** + * @description The current number of characters is counted and displayed. + * @param {String} inputText Text added. + * @returns {Boolean} + * @private + */ + _charCount: function (inputText) { + const maxCharCount = options.maxCharCount; + const countType = options.charCounterType; + let nextCharCount = 0; + if (!!inputText) nextCharCount = this.getCharLength(inputText, countType); + + this._setCharCount(); + + if (maxCharCount > 0) { + let over = false; + const count = functions.getCharCount(countType); + + if (count > maxCharCount) { + over = true; + if (nextCharCount > 0) { + this._editorRange(); + const range = this.getRange(); + const endOff = range.endOffset - 1; + const text = this.getSelectionNode().textContent; + const slicePosition = range.endOffset - (count - maxCharCount); + + this.getSelectionNode().textContent = text.slice(0, slicePosition < 0 ? 0 : slicePosition) + text.slice(range.endOffset, text.length); + this.setRange(range.endContainer, endOff, range.endContainer, endOff); + } + } else if ((count + nextCharCount) > maxCharCount) { + over = true; + } + + if (over) { + this._callCounterBlink(); + if (nextCharCount > 0) return false; + } + } + + return true; + }, + + /** + * @description When "element" is added, if it is greater than "options.maxCharCount", false is returned. + * @param {Node|String} element Element node or String. + * @param {String|null} charCounterType charCounterType. If it is null, the options.charCounterType + * @returns {Boolean} + */ + checkCharCount: function (element, charCounterType) { + if (options.maxCharCount) { + const countType = charCounterType || options.charCounterType; + const length = this.getCharLength((typeof element === 'string' ? element : this._charTypeHTML ? element.outerHTML : element.textContent), countType); + if (length > 0 && length + functions.getCharCount(countType) > options.maxCharCount) { + this._callCounterBlink(); + return false; + } + } + return true; + }, + + /** + * @description Get the length of the content. + * Depending on the option, the length of the character is taken. (charCounterType) + * @param {String} content Content to count + * @param {String} charCounterType options.charCounterType + * @returns {Number} + */ + getCharLength: function (content, charCounterType) { + return /byte/.test(charCounterType) ? util.getByteLength(content) : content.length; + }, + + /** + * @description Set the char count to charCounter element textContent. + * @private + */ + _setCharCount: function () { + if (context.element.charCounter) { + _w.setTimeout(function () { context.element.charCounter.textContent = functions.getCharCount(options.charCounterType); }); + } + }, + + /** + * @description The character counter blinks. + * @private + */ + _callCounterBlink: function () { + const charWrapper = context.element.charWrapper; + if (charWrapper && !util.hasClass(charWrapper, 'se-blink')) { + util.addClass(charWrapper, 'se-blink'); + _w.setTimeout(function () { + util.removeClass(charWrapper, 'se-blink'); + }, 600); + } + }, + + /** + * @description Check the components such as image and video and modify them according to the format. + * @private + */ + _checkComponents: function () { + for (let i = 0, len = this._fileInfoPluginsCheck.length; i < len; i++) { + this._fileInfoPluginsCheck[i](); + } + }, + + /** + * @description Initialize the information of the components. + * @private + */ + _resetComponents: function () { + for (let i = 0, len = this._fileInfoPluginsReset.length; i < len; i++) { + this._fileInfoPluginsReset[i](); + } + }, + + /** + * @description Set method in the code view area + * @param {String} value HTML string + * @private + */ + _setCodeView: function (value) { + if (options.codeMirrorEditor) { + options.codeMirrorEditor.getDoc().setValue(value); + } else { + context.element.code.value = value; + } + }, + + /** + * @description Get method in the code view area + * @private + */ + _getCodeView: function () { + return options.codeMirrorEditor ? options.codeMirrorEditor.getDoc().getValue() : context.element.code.value; + }, + + /** + * @description Initializ core variable + * @param {Boolean} reload Is relooad? + * @param {String} _initHTML initial html string + * @private + */ + _init: function (reload, _initHTML) { + const wRegExp = _w.RegExp; + this._ww = options.iframe ? context.element.wysiwygFrame.contentWindow : _w; + this._wd = _d; + this._charTypeHTML = options.charCounterType === 'byte-html'; + + if (!options.iframe && typeof _w.ShadowRoot === 'function') { + let child = context.element.wysiwygFrame; + while (child) { + if (child.shadowRoot) { + this._shadowRoot = child.shadowRoot; + break; + } else if (child instanceof _w.ShadowRoot) { + this._shadowRoot = child; + break; + } + child = child.parentNode; + } + if (this._shadowRoot) this._shadowRootControllerEventTarget = []; + } + + // set disallow text nodes + const disallowTextTags = _w.Object.keys(options._textTagsMap); + const allowTextTags = !options.addTagsWhitelist ? [] : options.addTagsWhitelist.split('|').filter(function (v) { return /b|i|ins|s|strike/i.test(v); }); + for (let i = 0; i < allowTextTags.length; i++) { + disallowTextTags.splice(disallowTextTags.indexOf(allowTextTags[i].toLowerCase()), 1); + } + this._disallowedTextTagsRegExp = disallowTextTags.length === 0 ? null : new wRegExp('(<\\/?)(' + disallowTextTags.join('|') + ')\\b\\s*(?:[^>^<]+)?\\s*(?=>)', 'gi'); + + // set whitelist + const defaultAttr = 'contenteditable|colspan|rowspan|target|href|download|rel|src|alt|class|type|controls|data-format|data-size|data-file-size|data-file-name|data-origin|data-align|data-image-link|data-rotate|data-proportion|data-percentage|origin-size|data-exp|data-font-size'; + this._allowHTMLComments = options._editorTagsWhitelist.indexOf('//') > -1; + this._htmlCheckWhitelistRegExp = new wRegExp('^(' + options._editorTagsWhitelist.replace('|//', '') + ')$', 'i'); + this.editorTagsWhitelistRegExp = util.createTagsWhitelist(options._editorTagsWhitelist.replace('|//', '|')); + this.pasteTagsWhitelistRegExp = util.createTagsWhitelist(options.pasteTagsWhitelist); + + const _attr = options.attributesWhitelist; + const tagsAttr = {}; + let allAttr = ''; + if (!!_attr) { + for (let k in _attr) { + if (!util.hasOwn(_attr, k)) continue; + if (k === 'all') { + allAttr = _attr[k] + '|'; + } else { + tagsAttr[k] = new wRegExp('((?:' + _attr[k] + '|' + defaultAttr + ')\s*=\s*"[^"]*")', 'ig'); + } + } + } + + this._attributesWhitelistRegExp = new wRegExp('((?:' + allAttr + defaultAttr + ')\s*=\s*"[^"]*")', 'ig'); + this._attributesTagsWhitelist = tagsAttr; + + // set modes + this._isInline = /inline/i.test(options.mode); + this._isBalloon = /balloon|balloon-always/i.test(options.mode); + this._isBalloonAlways = /balloon-always/i.test(options.mode); + + // caching buttons + this._cachingButtons(); + + // file components + this._fileInfoPluginsCheck = []; + this._fileInfoPluginsReset = []; + + // text components + this.managedTagsInfo = { query: '', map: {} }; + const managedClass = []; + + // Command and file plugins registration + this.activePlugins = []; + this._fileManager.tags = []; + this._fileManager.pluginMap = {}; + + let filePluginRegExp = []; + let plugin, button; + for (let key in plugins) { + if (!util.hasOwn(plugins, key)) continue; + plugin = plugins[key]; + button = pluginCallButtons[key]; + if (plugin.active && button) { + this.callPlugin(key, null, button); + } + if (typeof plugin.checkFileInfo === 'function' && typeof plugin.resetFileInfo === 'function') { + this.callPlugin(key, null, button); + this._fileInfoPluginsCheck.push(plugin.checkFileInfo.bind(this)); + this._fileInfoPluginsReset.push(plugin.resetFileInfo.bind(this)); + } + if (_w.Array.isArray(plugin.fileTags)) { + const fileTags = plugin.fileTags; + this.callPlugin(key, null, button); + this._fileManager.tags = this._fileManager.tags.concat(fileTags); + filePluginRegExp.push(key); + for (let tag = 0, tLen = fileTags.length; tag < tLen; tag++) { + this._fileManager.pluginMap[fileTags[tag].toLowerCase()] = key; + } + } + if (plugin.managedTags) { + const info = plugin.managedTags(); + managedClass.push('.' + info.className); + this.managedTagsInfo.map[info.className] = info.method.bind(this); + } + } + + this.managedTagsInfo.query = managedClass.toString(); + this._fileManager.queryString = this._fileManager.tags.join(','); + this._fileManager.regExp = new wRegExp('^(' + this._fileManager.tags.join('|') + ')$', 'i'); + this._fileManager.pluginRegExp = new wRegExp('^(' + (filePluginRegExp.length === 0 ? 'undefined' : filePluginRegExp.join('|')) + ')$', 'i'); + + // cache editor's element + this._variable._originCssText = context.element.topArea.style.cssText; + this._placeholder = context.element.placeholder; + this._lineBreaker = context.element.lineBreaker; + this._lineBreakerButton = this._lineBreaker.querySelector('button'); + + // Excute history function + this.history = Object(_history__WEBPACK_IMPORTED_MODULE_2__["default"])(this, this._onChange_historyStack.bind(this)); + + // register notice module + this.addModule([_plugins_modules_notice__WEBPACK_IMPORTED_MODULE_4__["default"]]); + + // Init, validate + if (options.iframe) { + this._wd = context.element.wysiwygFrame.contentDocument; + context.element.wysiwyg = this._wd.body; + if (options._editorStyles.editor) context.element.wysiwyg.style.cssText = options._editorStyles.editor; + if (options.height === 'auto') this._iframeAuto = this._wd.body; + } + + this._initWysiwygArea(reload, _initHTML); + }, + + /** + * @description Caching basic buttons to use + * @private + */ + _cachingButtons: function () { + this.codeViewDisabledButtons = context.element.toolbar.querySelectorAll('.se-toolbar button:not([class~="se-code-view-enabled"])'); + this.resizingDisabledButtons = context.element.toolbar.querySelectorAll('.se-toolbar button:not([class~="se-resizing-enabled"])'); + const tool = context.tool; + this.commandMap = { + SUB: tool.subscript, + SUP: tool.superscript, + OUTDENT: tool.outdent, + INDENT: tool.indent + }; + this.commandMap[options.textTags.bold.toUpperCase()] = tool.bold; + this.commandMap[options.textTags.underline.toUpperCase()] = tool.underline; + this.commandMap[options.textTags.italic.toUpperCase()] = tool.italic; + this.commandMap[options.textTags.strike.toUpperCase()] = tool.strike; + + this._styleCommandMap = { + fullScreen: tool.fullScreen, + showBlocks: tool.showBlocks, + codeView: tool.codeView + }; + }, + + /** + * @description Initializ wysiwyg area (Only called from core._init) + * @param {Boolean} reload Is relooad? + * @param {String} _initHTML initial html string + * @private + */ + _initWysiwygArea: function (reload, _initHTML) { + context.element.wysiwyg.innerHTML = reload ? _initHTML : this.convertContentsForEditor(typeof _initHTML === 'string' ? _initHTML : context.element.originElement.value); + }, + + /** + * @description Called when there are changes to tags in the wysiwyg region. + * @private + */ + _resourcesStateChange: function () { + this._iframeAutoHeight(); + this._checkPlaceholder(); + }, + + /** + * @description Called when after execute "history.push" + * @private + */ + _onChange_historyStack: function () { + event._applyTagEffects(); + core._variable.isChanged = true; + if (context.tool.save) context.tool.save.removeAttribute('disabled'); + if (functions.onChange) functions.onChange(this.getContents(true), this); + if (context.element.toolbar.style.display === 'block') event._showToolbarBalloon(); + }, + + /** + * @description Modify the height value of the iframe when the height of the iframe is automatic. + * @private + */ + _iframeAutoHeight: function () { + if (this._iframeAuto) { + _w.setTimeout(function () { context.element.wysiwygFrame.style.height = core._iframeAuto.offsetHeight + 'px'; }); + } + }, + + /** + * @description Set display property when there is placeholder. + * @private + */ + _checkPlaceholder: function () { + if (this._placeholder) { + if (this._variable.isCodeView) { + this._placeholder.style.display = 'none'; + return; + } + + const wysiwyg = context.element.wysiwyg; + if (!util.onlyZeroWidthSpace(wysiwyg.textContent) || wysiwyg.querySelector('.se-component, pre, blockquote, hr, li, table, img, iframe, video') || (wysiwyg.innerText.match(/\n/g) || '').length > 1) { + this._placeholder.style.display = 'none'; + } else { + this._placeholder.style.display = 'block'; + } + } + }, + + /** + * @description If there is no default format, add a format and move "selection". + * @param {String|null} formatName Format tag name (default: 'P') + * @private + */ + _setDefaultFormat: function (formatName) { + if (this._fileManager.pluginRegExp.test(this.currentControllerName)) return; + + const range = this.getRange(); + const commonCon = range.commonAncestorContainer; + const startCon = range.startContainer; + const rangeEl = util.getRangeFormatElement(commonCon, null); + let focusNode, offset, format; + + const fileComponent = util.getParentElement(commonCon, util.isComponent); + if (fileComponent && !util.isTable(fileComponent)) return; + if((util.isRangeFormatElement(startCon) || util.isWysiwygDiv(startCon)) && util.isComponent(startCon.childNodes[range.startOffset])) return; + + if (rangeEl) { + format = util.createElement(formatName || options.defaultTag); + format.innerHTML = rangeEl.innerHTML; + if (format.childNodes.length === 0) format.innerHTML = util.zeroWidthSpace; + + rangeEl.innerHTML = format.outerHTML; + format = rangeEl.firstChild; + focusNode = util.getEdgeChildNodes(format, null).sc; + + if (!focusNode) { + focusNode = util.createTextNode(util.zeroWidthSpace); + format.insertBefore(focusNode, format.firstChild); + } + + offset = focusNode.textContent.length; + this.setRange(focusNode, offset, focusNode, offset); + return; + } + + if(util.isRangeFormatElement(commonCon) && (commonCon.childNodes.length <= 1)) { + let br = null; + if (commonCon.childNodes.length === 1 && util.isBreak(commonCon.firstChild)) { + br = commonCon.firstChild; + } else { + br = util.createTextNode(util.zeroWidthSpace); + commonCon.appendChild(br); + } + + this.setRange(br, 1, br, 1); + return; + } + + this.execCommand('formatBlock', false, (formatName || options.defaultTag)); + focusNode = util.getEdgeChildNodes(commonCon, commonCon); + focusNode = focusNode ? focusNode.ec : commonCon; + + format = util.getFormatElement(focusNode, null); + if (!format) { + this.removeRange(); + this._editorRange(); + return; + } + + if (util.isBreak(format.nextSibling)) util.removeItem(format.nextSibling); + if (util.isBreak(format.previousSibling)) util.removeItem(format.previousSibling); + if (util.isBreak(focusNode)) { + const zeroWidth = util.createTextNode(util.zeroWidthSpace); + focusNode.parentNode.insertBefore(zeroWidth, focusNode); + focusNode = zeroWidth; + } + + this.effectNode = null; + this.nativeFocus(); + }, + + /** + * @description Initialization after "setOptions" + * @param {Object} el context.element + * @param {String} _initHTML Initial html string + * @private + */ + _setOptionsInit: function (el, _initHTML) { + this.context = context = Object(_context__WEBPACK_IMPORTED_MODULE_1__["default"])(el.originElement, this._getConstructed(el), options); + this._componentsInfoReset = true; + this._editorInit(true, _initHTML); + }, + + /** + * @description Initializ editor + * @param {Boolean} reload Is relooad? + * @param {String} _initHTML initial html string + * @private + */ + _editorInit: function (reload, _initHTML) { + // initialize core and add event listeners + this._init(reload, _initHTML); + event._addEvent(); + this._setCharCount(); + event._offStickyToolbar(); + event.onResize_window(); + + // toolbar visibility + context.element.toolbar.style.visibility = ''; + + this._checkComponents(); + this._componentsInfoInit = false; + this._componentsInfoReset = false; + + this.history.reset(true); + this._resourcesStateChange(); + + _w.setTimeout(function () { + if (typeof functions.onload === 'function') functions.onload(core, reload); + }); + }, + + /** + * @description Create and return an object to cache the new context. + * @param {Element} contextEl context.element + * @returns {Object} + * @private + */ + _getConstructed: function (contextEl) { + return { + _top: contextEl.topArea, + _relative: contextEl.relative, + _toolBar: contextEl.toolbar, + _menuTray: contextEl._menuTray, + _editorArea: contextEl.editorArea, + _wysiwygArea: contextEl.wysiwygFrame, + _codeArea: contextEl.code, + _placeholder: contextEl.placeholder, + _resizingBar: contextEl.resizingBar, + _navigation: contextEl.navigation, + _charCounter: contextEl.charCounter, + _charWrapper: contextEl.charWrapper, + _loading: contextEl.loading, + _lineBreaker: contextEl.lineBreaker, + _lineBreaker_t: contextEl.lineBreaker_t, + _lineBreaker_b: contextEl.lineBreaker_b, + _resizeBack: contextEl.resizeBackground, + _stickyDummy: contextEl._stickyDummy, + _arrow: contextEl._arrow + }; + } + }; + + /** + * @description event function + */ + const event = { + _IEisComposing: false, // In IE, there is no "e.isComposing" in the key-up event. + _lineBreakerBind: null, + _responsiveCurrentSize: 'default', + _responsiveButtonSize: null, + _responsiveButtons: null, + _directionKeyCode: new _w.RegExp('^(8|13|3[2-9]|40|46)$'), + _nonTextKeyCode: new _w.RegExp('^(8|13|1[6-9]|20|27|3[3-9]|40|45|46|11[2-9]|12[0-3]|144|145)$'), + _historyIgnoreKeyCode: new _w.RegExp('^(1[6-9]|20|27|3[3-9]|40|45|11[2-9]|12[0-3]|144|145)$'), + _onButtonsCheck: new _w.RegExp('^(' + _w.Object.keys(options._textTagsMap).join('|') + ')$', 'i'), + _frontZeroWidthReg: new _w.RegExp(util.zeroWidthSpace + '+', ''), + _keyCodeShortcut: { + 65: 'A', + 66: 'B', + 83: 'S', + 85: 'U', + 73: 'I', + 89: 'Y', + 90: 'Z', + 219: '[', + 221: ']' + }, + + _shortcutCommand: function (keyCode, shift) { + let command = null; + const keyStr = event._keyCodeShortcut[keyCode]; + + switch (keyStr) { + case 'A': + command = 'selectAll'; + break; + case 'B': + if (options.shortcutsDisable.indexOf('bold') === -1) { + command = 'bold'; + } + break; + case 'S': + if (shift && options.shortcutsDisable.indexOf('strike') === -1) { + command = 'strike'; + } else if (!shift && options.shortcutsDisable.indexOf('save') === -1) { + command = 'save'; + } + break; + case 'U': + if (options.shortcutsDisable.indexOf('underline') === -1) { + command = 'underline'; + } + break; + case 'I': + if (options.shortcutsDisable.indexOf('italic') === -1) { + command = 'italic'; + } + break; + case 'Z': + if (options.shortcutsDisable.indexOf('undo') === -1) { + if (shift) { + command = 'redo'; + } else { + command = 'undo'; + } + } + break; + case 'Y': + if (options.shortcutsDisable.indexOf('undo') === -1) { + command = 'redo'; + } + break; + case '[': + if (options.shortcutsDisable.indexOf('indent') === -1) { + command = options.rtl ? 'indent' : 'outdent'; + } + break; + case ']': + if (options.shortcutsDisable.indexOf('indent') === -1) { + command = options.rtl ? 'outdent' : 'indent'; + } + break; + } + + if (!command) return false; + + core.commandHandler(core.commandMap[command], command); + return true; + }, + + _applyTagEffects: function () { + let selectionNode = core.getSelectionNode(); + if (selectionNode === core.effectNode) return; + core.effectNode = selectionNode; + + const marginDir = options.rtl ? 'marginRight' : 'marginLeft'; + const commandMap = core.commandMap; + const classOnCheck = this._onButtonsCheck; + const commandMapNodes = []; + const currentNodes = []; + + const activePlugins = core.activePlugins; + const cLen = activePlugins.length; + let nodeName = ''; + + while (selectionNode.firstChild) { + selectionNode = selectionNode.firstChild; + } + + for (let element = selectionNode; !util.isWysiwygDiv(element); element = element.parentNode) { + if (!element) break; + if (element.nodeType !== 1 || util.isBreak(element)) continue; + nodeName = element.nodeName.toUpperCase(); + currentNodes.push(nodeName); + + /* Active plugins */ + for (let c = 0, name; c < cLen; c++) { + name = activePlugins[c]; + if (commandMapNodes.indexOf(name) === -1 && plugins[name].active.call(core, element)) { + commandMapNodes.push(name); + } + } + + if (util.isFormatElement(element)) { + /* Outdent */ + if (commandMapNodes.indexOf('OUTDENT') === -1 && commandMap.OUTDENT) { + if (util.isListCell(element) || (element.style[marginDir] && util.getNumber(element.style[marginDir], 0) > 0)) { + commandMapNodes.push('OUTDENT'); + commandMap.OUTDENT.removeAttribute('disabled'); + } + } + + /* Indent */ + if (commandMapNodes.indexOf('INDENT') === -1 && commandMap.INDENT && util.isListCell(element) && !element.previousElementSibling) { + commandMapNodes.push('INDENT'); + commandMap.INDENT.setAttribute('disabled', true); + } + + continue; + } + + /** default active buttons [strong, ins, em, del, sub, sup] */ + if (classOnCheck.test(nodeName)) { + commandMapNodes.push(nodeName); + util.addClass(commandMap[nodeName], 'active'); + } + } + + /** remove class, display text */ + for (let key in commandMap) { + if (commandMapNodes.indexOf(key) > -1 || !util.hasOwn(commandMap, key)) continue; + if (activePlugins.indexOf(key) > -1) { + plugins[key].active.call(core, null); + } else if (commandMap.OUTDENT && /^OUTDENT$/i.test(key)) { + commandMap.OUTDENT.setAttribute('disabled', true); + } else if (commandMap.INDENT && /^INDENT$/i.test(key)) { + commandMap.INDENT.removeAttribute('disabled'); + } else { + util.removeClass(commandMap[key], 'active'); + } + } + + /** save current nodes */ + core._variable.currentNodes = currentNodes.reverse(); + core._variable.currentNodesMap = commandMapNodes; + + /** Displays the current node structure to resizingBar */ + if (options.showPathLabel) context.element.navigation.textContent = core._variable.currentNodes.join(' > '); + }, + + _cancelCaptionEdit: function () { + this.setAttribute('contenteditable', false); + this.removeEventListener('blur', event._cancelCaptionEdit); + }, + + _buttonsEventHandler: function (e) { + let target = e.target; + if (core._bindControllersOff) e.stopPropagation(); + + if (/^(input|textarea|select|option)$/i.test(target.nodeName)) { + core._antiBlur = false; + } else { + e.preventDefault(); + } + + if (util.getParentElement(target, '.se-submenu')) { + e.stopPropagation(); + core._notHideToolbar = true; + } else { + let command = target.getAttribute('data-command'); + let className = target.className; + + while (!command && !/se-menu-list/.test(className) && !/sun-editor-common/.test(className)) { + target = target.parentNode; + command = target.getAttribute('data-command'); + className = target.className; + } + + if (command === core._submenuName || command === core._containerName) { + e.stopPropagation(); + } + } + }, + + onClick_toolbar: function (e) { + let target = e.target; + let display = target.getAttribute('data-display'); + let command = target.getAttribute('data-command'); + let className = target.className; + + while (target.parentNode && !command && !/se-menu-list/.test(className) && !/se-toolbar/.test(className)) { + target = target.parentNode; + command = target.getAttribute('data-command'); + display = target.getAttribute('data-display'); + className = target.className; + } + + if (!command && !display) return; + if (target.disabled) return; + if (!core.hasFocus) core.nativeFocus(); + if (!core._variable.isCodeView) core._editorRange(); + + core.actionCall(command, display, target); + }, + + onMouseDown_wysiwyg: function (e) { + if (util.isNonEditable(context.element.wysiwyg)) return; + + const tableCell = util.getParentElement(e.target, util.isCell); + if (tableCell) { + const tablePlugin = core.plugins.table; + if (tablePlugin && tableCell !== tablePlugin._fixedCell && !tablePlugin._shift) { + core.callPlugin('table', function () { + tablePlugin.onTableCellMultiSelect.call(core, tableCell, false); + }, null); + } + } + + if (core._isBalloon) { + event._hideToolbar(); + } + + if (/FIGURE/i.test(e.target.nodeName)) e.preventDefault(); + if (typeof functions.onMouseDown === 'function') functions.onMouseDown(e, core); + }, + + onClick_wysiwyg: function (e) { + const targetElement = e.target; + if (util.isNonEditable(context.element.wysiwyg)) return; + + const fileComponentInfo = core.getFileComponent(targetElement); + if (fileComponentInfo) { + e.preventDefault(); + core.selectComponent(fileComponentInfo.target, fileComponentInfo.pluginName); + return; + } + + const figcaption = util.getParentElement(targetElement, 'FIGCAPTION'); + if (util.isNonEditable(figcaption)) { + e.preventDefault(); + figcaption.setAttribute('contenteditable', true); + figcaption.focus(); + + if (core._isInline && !core._inlineToolbarAttr.isShow) { + event._showToolbarInline(); + + const hideToolbar = function () { + event._hideToolbar(); + figcaption.removeEventListener('blur', hideToolbar); + }; + + figcaption.addEventListener('blur', hideToolbar); + } + } + + _w.setTimeout(core._editorRange.bind(core)); + core._editorRange(); + + const selectionNode = core.getSelectionNode(); + const formatEl = util.getFormatElement(selectionNode, null); + const rangeEl = util.getRangeFormatElement(selectionNode, null); + if ((!formatEl || formatEl === rangeEl) && !util.isNonEditable(targetElement) && !util.isList(rangeEl)) { + const range = core.getRange(); + if (util.getFormatElement(range.startContainer) === util.getFormatElement(range.endContainer)) { + if (util.isList(rangeEl)) { + e.preventDefault(); + const oLi = util.createElement('LI'); + const prevLi = selectionNode.nextElementSibling; + oLi.appendChild(selectionNode); + rangeEl.insertBefore(oLi, prevLi); + core.focus(); + } else if (!util.isWysiwygDiv(selectionNode) && !util.isComponent(selectionNode) && (!util.isTable(selectionNode) || util.isCell(selectionNode))) { + e.preventDefault(); + core._setDefaultFormat(util.isRangeFormatElement(rangeEl) ? 'DIV' : options.defaultTag); + core.focus(); + } else { + event._applyTagEffects(); + } + } + } else { + event._applyTagEffects(); + } + + if (core._isBalloon) _w.setTimeout(event._toggleToolbarBalloon); + if (typeof functions.onClick === 'function') functions.onClick(e, core); + }, + + _balloonDelay: null, + _showToolbarBalloonDelay: function () { + if (event._balloonDelay) { + _w.clearTimeout(event._balloonDelay); + } + + event._balloonDelay = _w.setTimeout(function () { + _w.clearTimeout(this._balloonDelay); + this._balloonDelay = null; + this._showToolbarBalloon(); + }.bind(event), 350); + }, + + _toggleToolbarBalloon: function () { + core._editorRange(); + const range = core.getRange(); + if (core._bindControllersOff || (!core._isBalloonAlways && range.collapsed)) event._hideToolbar(); + else event._showToolbarBalloon(range); + }, + + _showToolbarBalloon: function (rangeObj) { + if (!core._isBalloon) return; + + const range = rangeObj || core.getRange(); + const toolbar = context.element.toolbar; + const topArea = context.element.topArea; + const selection = core.getSelection(); + + let isDirTop; + if (core._isBalloonAlways && range.collapsed) { + isDirTop = true; + } else if (selection.focusNode === selection.anchorNode) { + isDirTop = selection.focusOffset < selection.anchorOffset; + } else { + const childNodes = util.getListChildNodes(range.commonAncestorContainer, null); + isDirTop = util.getArrayIndex(childNodes, selection.focusNode) < util.getArrayIndex(childNodes, selection.anchorNode); + } + + let rects = range.getClientRects(); + rects = rects[isDirTop ? 0 : rects.length - 1]; + + const globalScroll = core.getGlobalScrollOffset(); + let scrollLeft = globalScroll.left; + let scrollTop = globalScroll.top; + + const editorWidth = topArea.offsetWidth; + const offsets = event._getEditorOffsets(null); + const stickyTop = offsets.top; + const editorLeft = offsets.left; + + toolbar.style.top = '-10000px'; + toolbar.style.visibility = 'hidden'; + toolbar.style.display = 'block'; + + if (!rects) { + const node = core.getSelectionNode(); + if (util.isFormatElement(node)) { + const zeroWidth = util.createTextNode(util.zeroWidthSpace); + core.insertNode(zeroWidth, null, false); + core.setRange(zeroWidth, 1, zeroWidth, 1); + core._editorRange(); + rects = core.getRange().getClientRects(); + rects = rects[isDirTop ? 0 : rects.length - 1]; + } + + if (!rects) { + const nodeOffset = util.getOffset(node, context.element.wysiwygFrame); + rects = { + left: nodeOffset.left, + top: nodeOffset.top, + right: nodeOffset.left, + bottom: nodeOffset.top + node.offsetHeight, + noText: true + }; + scrollLeft = 0; + scrollTop = 0; + } + + isDirTop = true; + } + + const arrowMargin = _w.Math.round(context.element._arrow.offsetWidth / 2); + const toolbarWidth = toolbar.offsetWidth; + const toolbarHeight = toolbar.offsetHeight; + const iframeRects = /iframe/i.test(context.element.wysiwygFrame.nodeName) ? context.element.wysiwygFrame.getClientRects()[0] : null; + if (iframeRects) { + rects = { + left: rects.left + iframeRects.left, + top: rects.top + iframeRects.top, + right: rects.right + iframeRects.right - iframeRects.width, + bottom: rects.bottom + iframeRects.bottom - iframeRects.height + }; + } + + event._setToolbarOffset(isDirTop, rects, toolbar, editorLeft, editorWidth, scrollLeft, scrollTop, stickyTop, arrowMargin); + if (toolbarWidth !== toolbar.offsetWidth || toolbarHeight !== toolbar.offsetHeight) { + event._setToolbarOffset(isDirTop, rects, toolbar, editorLeft, editorWidth, scrollLeft, scrollTop, stickyTop, arrowMargin); + } + + if (options.toolbarContainer) { + const editorParent = topArea.parentElement; + + let container = options.toolbarContainer; + let left = container.offsetLeft; + let top = container.offsetTop; + + while(!container.parentElement.contains(editorParent) || !/^(BODY|HTML)$/i.test(container.parentElement.nodeName)) { + container = container.offsetParent; + left += container.offsetLeft; + top += container.offsetTop; + } + + toolbar.style.left = (toolbar.offsetLeft - left + topArea.offsetLeft) + 'px'; + toolbar.style.top = (toolbar.offsetTop - top + topArea.offsetTop) + 'px'; + } + + toolbar.style.visibility = ''; + }, + + _setToolbarOffset: function (isDirTop, rects, toolbar, editorLeft, editorWidth, scrollLeft, scrollTop, stickyTop, arrowMargin) { + const padding = 1; + const toolbarWidth = toolbar.offsetWidth; + const toolbarHeight = rects.noText && !isDirTop ? 0 : toolbar.offsetHeight; + + const absoluteLeft = (isDirTop ? rects.left : rects.right) - editorLeft - (toolbarWidth / 2) + scrollLeft; + const overRight = absoluteLeft + toolbarWidth - editorWidth; + + let t = (isDirTop ? rects.top - toolbarHeight - arrowMargin : rects.bottom + arrowMargin) - (rects.noText ? 0 : stickyTop) + scrollTop; + let l = absoluteLeft < 0 ? padding : overRight < 0 ? absoluteLeft : absoluteLeft - overRight - padding - 1; + + let resetTop = false; + const space = t + (isDirTop ? (event._getEditorOffsets(null).top) : (toolbar.offsetHeight - context.element.wysiwyg.offsetHeight)); + if (!isDirTop && space > 0 && event._getPageBottomSpace() < space) { + isDirTop = true; + resetTop = true; + } else if (isDirTop && _d.documentElement.offsetTop > space) { + isDirTop = false; + resetTop = true; + } + + if (resetTop) t = (isDirTop ? rects.top - toolbarHeight - arrowMargin : rects.bottom + arrowMargin) - (rects.noText ? 0 : stickyTop) + scrollTop; + + toolbar.style.left = _w.Math.floor(l) + 'px'; + toolbar.style.top = _w.Math.floor(t) + 'px'; + + if (isDirTop) { + util.removeClass(context.element._arrow, 'se-arrow-up'); + util.addClass(context.element._arrow, 'se-arrow-down'); + context.element._arrow.style.top = toolbarHeight + 'px'; + } else { + util.removeClass(context.element._arrow, 'se-arrow-down'); + util.addClass(context.element._arrow, 'se-arrow-up'); + context.element._arrow.style.top = -arrowMargin + 'px'; + } + + const arrow_left = _w.Math.floor((toolbarWidth / 2) + (absoluteLeft - l)); + context.element._arrow.style.left = (arrow_left + arrowMargin > toolbar.offsetWidth ? toolbar.offsetWidth - arrowMargin : arrow_left < arrowMargin ? arrowMargin : arrow_left) + 'px'; + }, + + _showToolbarInline: function () { + if (!core._isInline) return; + + const toolbar = context.element.toolbar; + if (options.toolbarContainer) toolbar.style.position = 'relative'; + else toolbar.style.position = 'absolute'; + + toolbar.style.visibility = 'hidden'; + toolbar.style.display = 'block'; + core._inlineToolbarAttr.width = toolbar.style.width = options.toolbarWidth; + core._inlineToolbarAttr.top = toolbar.style.top = (options.toolbarContainer ? 0 : (-1 - toolbar.offsetHeight)) + 'px'; + + if (typeof functions.showInline === 'function') functions.showInline(toolbar, context, core); + + event.onScroll_window(); + core._inlineToolbarAttr.isShow = true; + toolbar.style.visibility = ''; + }, + + _hideToolbar: function () { + if (!core._notHideToolbar && !core._variable.isFullScreen) { + context.element.toolbar.style.display = 'none'; + core._inlineToolbarAttr.isShow = false; + } + }, + + onInput_wysiwyg: function (e) { + core._editorRange(); + + const data = (e.data === null ? '' : e.data === undefined ? ' ' : e.data) || ''; + if (!core._charCount(data)) { + e.preventDefault(); + e.stopPropagation(); + } + + // history stack + core.history.push(true); + + if (typeof functions.onInput === 'function') functions.onInput(e, core); + }, + + _isUneditableNode: function (range, isFront) { + const container = isFront ? range.startContainer : range.endContainer; + const offset = isFront ? range.startOffset : range.endOffset; + const siblingKey = isFront ? 'previousSibling' : 'nextSibling'; + const isElement = container.nodeType === 1; + let siblingNode; + + if (isElement) { + siblingNode = event._isUneditableNode_getSibling(container.childNodes[offset], siblingKey, container); + return siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false'; + } else { + siblingNode = event._isUneditableNode_getSibling(container, siblingKey, container); + return core.isEdgePoint(container, offset, isFront ? 'front' : 'end') && (siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false'); + } + }, + + _isUneditableNode_getSibling: function (selectNode, siblingKey, container) { + if (!selectNode) return null; + let siblingNode = selectNode[siblingKey]; + + if (!siblingNode) { + siblingNode = util.getFormatElement(container); + siblingNode = siblingNode ? siblingNode[siblingKey] : null; + if (siblingNode && !util.isComponent(siblingNode)) siblingNode = siblingKey === 'previousSibling' ? siblingNode.firstElementChild : siblingNode.lastElementChild; + else return null; + } + + return siblingNode; + }, + + _onShortcutKey: false, + onKeyDown_wysiwyg: function (e) { + const keyCode = e.keyCode; + const shift = e.shiftKey; + const ctrl = e.ctrlKey || e.metaKey || keyCode === 91 || keyCode === 92 || keyCode === 224; + const alt = e.altKey; + event._IEisComposing = keyCode === 229; + + core.submenuOff(); + + if (core._isBalloon) { + event._hideToolbar(); + } + + /** Shortcuts */ + if (ctrl && event._shortcutCommand(keyCode, shift)) { + event._onShortcutKey = true; + e.preventDefault(); + e.stopPropagation(); + return false; + } else if (event._onShortcutKey) { + event._onShortcutKey = false; + } + + /** default key action */ + let selectionNode = core.getSelectionNode(); + const range = core.getRange(); + const selectRange = !range.collapsed || range.startContainer !== range.endContainer; + const fileComponentName = core._fileManager.pluginRegExp.test(core.currentControllerName) ? core.currentControllerName : ''; + let formatEl = util.getFormatElement(selectionNode, null) || selectionNode; + let rangeEl = util.getRangeFormatElement(formatEl, null); + + switch (keyCode) { + case 8: /** backspace key */ + if (!selectRange) { + if (fileComponentName) { + e.preventDefault(); + e.stopPropagation(); + core.plugins[fileComponentName].destroy.call(core); + break; + } + } + + if (selectRange && event._hardDelete()) { + e.preventDefault(); + e.stopPropagation(); + break; + } + + if (!util.isFormatElement(formatEl) && !context.element.wysiwyg.firstElementChild && !util.isComponent(selectionNode)) { + e.preventDefault(); + e.stopPropagation(); + core._setDefaultFormat(options.defaultTag); + return false; + } + + if (!selectRange && !formatEl.previousElementSibling && (range.startOffset === 0 && !selectionNode.previousSibling && !util.isListCell(formatEl) && + (util.isFormatElement(formatEl) && (!util.isFreeFormatElement(formatEl) || util.isClosureFreeFormatElement(formatEl))))) { + // closure range + if (util.isClosureRangeFormatElement(formatEl.parentNode)) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + // maintain default format + if (util.isWysiwygDiv(formatEl.parentNode) && formatEl.childNodes.length <= 1 && (!formatEl.firstChild || util.onlyZeroWidthSpace(formatEl.textContent))) { + e.preventDefault(); + e.stopPropagation(); + + if (formatEl.nodeName.toUpperCase() === options.defaultTag.toUpperCase()) { + formatEl.innerHTML = '
'; + const attrs = formatEl.attributes; + while (attrs[0]) { + formatEl.removeAttribute(attrs[0].name); + } + } else { + const defaultFormat = util.createElement(options.defaultTag); + defaultFormat.innerHTML = '
'; + formatEl.parentElement.replaceChild(defaultFormat, formatEl); + } + + core.nativeFocus(); + return false; + } + } + + // clean remove tag + if (formatEl && range.startContainer === range.endContainer && selectionNode.nodeType === 3 && !util.isFormatElement(selectionNode.parentNode)) { + if (range.collapsed ? selectionNode.textContent.length === 1 : (range.endOffset - range.startOffset) === selectionNode.textContent.length) { + e.preventDefault(); + + let offset = null; + let prev = selectionNode.parentNode.previousSibling; + const next = selectionNode.parentNode.nextSibling; + if (!prev) { + if (!next) { + prev = util.createElement('BR'); + formatEl.appendChild(prev); + } else { + prev = next; + offset = 0; + } + } + + selectionNode.textContent = ''; + util.removeItemAllParents(selectionNode, null, formatEl); + offset = typeof offset === 'number' ? offset : prev.nodeType === 3 ? prev.textContent.length : 1; + core.setRange(prev, offset, prev, offset); + break; + } + } + + // tag[contenteditable="false"] + if (event._isUneditableNode(range, true)) { + e.preventDefault(); + e.stopPropagation(); + break; + } + + // nested list + const commonCon = range.commonAncestorContainer; + formatEl = util.getFormatElement(range.startContainer, null); + rangeEl = util.getRangeFormatElement(formatEl, null); + if (rangeEl && formatEl && !util.isCell(rangeEl) && !/^FIGCAPTION$/i.test(rangeEl.nodeName)) { + if (util.isListCell(formatEl) && util.isList(rangeEl) && (util.isListCell(rangeEl.parentNode) || formatEl.previousElementSibling) && (selectionNode === formatEl || (selectionNode.nodeType === 3 && (!selectionNode.previousSibling || util.isList(selectionNode.previousSibling)))) && + (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.startContainer) : (range.startOffset === 0 && range.collapsed))) { + if (range.startContainer !== range.endContainer) { + e.preventDefault(); + + core.removeNode(); + if (range.startContainer.nodeType === 3) { + core.setRange(range.startContainer, range.startContainer.textContent.length, range.startContainer, range.startContainer.textContent.length); + } + // history stack + core.history.push(true); + } else { + let prev = formatEl.previousElementSibling || rangeEl.parentNode; + if (util.isListCell(prev)) { + e.preventDefault(); + + let prevLast = prev; + if (!prev.contains(formatEl) && util.isListCell(prevLast) && util.isList(prevLast.lastElementChild)) { + prevLast = prevLast.lastElementChild.lastElementChild; + while (util.isListCell(prevLast) && util.isList(prevLast.lastElementChild)) { + prevLast = prevLast.lastElementChild && prevLast.lastElementChild.lastElementChild; + } + prev = prevLast; + } + + let con = prev === rangeEl.parentNode ? rangeEl.previousSibling : prev.lastChild; + if (!con) { + con = util.createTextNode(util.zeroWidthSpace); + rangeEl.parentNode.insertBefore(con, rangeEl.parentNode.firstChild); + } + const offset = con.nodeType === 3 ? con.textContent.length : 1; + const children = formatEl.childNodes; + let after = con; + let child = children[0]; + while ((child = children[0])) { + prev.insertBefore(child, after.nextSibling); + after = child; + } + + util.removeItem(formatEl); + if (rangeEl.children.length === 0) util.removeItem(rangeEl); + + core.setRange(con, offset, con, offset); + // history stack + core.history.push(true); + } + } + + break; + } + + // detach range + if (!selectRange && range.startOffset === 0) { + let detach = true; + let comm = commonCon; + while (comm && comm !== rangeEl && !util.isWysiwygDiv(comm)) { + if (comm.previousSibling) { + if (comm.previousSibling.nodeType === 1 || !util.onlyZeroWidthSpace(comm.previousSibling.textContent.trim())) { + detach = false; + break; + } + } + comm = comm.parentNode; + } + + if (detach && rangeEl.parentNode) { + e.preventDefault(); + core.detachRangeFormatElement(rangeEl, (util.isListCell(formatEl) ? [formatEl] : null), null, false, false); + // history stack + core.history.push(true); + break; + } + } + } + + // component + if (!selectRange && formatEl && (range.startOffset === 0 || (selectionNode === formatEl ? !!formatEl.childNodes[range.startOffset] : false))) { + const sel = selectionNode === formatEl ? formatEl.childNodes[range.startOffset] : selectionNode; + const prev = formatEl.previousSibling; + // select file component + const ignoreZWS = (commonCon.nodeType === 3 || util.isBreak(commonCon)) && !commonCon.previousSibling && range.startOffset === 0; + if (!sel.previousSibling && (util.isComponent(commonCon.previousSibling) || (ignoreZWS && util.isComponent(prev)))) { + const fileComponentInfo = core.getFileComponent(prev); + if (fileComponentInfo) { + e.preventDefault(); + e.stopPropagation(); + if (formatEl.textContent.length === 0) util.removeItem(formatEl); + if (core.selectComponent(fileComponentInfo.target, fileComponentInfo.pluginName) === false) core.blur(); + } else if (util.isComponent(prev)) { + e.preventDefault(); + e.stopPropagation(); + util.removeItem(prev); + } + break; + } + // delete nonEditable + if (util.isNonEditable(sel.previousSibling)) { + e.preventDefault(); + e.stopPropagation(); + util.removeItem(sel.previousSibling); + break; + } + } + + break; + case 46: /** delete key */ + if (fileComponentName) { + e.preventDefault(); + e.stopPropagation(); + core.plugins[fileComponentName].destroy.call(core); + break; + } + + if (selectRange && event._hardDelete()) { + e.preventDefault(); + e.stopPropagation(); + break; + } + + // tag[contenteditable="false"] + if (event._isUneditableNode(range, false)) { + e.preventDefault(); + e.stopPropagation(); + break; + } + + // component + if ((util.isFormatElement(selectionNode) || selectionNode.nextSibling === null || (util.onlyZeroWidthSpace(selectionNode.nextSibling) && selectionNode.nextSibling.nextSibling === null)) && range.startOffset === selectionNode.textContent.length) { + let nextEl = formatEl.nextElementSibling; + if (!nextEl) { + e.preventDefault(); + break; + } + + if (util.isComponent(nextEl)) { + e.preventDefault(); + + if (util.onlyZeroWidthSpace(formatEl)) { + util.removeItem(formatEl); + // table component + if (util.isTable(nextEl)) { + let cell = util.getChildElement(nextEl, util.isCell, false); + cell = cell.firstElementChild || cell; + core.setRange(cell, 0, cell, 0); + break; + } + } + + // select file component + const fileComponentInfo = core.getFileComponent(nextEl); + if (fileComponentInfo) { + e.stopPropagation(); + if (core.selectComponent(fileComponentInfo.target, fileComponentInfo.pluginName) === false) core.blur(); + } else if (util.isComponent(nextEl)) { + e.stopPropagation(); + util.removeItem(nextEl); + } + + break; + } + } + + if (!selectRange && (core.isEdgePoint(range.endContainer, range.endOffset) || (selectionNode === formatEl ? !!formatEl.childNodes[range.startOffset] : false))) { + const sel = selectionNode === formatEl ? formatEl.childNodes[range.startOffset] : selectionNode; + // delete nonEditable + if (util.isNonEditable(sel.nextSibling)) { + e.preventDefault(); + e.stopPropagation(); + util.removeItem(sel.nextSibling); + break; + } + } + + // nested list + formatEl = util.getFormatElement(range.startContainer, null); + rangeEl = util.getRangeFormatElement(formatEl, null); + if (util.isListCell(formatEl) && util.isList(rangeEl) && (selectionNode === formatEl || (selectionNode.nodeType === 3 && (!selectionNode.nextSibling || util.isList(selectionNode.nextSibling)) && + (util.getFormatElement(range.startContainer, null) !== util.getFormatElement(range.endContainer, null) ? rangeEl.contains(range.endContainer) : (range.endOffset === selectionNode.textContent.length && range.collapsed))))) { + if (range.startContainer !== range.endContainer) core.removeNode(); + + let next = util.getArrayItem(formatEl.children, util.isList, false); + next = next || formatEl.nextElementSibling || rangeEl.parentNode.nextElementSibling; + if (next && (util.isList(next) || util.getArrayItem(next.children, util.isList, false))) { + e.preventDefault(); + + let con, children; + if (util.isList(next)) { + const child = next.firstElementChild; + children = child.childNodes; + con = children[0]; + while (children[0]) { + formatEl.insertBefore(children[0], next); + } + util.removeItem(child); + } else { + con = next.firstChild; + children = next.childNodes; + while (children[0]) { + formatEl.appendChild(children[0]); + } + util.removeItem(next); + } + core.setRange(con, 0, con, 0); + // history stack + core.history.push(true); + } + break; + } + + break; + case 9: /** tab key */ + if (fileComponentName || options.tabDisable) break; + e.preventDefault(); + if (ctrl || alt || util.isWysiwygDiv(selectionNode)) break; + + const isEdge = (!range.collapsed || core.isEdgePoint(range.startContainer, range.startOffset)); + const selectedFormats = core.getSelectedElements(null); + selectionNode = core.getSelectionNode(); + const cells = []; + let lines = []; + let fc = util.isListCell(selectedFormats[0]), lc = util.isListCell(selectedFormats[selectedFormats.length - 1]); + let r = {sc: range.startContainer, so: range.startOffset, ec: range.endContainer, eo: range.endOffset}; + for (let i = 0, len = selectedFormats.length, f; i < len; i++) { + f = selectedFormats[i]; + if (util.isListCell(f)) { + if (!f.previousElementSibling && !shift) { + continue; + } else { + cells.push(f); + } + } else { + lines.push(f); + } + } + + // Nested list + if (cells.length > 0 && isEdge && core.plugins.list) { + r = core.plugins.list.editInsideList.call(core, shift, cells); + } else { + // table + const tableCell = util.getParentElement(selectionNode, util.isCell); + if (tableCell && isEdge) { + const table = util.getParentElement(tableCell, 'table'); + const cells = util.getListChildren(table, util.isCell); + let idx = shift ? util.prevIdx(cells, tableCell) : util.nextIdx(cells, tableCell); + + if (idx === cells.length && !shift) idx = 0; + if (idx === -1 && shift) idx = cells.length - 1; + + let moveCell = cells[idx]; + if (!moveCell) break; + moveCell = moveCell.firstElementChild || moveCell; + core.setRange(moveCell, 0, moveCell, 0); + break; + } + + lines = lines.concat(cells); + fc = lc = null; + } + + // Lines tab(4) + if (lines.length > 0) { + if (!shift) { + const tabText = util.createTextNode(new _w.Array(core._variable.tabSize + 1).join('\u00A0')); + if (lines.length === 1) { + const textRange = core.insertNode(tabText, null, true); + if (!textRange) return false; + if (!fc) { + r.sc = tabText; + r.so = textRange.endOffset; + } + if (!lc) { + r.ec = tabText; + r.eo = textRange.endOffset; + } + } else { + const len = lines.length - 1; + for (let i = 0, child; i <= len; i++) { + child = lines[i].firstChild; + if (!child) continue; + + if (util.isBreak(child)) { + lines[i].insertBefore(tabText.cloneNode(false), child); + } else { + child.textContent = tabText.textContent + child.textContent; + } + } + + const firstChild = util.getChildElement(lines[0], 'text', false); + const endChild = util.getChildElement(lines[len], 'text', true); + if (!fc && firstChild) { + r.sc = firstChild; + r.so = 0; + } + if (!lc && endChild) { + r.ec = endChild; + r.eo = endChild.textContent.length; + } + } + } else { + const len = lines.length - 1; + for (let i = 0, line; i <= len; i++) { + line = lines[i].childNodes; + for (let c = 0, cLen = line.length, child; c < cLen; c++) { + child = line[c]; + if (!child) break; + if (util.onlyZeroWidthSpace(child)) continue; + + if (/^\s{1,4}$/.test(child.textContent)) { + util.removeItem(child); + } else if (/^\s{1,4}/.test(child.textContent)) { + child.textContent = child.textContent.replace(/^\s{1,4}/, ''); + } + + break; + } + } + + const firstChild = util.getChildElement(lines[0], 'text', false); + const endChild = util.getChildElement(lines[len], 'text', true); + if (!fc && firstChild) { + r.sc = firstChild; + r.so = 0; + } + if (!lc && endChild) { + r.ec = endChild; + r.eo = endChild.textContent.length; + } + } + } + + core.setRange(r.sc, r.so, r.ec, r.eo); + // history stack + core.history.push(false); + + break; + case 13: /** enter key */ + const freeFormatEl = util.getFreeFormatElement(selectionNode, null); + + if (core._charTypeHTML) { + let enterHTML = ''; + if ((!shift && freeFormatEl) || shift) { + enterHTML = '
'; + } else { + enterHTML = '<' + formatEl.nodeName + '>
'; + } + + if (!core.checkCharCount(enterHTML, 'byte-html')) { + e.preventDefault(); + return false; + } + } + + if (!shift && /^H[1-6]$/i.test(formatEl.nodeName) && core.isEdgeFormat(range.endContainer, range.endOffset, 'end')) { + e.preventDefault(); + const newFormat = core.appendFormatTag(formatEl, options.defaultTag); + core.setRange(newFormat, 1, newFormat, 1); + break; + } + + if (!shift && freeFormatEl) { + e.preventDefault(); + const selectionFormat = selectionNode === freeFormatEl; + const wSelection = core.getSelection(); + const children = selectionNode.childNodes, offset = wSelection.focusOffset, prev = selectionNode.previousElementSibling, next = selectionNode.nextSibling; + + if (!util.isClosureFreeFormatElement(freeFormatEl) && !!children && ((selectionFormat && range.collapsed && children.length - 1 <= offset + 1 && util.isBreak(children[offset]) && (!children[offset + 1] || ((!children[offset + 2] || util.onlyZeroWidthSpace(children[offset + 2].textContent)) && children[offset + 1].nodeType === 3 && util.onlyZeroWidthSpace(children[offset + 1].textContent))) && offset > 0 && util.isBreak(children[offset - 1])) || + (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(prev) && (util.isBreak(prev.previousSibling) || !util.onlyZeroWidthSpace(prev.previousSibling.textContent)) && (!next || (!util.isBreak(next) && util.onlyZeroWidthSpace(next.textContent)))))) { + if (selectionFormat) util.removeItem(children[offset - 1]); + else util.removeItem(selectionNode); + const newEl = core.appendFormatTag(freeFormatEl, util.isFormatElement(freeFormatEl.nextElementSibling) ? freeFormatEl.nextElementSibling : null); + util.copyFormatAttributes(newEl, freeFormatEl); + core.setRange(newEl, 1, newEl, 1); + break; + } + + if (selectionFormat) { + functions.insertHTML(((range.collapsed && util.isBreak(range.startContainer.childNodes[range.startOffset - 1])) ? '
' : '

'), true, false); + + let focusNode = wSelection.focusNode; + const wOffset = wSelection.focusOffset; + if (freeFormatEl === focusNode) { + focusNode = focusNode.childNodes[wOffset - offset > 1 ? wOffset - 1 : wOffset]; + } + + core.setRange(focusNode, 1, focusNode, 1); + } else { + const focusNext = wSelection.focusNode.nextSibling; + const br = util.createElement('BR'); + core.insertNode(br, null, false); + + const brPrev = br.previousSibling, brNext = br.nextSibling; + if (!util.isBreak(focusNext) && !util.isBreak(brPrev) && (!brNext || util.onlyZeroWidthSpace(brNext))) { + br.parentNode.insertBefore(br.cloneNode(false), br); + core.setRange(br, 1, br, 1); + } else { + core.setRange(brNext, 0, brNext, 0); + } + } + + event._onShortcutKey = true; + break; + } + + if (selectRange) break; + + if (rangeEl && formatEl && !util.isCell(rangeEl) && !/^FIGCAPTION$/i.test(rangeEl.nodeName)) { + const range = core.getRange(); + if(core.isEdgePoint(range.endContainer, range.endOffset) && util.isList(selectionNode.nextSibling)) { + e.preventDefault(); + const newEl = util.createElement('LI'); + const br = util.createElement('BR'); + newEl.appendChild(br); + + formatEl.parentNode.insertBefore(newEl, formatEl.nextElementSibling); + newEl.appendChild(selectionNode.nextSibling); + + core.setRange(br, 1, br, 1); + break; + } + + if ((range.commonAncestorContainer.nodeType === 3 ? !range.commonAncestorContainer.nextElementSibling : true) && util.onlyZeroWidthSpace(formatEl.innerText.trim())) { + e.preventDefault(); + let newEl = null; + + if (util.isListCell(rangeEl.parentNode)) { + rangeEl = formatEl.parentNode.parentNode.parentNode; + newEl = util.splitElement(formatEl, null, util.getElementDepth(formatEl) - 2); + if (!newEl) { + const newListCell = util.createElement('LI'); + newListCell.innerHTML = '
'; + rangeEl.insertBefore(newListCell, newEl); + newEl = newListCell; + } + } else { + const newFormat = util.isCell(rangeEl.parentNode) ? 'DIV' : util.isList(rangeEl.parentNode) ? 'LI' : util.isFormatElement(rangeEl.nextElementSibling) ? rangeEl.nextElementSibling.nodeName : util.isFormatElement(rangeEl.previousElementSibling) ? rangeEl.previousElementSibling.nodeName : options.defaultTag; + newEl = util.createElement(newFormat); + const edge = core.detachRangeFormatElement(rangeEl, [formatEl], null, true, true); + edge.cc.insertBefore(newEl, edge.ec); + } + + newEl.innerHTML = '
'; + util.copyFormatAttributes(newEl, formatEl); + util.removeItemAllParents(formatEl, null, null); + core.setRange(newEl, 1, newEl, 1); + break; + } + } + + if (rangeEl && util.getParentElement(rangeEl, 'FIGCAPTION') && util.getParentElement(rangeEl, util.isList)) { + e.preventDefault(); + formatEl = core.appendFormatTag(formatEl, null); + core.setRange(formatEl, 0, formatEl, 0); + } + + if (fileComponentName) { + e.preventDefault(); + e.stopPropagation(); + const compContext = context[fileComponentName]; + const container = compContext._container; + const sibling = container.previousElementSibling || container.nextElementSibling; + + let newEl = null; + if (util.isListCell(container.parentNode)) { + newEl = util.createElement('BR'); + } else { + newEl = util.createElement(util.isFormatElement(sibling) ? sibling.nodeName : options.defaultTag); + newEl.innerHTML = '
'; + } + + container.parentNode.insertBefore(newEl, container); + + core.callPlugin(fileComponentName, function () { + if (core.selectComponent(compContext._element, fileComponentName) === false) core.blur(); + }, null); + } + + break; + case 27: + if (fileComponentName) { + e.preventDefault(); + e.stopPropagation(); + core.controllersOff(); + return false; + } + break; + } + + if (shift && keyCode === 16) { + e.preventDefault(); + e.stopPropagation(); + const tablePlugin = core.plugins.table; + if (tablePlugin && !tablePlugin._shift && !tablePlugin._ref) { + const cell = util.getParentElement(formatEl, util.isCell); + if (cell) { + tablePlugin.onTableCellMultiSelect.call(core, cell, true); + return; + } + } + } else if (shift && (util.isOSX_IOS ? alt : ctrl) && keyCode === 32) { + e.preventDefault(); + e.stopPropagation(); + const nbsp = core.insertNode(util.createTextNode('\u00a0')); + if (nbsp && nbsp.container) { + core.setRange(nbsp.container, nbsp.endOffset, nbsp.container, nbsp.endOffset); + return; + } + } + + const textKey = !ctrl && !alt && !selectRange && !event._nonTextKeyCode.test(keyCode); + if (textKey && range.collapsed && range.startContainer === range.endContainer && util.isBreak(range.commonAncestorContainer)) { + const zeroWidth = util.createTextNode(util.zeroWidthSpace); + core.insertNode(zeroWidth, null, false); + core.setRange(zeroWidth, 1, zeroWidth, 1); + } + + if (typeof functions.onKeyDown === 'function') functions.onKeyDown(e, core); + }, + + onKeyUp_wysiwyg: function (e) { + if (event._onShortcutKey) return; + core._editorRange(); + + const range = core.getRange(); + const keyCode = e.keyCode; + const ctrl = e.ctrlKey || e.metaKey || keyCode === 91 || keyCode === 92 || keyCode === 224; + const alt = e.altKey; + let selectionNode = core.getSelectionNode(); + + if (core._isBalloon && ((core._isBalloonAlways && keyCode !== 27) || !range.collapsed)) { + if (core._isBalloonAlways) { + if (keyCode !== 27) event._showToolbarBalloonDelay(); + } else { + event._showToolbarBalloon(); + return; + } + } + + /** when format tag deleted */ + if (keyCode === 8 && util.isWysiwygDiv(selectionNode) && selectionNode.textContent === '' && selectionNode.children.length === 0) { + e.preventDefault(); + e.stopPropagation(); + + selectionNode.innerHTML = ''; + + const oFormatTag = util.createElement(util.isFormatElement(core._variable.currentNodes[0]) ? core._variable.currentNodes[0] : options.defaultTag); + oFormatTag.innerHTML = '
'; + + selectionNode.appendChild(oFormatTag); + core.setRange(oFormatTag, 0, oFormatTag, 0); + event._applyTagEffects(); + + core.history.push(false); + return; + } + + const formatEl = util.getFormatElement(selectionNode, null); + const rangeEl = util.getRangeFormatElement(selectionNode, null); + if (((!formatEl && range.collapsed) || formatEl === rangeEl) && !util.isComponent(selectionNode) && !util.isList(selectionNode)) { + core._setDefaultFormat(util.isRangeFormatElement(rangeEl) ? 'DIV' : options.defaultTag); + selectionNode = core.getSelectionNode(); + } + + if (event._directionKeyCode.test(keyCode)) { + event._applyTagEffects(); + } + + const textKey = !ctrl && !alt && !event._nonTextKeyCode.test(keyCode); + if (textKey && selectionNode.nodeType === 3 && util.zeroWidthRegExp.test(selectionNode.textContent) && !(e.isComposing !== undefined ? e.isComposing : event._IEisComposing)) { + let so = range.startOffset, eo = range.endOffset; + const frontZeroWidthCnt = (selectionNode.textContent.substring(0, eo).match(event._frontZeroWidthReg) || '').length; + so = range.startOffset - frontZeroWidthCnt; + eo = range.endOffset - frontZeroWidthCnt; + selectionNode.textContent = selectionNode.textContent.replace(util.zeroWidthRegExp, ''); + core.setRange(selectionNode, so < 0 ? 0 : so, selectionNode, eo < 0 ? 0 : eo); + } + + core._charCount(''); + + // history stack + core.history.push(true); + + if (typeof functions.onKeyUp === 'function') functions.onKeyUp(e, core); + }, + + onScroll_wysiwyg: function (e) { + core.controllersOff(); + if (core._isBalloon) event._hideToolbar(); + if (typeof functions.onScroll === 'function') functions.onScroll(e, core); + }, + + onFocus_wysiwyg: function (e) { + if (core._antiBlur) return; + core.hasFocus = true; + if (core._isInline) event._showToolbarInline(); + if (typeof functions.onFocus === 'function') functions.onFocus(e, core); + }, + + onBlur_wysiwyg: function (e) { + if (core._antiBlur || core._variable.isCodeView) return; + core.hasFocus = false; + core.controllersOff(); + if (core._isInline || core._isBalloon) event._hideToolbar(); + if (typeof functions.onBlur === 'function') functions.onBlur(e, core); + + // active class reset of buttons + const commandMap = core.commandMap; + const activePlugins = core.activePlugins; + for (let key in commandMap) { + if (!util.hasOwn(commandMap, key)) continue; + if (activePlugins.indexOf(key) > -1) { + plugins[key].active.call(core, null); + } else if (commandMap.OUTDENT && /^OUTDENT$/i.test(key)) { + commandMap.OUTDENT.setAttribute('disabled', true); + } else if (commandMap.INDENT && /^INDENT$/i.test(key)) { + commandMap.INDENT.removeAttribute('disabled'); + } else { + util.removeClass(commandMap[key], 'active'); + } + } + + core._variable.currentNodes = []; + core._variable.currentNodesMap = []; + if (options.showPathLabel) context.element.navigation.textContent = ''; + }, + + onMouseDown_resizingBar: function (e) { + e.stopPropagation(); + + core.submenuOff(); + core.controllersOff(); + + core._variable.resizeClientY = e.clientY; + context.element.resizeBackground.style.display = 'block'; + + function closureFunc() { + context.element.resizeBackground.style.display = 'none'; + _d.removeEventListener('mousemove', event._resize_editor); + _d.removeEventListener('mouseup', closureFunc); + } + + _d.addEventListener('mousemove', event._resize_editor); + _d.addEventListener('mouseup', closureFunc); + }, + + _resize_editor: function (e) { + const resizeInterval = context.element.editorArea.offsetHeight + (e.clientY - core._variable.resizeClientY); + context.element.wysiwygFrame.style.height = context.element.code.style.height = (resizeInterval < core._variable.minResizingSize ? core._variable.minResizingSize : resizeInterval) + 'px'; + core._variable.resizeClientY = e.clientY; + }, + + onResize_window: function () { + core.controllersOff(); + + const responsiveSize = event._responsiveButtonSize; + if (responsiveSize) { + let w = 0; + if ((core._isBalloon || core._isInline) && options.toolbarWidth === 'auto') { + w = context.element.topArea.offsetWidth; + } else { + w = context.element.toolbar.offsetWidth; + } + + let responsiveWidth = 'default'; + for (let i = 1, len = responsiveSize.length; i < len; i++) { + if (w < responsiveSize[i]) { + responsiveWidth = responsiveSize[i] + ''; + break; + } + } + + if (event._responsiveCurrentSize !== responsiveWidth) { + event._responsiveCurrentSize = responsiveWidth; + functions.setToolbarButtons(event._responsiveButtons[responsiveWidth]); + } + } + + if (context.element.toolbar.offsetWidth === 0) return; + + if (context.fileBrowser && context.fileBrowser.area.style.display === 'block') { + context.fileBrowser.body.style.maxHeight = (_w.innerHeight - context.fileBrowser.header.offsetHeight - 50) + 'px'; + } + + if (core.submenuActiveButton && core.submenu) { + core._setMenuPosition(core.submenuActiveButton, core.submenu); + } + + if (core._variable.isFullScreen) { + core._variable.innerHeight_fullScreen += (_w.innerHeight - context.element.toolbar.offsetHeight) - core._variable.innerHeight_fullScreen; + context.element.editorArea.style.height = core._variable.innerHeight_fullScreen + 'px'; + return; + } + + if (core._variable.isCodeView && core._isInline) { + event._showToolbarInline(); + return; + } + + core._iframeAutoHeight(); + + if (core._sticky) { + context.element.toolbar.style.width = (context.element.topArea.offsetWidth - 2) + 'px'; + event.onScroll_window(); + } + }, + + onScroll_window: function () { + if (core._variable.isFullScreen || context.element.toolbar.offsetWidth === 0 || options.stickyToolbar < 0) return; + + const element = context.element; + const editorHeight = element.editorArea.offsetHeight; + const y = (this.scrollY || _d.documentElement.scrollTop) + options.stickyToolbar; + const editorTop = event._getEditorOffsets(options.toolbarContainer).top - (core._isInline ? element.toolbar.offsetHeight : 0); + + if (y < editorTop) { + event._offStickyToolbar(); + } + else if (y + core._variable.minResizingSize >= editorHeight + editorTop) { + if (!core._sticky) event._onStickyToolbar(); + element.toolbar.style.top = (editorHeight + editorTop + options.stickyToolbar -y - core._variable.minResizingSize) + 'px'; + } + else if (y >= editorTop) { + event._onStickyToolbar(); + } + }, + + _getEditorOffsets: function (container) { + let offsetEl = container || context.element.topArea; + let t = 0, l = 0, s = 0; + + while (offsetEl) { + t += offsetEl.offsetTop; + l += offsetEl.offsetLeft; + s += offsetEl.scrollTop; + offsetEl = offsetEl.offsetParent; + } + + return { + top: t, + left: l, + scroll: s + }; + }, + + _getPageBottomSpace: function () { + return _d.documentElement.scrollHeight - (event._getEditorOffsets(null).top + context.element.topArea.offsetHeight); + }, + + _onStickyToolbar: function () { + const element = context.element; + + if (!core._isInline && !options.toolbarContainer) { + element._stickyDummy.style.height = element.toolbar.offsetHeight + 'px'; + element._stickyDummy.style.display = 'block'; + } + + element.toolbar.style.top = options.stickyToolbar + 'px'; + element.toolbar.style.width = core._isInline ? core._inlineToolbarAttr.width : element.toolbar.offsetWidth + 'px'; + util.addClass(element.toolbar, 'se-toolbar-sticky'); + core._sticky = true; + }, + + _offStickyToolbar: function () { + const element = context.element; + + element._stickyDummy.style.display = 'none'; + element.toolbar.style.top = core._isInline ? core._inlineToolbarAttr.top : ''; + element.toolbar.style.width = core._isInline ? core._inlineToolbarAttr.width : ''; + element.editorArea.style.marginTop = ''; + + util.removeClass(element.toolbar, 'se-toolbar-sticky'); + core._sticky = false; + }, + + _codeViewAutoHeight: function () { + context.element.code.style.height = context.element.code.scrollHeight + 'px'; + }, + + // FireFox - table delete, Chrome - image, video, audio + _hardDelete: function () { + const range = core.getRange(); + const sc = range.startContainer; + const ec = range.endContainer; + + // table + const sCell = util.getRangeFormatElement(sc); + const eCell = util.getRangeFormatElement(ec); + const sIsCell = util.isCell(sCell); + const eIsCell = util.isCell(eCell); + if (((sIsCell && !sCell.previousElementSibling && !sCell.parentElement.previousElementSibling) || (eIsCell && !eCell.nextElementSibling && !eCell.parentElement.nextElementSibling)) && sCell !== eCell) { + if (!sIsCell) { + util.removeItem(util.getParentElement(eCell, util.isComponent)); + } else if (!eIsCell) { + util.removeItem(util.getParentElement(sCell, util.isComponent)); + } else { + util.removeItem(util.getParentElement(sCell, util.isComponent)); + core.nativeFocus(); + return true; + } + } + + // component + const sComp = sc.nodeType === 1 ? util.getParentElement(sc, '.se-component') : null; + const eComp = ec.nodeType === 1 ? util.getParentElement(ec, '.se-component') : null; + if (sComp) util.removeItem(sComp); + if (eComp) util.removeItem(eComp); + + return false; + }, + + onPaste_wysiwyg: function (e) { + const clipboardData = util.isIE ? _w.clipboardData : e.clipboardData; + if (!clipboardData) return true; + return event._dataTransferAction('paste', e, clipboardData); + }, + + _setClipboardComponent: function (e, info, clipboardData) { + e.preventDefault(); + e.stopPropagation(); + clipboardData.setData('text/html', info.component.outerHTML); + }, + + onCopy_wysiwyg: function (e) { + const clipboardData = util.isIE ? _w.clipboardData : e.clipboardData; + if (typeof functions.onCopy === 'function' && !functions.onCopy(e, clipboardData, core)) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + + const info = core.currentFileComponentInfo; + if (info && !util.isIE) { + event._setClipboardComponent(e, info, clipboardData); + util.addClass(info.component, 'se-component-copy'); + // copy effect + _w.setTimeout(function () { + util.removeClass(info.component, 'se-component-copy'); + }, 150); + } + }, + + onCut_wysiwyg: function (e) { + const clipboardData = util.isIE ? _w.clipboardData : e.clipboardData; + if (typeof functions.onCut === 'function' && !functions.onCut(e, clipboardData, core)) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + + const info = core.currentFileComponentInfo; + if (info && !util.isIE) { + event._setClipboardComponent(e, info, clipboardData); + util.removeItem(info.component); + core.controllersOff(); + } + + _w.setTimeout(function () { + // history stack + core.history.push(false); + }); + }, + + onDrop_wysiwyg: function (e) { + const dataTransfer = e.dataTransfer; + if (!dataTransfer) return true; + if (util.isIE) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + + core.removeNode(); + event._setDropLocationSelection(e); + return event._dataTransferAction('drop', e, dataTransfer); + }, + + _setDropLocationSelection: function (e) { + if (e.rangeParent) { + core.setRange(e.rangeParent, e.rangeOffset, e.rangeParent, e.rangeOffset); + } else if (core._wd.caretRangeFromPoint) { + const r = core._wd.caretRangeFromPoint(e.clientX, e.clientY); + core.setRange(r.startContainer, r.startOffset, r.endContainer, r.endOffset); + } else { + const r = core.getRange(); + core.setRange(r.startContainer, r.startOffset, r.endContainer, r.endOffset); + } + }, + + _dataTransferAction: function (type, e, data) { + let plainText, cleanData; + if (util.isIE) { + plainText = data.getData('Text'); + + const range = core.getRange(); + const tempDiv = util.createElement('DIV'); + const tempRange = { + sc: range.startContainer, + so: range.startOffset, + ec: range.endContainer, + eo: range.endOffset + }; + + tempDiv.setAttribute('contenteditable', true); + tempDiv.style.cssText = 'position:absolute; top:0; left:0; width:1px; height:1px; overflow:hidden;'; + + context.element.relative.appendChild(tempDiv); + tempDiv.focus(); + + _w.setTimeout(function () { + cleanData = tempDiv.innerHTML; + util.removeItem(tempDiv); + core.setRange(tempRange.sc, tempRange.so, tempRange.ec, tempRange.eo); + event._setClipboardData(type, e, plainText, cleanData, data); + }); + + return true; + } else { + plainText = data.getData('text/plain'); + cleanData = data.getData('text/html') || plainText; + if (event._setClipboardData(type, e, plainText, cleanData, data) === false) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + }, + + _setClipboardData: function (type, e, plainText, cleanData, data) { + // MS word, OneNode, Excel + const MSData = /class=["']*Mso(Normal|List)/i.test(cleanData) || /content=["']*Word.Document/i.test(cleanData) || /content=["']*OneNote.File/i.test(cleanData) || /content=["']*Excel.Sheet/i.test(cleanData); + if (MSData) { + cleanData = cleanData.replace(/\n/g, ' '); + plainText = plainText.replace(/\n/g, ' '); + } else { + plainText = plainText.replace(/\n/g, ''); + } + + cleanData = core.cleanHTML(cleanData, core.pasteTagsWhitelistRegExp); + const maxCharCount = core._charCount(core._charTypeHTML ? cleanData : plainText); + + // paste event + if (type === 'paste' && typeof functions.onPaste === 'function') { + const value = functions.onPaste(e, cleanData, maxCharCount, core); + if (!value) return false; + if (typeof value === 'string') cleanData = value; + } + // drop event + if (type === 'drop' && typeof functions.onDrop === 'function') { + const value = functions.onDrop(e, cleanData, maxCharCount, core); + if (!value) return false; + if (typeof value === 'string') cleanData = value; + } + + // files + const files = data.files; + if (files.length > 0 && !MSData) { + if (/^image/.test(files[0].type) && core.plugins.image) { + functions.insertImage(files); + } + return false; + } + + if (!maxCharCount) { + return false; + } + + if (cleanData) { + functions.insertHTML(cleanData, true, false); + return false; + } + }, + + onMouseMove_wysiwyg: function (e) { + if (core.isDisabled) return; + const component = util.getParentElement(e.target, util.isComponent); + const lineBreakerStyle = core._lineBreaker.style; + + if (component && !core.currentControllerName) { + const ctxEl = context.element; + let scrollTop = 0; + let el = ctxEl.wysiwyg; + do { + scrollTop += el.scrollTop; + el = el.parentElement; + } while (el && !/^(BODY|HTML)$/i.test(el.nodeName)); + + const wScroll = ctxEl.wysiwyg.scrollTop; + const offsets = event._getEditorOffsets(null); + const componentTop = util.getOffset(component, ctxEl.wysiwygFrame).top + wScroll; + const y = e.pageY + scrollTop + (options.iframe && !options.toolbarContainer ? ctxEl.toolbar.offsetHeight : 0); + const c = componentTop + (options.iframe ? scrollTop : offsets.top); + + const isList = util.isListCell(component.parentNode); + let dir = '', top = ''; + if ((isList ? !component.previousSibling : !util.isFormatElement(component.previousElementSibling)) && y < (c + 20)) { + top = componentTop; + dir = 't'; + } else if ((isList ? !component.nextSibling : !util.isFormatElement(component.nextElementSibling)) && y > (c + component.offsetHeight - 20)) { + top = componentTop + component.offsetHeight; + dir = 'b'; + } else { + lineBreakerStyle.display = 'none'; + return; + } + + core._variable._lineBreakComp = component; + core._variable._lineBreakDir = dir; + lineBreakerStyle.top = (top - wScroll) + 'px'; + core._lineBreakerButton.style.left = (util.getOffset(component).left + (component.offsetWidth / 2) - 15) + 'px'; + lineBreakerStyle.display = 'block'; + } // off line breaker + else if (lineBreakerStyle.display !== 'none') { + lineBreakerStyle.display = 'none'; + } + }, + + _onMouseDown_lineBreak: function (e) { + e.preventDefault(); + }, + + _onLineBreak: function (e) { + e.preventDefault(); + + const component = core._variable._lineBreakComp; + const dir = !this ? core._variable._lineBreakDir : this; + const isList = util.isListCell(component.parentNode); + + const format = util.createElement(isList ? 'BR' : util.isCell(component.parentNode) ? 'DIV' : options.defaultTag); + if (!isList) format.innerHTML = '
'; + + if (core._charTypeHTML && !core.checkCharCount(format.outerHTML, 'byte-html')) return; + + component.parentNode.insertBefore(format, dir === 't' ? component : component.nextSibling); + core._lineBreaker.style.display = 'none'; + core._variable._lineBreakComp = null; + + const focusEl = isList ? format : format.firstChild; + core.setRange(focusEl, 1, focusEl, 1); + // history stack + core.history.push(false); + }, + + _addEvent: function () { + const eventWysiwyg = options.iframe ? core._ww : context.element.wysiwyg; + + /** toolbar event */ + context.element.toolbar.addEventListener('mousedown', event._buttonsEventHandler, false); + context.element._menuTray.addEventListener('mousedown', event._buttonsEventHandler, false); + context.element.toolbar.addEventListener('click', event.onClick_toolbar, false); + /** editor area */ + eventWysiwyg.addEventListener('mousedown', event.onMouseDown_wysiwyg, false); + eventWysiwyg.addEventListener('click', event.onClick_wysiwyg, false); + eventWysiwyg.addEventListener(util.isIE ? 'textinput' : 'input', event.onInput_wysiwyg, false); + eventWysiwyg.addEventListener('keydown', event.onKeyDown_wysiwyg, false); + eventWysiwyg.addEventListener('keyup', event.onKeyUp_wysiwyg, false); + eventWysiwyg.addEventListener('paste', event.onPaste_wysiwyg, false); + eventWysiwyg.addEventListener('copy', event.onCopy_wysiwyg, false); + eventWysiwyg.addEventListener('cut', event.onCut_wysiwyg, false); + eventWysiwyg.addEventListener('drop', event.onDrop_wysiwyg, false); + eventWysiwyg.addEventListener('scroll', event.onScroll_wysiwyg, false); + eventWysiwyg.addEventListener('focus', event.onFocus_wysiwyg, false); + eventWysiwyg.addEventListener('blur', event.onBlur_wysiwyg, false); + + /** line breaker */ + event._lineBreakerBind = { a: event._onLineBreak.bind(''), t: event._onLineBreak.bind('t'), b: event._onLineBreak.bind('b') }; + eventWysiwyg.addEventListener('mousemove', event.onMouseMove_wysiwyg, false); + core._lineBreakerButton.addEventListener('mousedown', event._onMouseDown_lineBreak, false); + core._lineBreakerButton.addEventListener('click', event._lineBreakerBind.a, false); + context.element.lineBreaker_t.addEventListener('mousedown', event._lineBreakerBind.t, false); + context.element.lineBreaker_b.addEventListener('mousedown', event._lineBreakerBind.b, false); + + /** Events are registered only when there is a table plugin. */ + if (core.plugins.table) { + eventWysiwyg.addEventListener('touchstart', event.onMouseDown_wysiwyg, {passive: true, useCapture: false}); + } + + /** code view area auto line */ + if (options.height === 'auto' && !options.codeMirrorEditor) { + context.element.code.addEventListener('keydown', event._codeViewAutoHeight, false); + context.element.code.addEventListener('keyup', event._codeViewAutoHeight, false); + context.element.code.addEventListener('paste', event._codeViewAutoHeight, false); + } + + /** resizingBar */ + if (context.element.resizingBar) { + if (/\d+/.test(options.height)) { + context.element.resizingBar.addEventListener('mousedown', event.onMouseDown_resizingBar, false); + } else { + util.addClass(context.element.resizingBar, 'se-resizing-none'); + } + } + + /** window event */ + event._setResponsiveToolbar(); + _w.removeEventListener('resize', event.onResize_window); + _w.removeEventListener('scroll', event.onScroll_window); + + _w.addEventListener('resize', event.onResize_window, false); + if (options.stickyToolbar > -1) { + _w.addEventListener('scroll', event.onScroll_window, false); + } + }, + + _removeEvent: function () { + const eventWysiwyg = options.iframe ? core._ww : context.element.wysiwyg; + + context.element.toolbar.removeEventListener('mousedown', event._buttonsEventHandler); + context.element._menuTray.removeEventListener('mousedown', event._buttonsEventHandler); + context.element.toolbar.removeEventListener('click', event.onClick_toolbar); + + eventWysiwyg.removeEventListener('mousedown', event.onMouseDown_wysiwyg); + eventWysiwyg.removeEventListener('click', event.onClick_wysiwyg); + eventWysiwyg.removeEventListener(util.isIE ? 'textinput' : 'input', event.onInput_wysiwyg); + eventWysiwyg.removeEventListener('keydown', event.onKeyDown_wysiwyg); + eventWysiwyg.removeEventListener('keyup', event.onKeyUp_wysiwyg); + eventWysiwyg.removeEventListener('paste', event.onPaste_wysiwyg); + eventWysiwyg.removeEventListener('copy', event.onCopy_wysiwyg); + eventWysiwyg.removeEventListener('cut', event.onCut_wysiwyg); + eventWysiwyg.removeEventListener('drop', event.onDrop_wysiwyg); + eventWysiwyg.removeEventListener('scroll', event.onScroll_wysiwyg); + + eventWysiwyg.removeEventListener('mousemove', event.onMouseMove_wysiwyg); + core._lineBreakerButton.removeEventListener('mousedown', event._onMouseDown_lineBreak); + core._lineBreakerButton.removeEventListener('click', event._lineBreakerBind.a); + context.element.lineBreaker_t.removeEventListener('mousedown', event._lineBreakerBind.t); + context.element.lineBreaker_b.removeEventListener('mousedown', event._lineBreakerBind.b); + event._lineBreakerBind = null; + + eventWysiwyg.removeEventListener('touchstart', event.onMouseDown_wysiwyg, {passive: true, useCapture: false}); + + eventWysiwyg.removeEventListener('focus', event.onFocus_wysiwyg); + eventWysiwyg.removeEventListener('blur', event.onBlur_wysiwyg); + + context.element.code.removeEventListener('keydown', event._codeViewAutoHeight); + context.element.code.removeEventListener('keyup', event._codeViewAutoHeight); + context.element.code.removeEventListener('paste', event._codeViewAutoHeight); + + if (context.element.resizingBar) { + context.element.resizingBar.removeEventListener('mousedown', event.onMouseDown_resizingBar); + } + + _w.removeEventListener('resize', event.onResize_window); + _w.removeEventListener('scroll', event.onScroll_window); + }, + + _setResponsiveToolbar: function () { + if (_responsiveButtons.length === 0) { + _responsiveButtons = null; + return; + } + + event._responsiveCurrentSize = 'default'; + const sizeArray = event._responsiveButtonSize = []; + const buttonsObj = event._responsiveButtons = {default: _responsiveButtons[0]}; + for (let i = 1, len = _responsiveButtons.length, size, buttonGroup; i < len; i++) { + buttonGroup = _responsiveButtons[i]; + size = buttonGroup[0] * 1; + sizeArray.push(size); + buttonsObj[size] = buttonGroup[1]; + } + + sizeArray.sort(function (a, b) { return a - b; }).unshift('default'); + } + }; + + /** functions */ + const functions = { + /** + * @description Core, Util object + */ + core: core, + util: util, + + /** + * @description Event functions + * @param {Object} e Event Object + * @param {Object} core Core object + */ + onload: null, + onScroll: null, + onMouseDown: null, + onClick: null, + onInput: null, + onKeyDown: null, + onKeyUp: null, + onCopy: null, + onCut: null, + onFocus: null, + onBlur: null, + + /** + * @description Event functions + * @param {String} contents Current contents + * @param {Object} core Core object + */ + onChange: null, + + /** + * @description Event functions (drop, paste) + * When false is returned, the default behavior is stopped. + * If the string is returned, the cleanData value is modified to the return value. + * @param {Object} e Event object. + * @param {String} cleanData HTML string modified for editor format. + * @param {Boolean} maxChartCount option (true if max character is exceeded) + * @param {Object} core Core object + * @returns {Boolean|String} + */ + onDrop: null, + onPaste: null, + + /** + * @description Called just before the inline toolbar is positioned and displayed on the screen. + * @param {Element} toolbar Toolbar Element + * @param {Object} context The editor's context object (editor.getContext()) + * @param {Object} core Core object + */ + showInline: null, + + /** + * @description Called just after the controller is positioned and displayed on the screen. + * controller - editing elements displayed on the screen [image resizing, table editor, link editor..]] + * @param {String} name The name of the plugin that called the controller + * @param {Array} controllers Array of Controller elements + * @param {Object} core Core object + */ + showController: null, + + /** + * @description An event when toggling between code view and wysiwyg view. + * @param {Boolean} isCodeView Whether the current code view mode + * @param {Object} core Core object + */ + toggleCodeView: null, + + /** + * @description An event when toggling full screen. + * @param {Boolean} isFullScreen Whether the current full screen mode + * @param {Object} core Core object + */ + toggleFullScreen: null, + + /** + * @description It replaces the default callback function of the image upload + * @param {Object} response Response object + * @param {Object} info Input information + * - linkValue: Link url value + * - linkNewWindow: Open in new window Check Value + * - inputWidth: Value of width input + * - inputHeight: Value of height input + * - align: Align Check Value + * - isUpdate: Update image if true, create image if false + * - element: If isUpdate is true, the currently selected image. + * @param {Object} core Core object + */ + imageUploadHandler: null, + + /** + * @description It replaces the default callback function of the video upload + * @param xmlHttp xmlHttpRequest object + * @param info Input information + * - inputWidth: Value of width input + * - inputHeight: Value of height input + * - align: Align Check Value + * - isUpdate: Update video if true, create video if false + * - element: If isUpdate is true, the currently selected video. + * @param core Core object + */ + videoUploadHandler: null, + + /** + * @description It replaces the default callback function of the audio upload + * @param xmlHttp xmlHttpRequest object + * @param info Input information + * - isUpdate: Update audio if true, create audio if false + * - element: If isUpdate is true, the currently selected audio. + * @param core Core object + */ + audioUploadHandler: null, + + /** + * @description Called before the image is uploaded + * If true is returned, the internal upload process runs normally. + * If false is returned, no image upload is performed. + * If new fileList are returned, replaced the previous fileList + * If undefined is returned, it waits until "uploadHandler" is executed. + * @param {Array} files Files array + * @param {Object} info info: { + * - linkValue: Link url value + * - linkNewWindow: Open in new window Check Value + * - inputWidth: Value of width input + * - inputHeight: Value of height input + * - align: Align Check Value + * - isUpdate: Update image if true, create image if false + * - element: If isUpdate is true, the currently selected image. + * } + * @param {Object} core Core object + * @param {Function} uploadHandler If undefined is returned, it waits until "uploadHandler" is executed. + * "uploadHandler" is an upload function with "core" and "info" bound. + * [upload files] : uploadHandler(files or [new File(...),]) + * [error] : uploadHandler("Error message") + * [Just finish] : uploadHandler() + * [directly register] : uploadHandler(response) // Same format as "imageUploadUrl" response + * ex) { + * // "errorMessage": "insert error message", + * "result": [ { "url": "...", "name": "...", "size": "999" }, ] + * } + * @returns {Boolean|Array|undefined} + */ + onImageUploadBefore: null, + /** + * @description Called before the video is uploaded + * If true is returned, the internal upload process runs normally. + * If false is returned, no video(iframe, video) upload is performed. + * If new fileList are returned, replaced the previous fileList + * If undefined is returned, it waits until "uploadHandler" is executed. + * @param {Array} files Files array + * @param {Object} info info: { + * - inputWidth: Value of width input + * - inputHeight: Value of height input + * - align: Align Check Value + * - isUpdate: Update video if true, create video if false + * - element: If isUpdate is true, the currently selected video. + * } + * @param {Object} core Core object + * @param {Function} uploadHandler If undefined is returned, it waits until "uploadHandler" is executed. + * "uploadHandler" is an upload function with "core" and "info" bound. + * [upload files] : uploadHandler(files or [new File(...),]) + * [error] : uploadHandler("Error message") + * [Just finish] : uploadHandler() + * [directly register] : uploadHandler(response) // Same format as "videoUploadUrl" response + * ex) { + * // "errorMessage": "insert error message", + * "result": [ { "url": "...", "name": "...", "size": "999" }, ] + * } + * @returns {Boolean|Array|undefined} + */ + onVideoUploadBefore: null, + /** + * @description Called before the audio is uploaded + * If true is returned, the internal upload process runs normally. + * If false is returned, no audio upload is performed. + * If new fileList are returned, replaced the previous fileList + * If undefined is returned, it waits until "uploadHandler" is executed. + * @param {Array} files Files array + * @param {Object} info info: { + * - isUpdate: Update audio if true, create audio if false + * - element: If isUpdate is true, the currently selected audio. + * } + * @param {Object} core Core object + * @param {Function} uploadHandler If undefined is returned, it waits until "uploadHandler" is executed. + * "uploadHandler" is an upload function with "core" and "info" bound. + * [upload files] : uploadHandler(files or [new File(...),]) + * [error] : uploadHandler("Error message") + * [Just finish] : uploadHandler() + * [directly register] : uploadHandler(response) // Same format as "audioUploadUrl" response + * ex) { + * // "errorMessage": "insert error message", + * "result": [ { "url": "...", "name": "...", "size": "999" }, ] + * } + * @returns {Boolean|Array|undefined} + */ + onAudioUploadBefore: null, + + /** + * @description Called when the image is uploaded, updated, deleted + * @param {Element} targetElement Target element + * @param {Number} index Uploaded index + * @param {String} state Upload status ('create', 'update', 'delete') + * @param {Object} info Image info object + * - index: data index + * - name: file name + * - size: file size + * - select: select function + * - delete: delete function + * - element: target element + * - src: src attribute of tag + * @param {Number} remainingFilesCount Count of remaining files to upload (0 when added as a url) + * @param {Object} core Core object + */ + onImageUpload: null, + /** + * @description Called when the video(iframe, video) is is uploaded, updated, deleted + * -- arguments is same "onImageUpload" -- + */ + onVideoUpload: null, + /** + * @description Called when the audio is is uploaded, updated, deleted + * -- arguments is same "onImageUpload" -- + */ + onAudioUpload: null, + + /** + * @description Called when the image is upload failed + * @param {String} errorMessage Error message + * @param {Object} result Response Object + * @param {Object} core Core object + * @returns {Boolean} + */ + onImageUploadError: null, + /** + * @description Called when the video(iframe, video) upload failed + * -- arguments is same "onImageUploadError" -- + */ + onVideoUploadError: null, + /** + * @description Called when the audio upload failed + * -- arguments is same "onImageUploadError" -- + */ + onAudioUploadError: null, + + /** + * @description Reset the buttons on the toolbar. (Editor is not reloaded) + * You cannot set a new plugin for the button. + * @param {Array} buttonList Button list + */ + setToolbarButtons: function (buttonList) { + core.submenuOff(); + core.containerOff(); + + const newToolbar = _constructor__WEBPACK_IMPORTED_MODULE_0__["default"]._createToolBar(_d, buttonList, core.plugins, options); + _responsiveButtons = newToolbar.responsiveButtons; + core._moreLayerActiveButton = null; + event._setResponsiveToolbar(); + + context.element.toolbar.replaceChild(newToolbar._buttonTray, context.element._buttonTray); + const newContext = Object(_context__WEBPACK_IMPORTED_MODULE_1__["default"])(context.element.originElement, core._getConstructed(context.element), options); + + context.element = newContext.element; + context.tool = newContext.tool; + if (options.iframe) context.element.wysiwyg = core._wd.body; + core._cachingButtons(); + core.history._resetCachingButton(); + + core.activePlugins = []; + const oldCallButtons = pluginCallButtons; + pluginCallButtons = newToolbar.pluginCallButtons; + let plugin, button, oldButton; + for (let key in pluginCallButtons) { + if (!util.hasOwn(pluginCallButtons, key)) continue; + plugin = plugins[key]; + button = pluginCallButtons[key]; + if (plugin.active && button) { + oldButton = oldCallButtons[key]; + core.callPlugin(key, null, oldButton || button); + if (oldButton) { + button.parentElement.replaceChild(oldButton, button); + pluginCallButtons[key] = oldButton; + } + } + } + + if (core.hasFocus) event._applyTagEffects(); + + if (core._variable.isCodeView) util.addClass(core._styleCommandMap.codeView, 'active'); + if (core._variable.isFullScreen) util.addClass(core._styleCommandMap.fullScreen, 'active'); + if (util.hasClass(context.element.wysiwyg, 'se-show-block')) util.addClass(core._styleCommandMap.showBlocks, 'active'); + }, + + /** + * @description Add or reset option property (Editor is reloaded) + * @param {Object} _options Options + */ + setOptions: function (_options) { + event._removeEvent(); + core._resetComponents(); + + util.removeClass(core._styleCommandMap.showBlocks, 'active'); + util.removeClass(core._styleCommandMap.codeView, 'active'); + core._variable.isCodeView = false; + core._iframeAuto = null; + + core.plugins = _options.plugins || core.plugins; + const mergeOptions = [options, _options].reduce(function (init, option) { + for (let key in option) { + if (!util.hasOwn(option, key)) continue; + if (key === 'plugins' && option[key] && init[key]) { + let i = init[key], o = option[key]; + i = i.length ? i : _w.Object.keys(i).map(function(name) { return i[name]; }); + o = o.length ? o : _w.Object.keys(o).map(function(name) { return o[name]; }); + init[key] = (o.filter(function(val) { return i.indexOf(val) === -1; })).concat(i); + } else { + init[key] = option[key]; + } + } + return init; + }, {}); + + const el = context.element; + const _initHTML = el.wysiwyg.innerHTML; + + // set option + const cons = _constructor__WEBPACK_IMPORTED_MODULE_0__["default"]._setOptions(mergeOptions, context, options); + + if (cons.callButtons) { + pluginCallButtons = cons.callButtons; + core.initPlugins = {}; + } + + if (cons.plugins) { + core.plugins = plugins = cons.plugins; + } + + // reset context + if (el._menuTray.children.length === 0) this._menuTray = {}; + _responsiveButtons = cons.toolbar.responsiveButtons; + core.options = options = mergeOptions; + core.lang = lang = options.lang; + + if (options.iframe) { + el.wysiwygFrame.addEventListener('load', function () { + util._setIframeDocument(this, options); + core._setOptionsInit(el, _initHTML); + }); + } + + el.editorArea.appendChild(el.wysiwygFrame); + + if (!options.iframe) { + core._setOptionsInit(el, _initHTML); + } + }, + + /** + * @description Set "options.defaultStyle" style. + * Define the style of the edit area + * It can also be defined with the "setOptions" method, but the "setDefaultStyle" method does not render the editor again. + * @param {String} style Style string + */ + setDefaultStyle: function (style) { + const newStyles = options._editorStyles = util._setDefaultOptionStyle(options, style); + const el = context.element; + + // top area + el.topArea.style.cssText = newStyles.top; + // code view + el.code.style.cssText = options._editorStyles.frame; + el.code.style.display = 'none'; + if (options.height === 'auto') { + el.code.style.overflow = 'hidden'; + } else { + el.code.style.overflow = ''; + } + // wysiwyg frame + if (!options.iframe) { + el.wysiwygFrame.style.cssText = newStyles.frame + newStyles.editor; + } else { + el.wysiwygFrame.style.cssText = newStyles.frame; + el.wysiwyg.style.cssText = newStyles.editor; + } + }, + + /** + * @description Open a notice area + * @param {String} message Notice message + */ + noticeOpen: function (message) { + core.notice.open.call(core, message); + }, + + /** + * @description Close a notice area + */ + noticeClose: function () { + core.notice.close.call(core); + }, + + /** + * @description Copying the contents of the editor to the original textarea + */ + save: function () { + context.element.originElement.value = core.getContents(false); + }, + + /** + * @description Gets the suneditor's context object. Contains settings, plugins, and cached element objects + * @returns {Object} + */ + getContext: function () { + return context; + }, + + /** + * @description Gets the contents of the suneditor + * @param {Boolean} onlyContents - Return only the contents of the body without headers when the "fullPage" option is true + * @returns {String} + */ + getContents: function (onlyContents) { + return core.getContents(onlyContents); + }, + + /** + * @description Gets only the text of the suneditor contents + * @returns {String} + */ + getText: function () { + return context.element.wysiwyg.textContent; + }, + + /** + * @description Get the editor's number of characters or binary data size. + * You can use the "charCounterType" option format. + * @param {String|null} charCounterType options - charCounterType ('char', 'byte', 'byte-html') + * If argument is no value, the currently set "charCounterType" option is used. + * @returns {Number} + */ + getCharCount: function (charCounterType) { + charCounterType = typeof charCounterType === 'string' ? charCounterType : options.charCounterType; + return core.getCharLength((core._charTypeHTML ? context.element.wysiwyg.innerHTML : context.element.wysiwyg.textContent), charCounterType); + }, + + /** + * @description Gets uploaded images informations + * - index: data index + * - name: file name + * - size: file size + * - select: select function + * - delete: delete function + * - element: target element + * - src: src attribute of tag + * @returns {Array} + */ + getImagesInfo: function () { + return context.image ? context.image._infoList : []; + }, + + /** + * @description Gets uploaded files(plugin using fileManager) information list. + * image: [img], video: [video, iframe], audio: [audio] + * When the argument value is 'image', it is the same function as "getImagesInfo". + * - index: data index + * - name: file name + * - size: file size + * - select: select function + * - delete: delete function + * - element: target element + * - src: src attribute of tag + * @param {String} pluginName Plugin name (image, video, audio) + * @returns {Array} + */ + getFilesInfo: function (pluginName) { + return context[pluginName] ? context[pluginName]._infoList : []; + }, + + /** + * @description Upload images using image plugin + * @param {FileList} files FileList + */ + insertImage: function (files) { + if (!core.plugins.image || !files) return; + + if (!core.initPlugins.image) core.callPlugin('image', core.plugins.image.submitAction.bind(core, files), null); + else core.plugins.image.submitAction.call(core, files); + core.focus(); + }, + + /** + * @description Inserts an HTML element or HTML string or plain string at the current cursor position + * @param {Element|String} html HTML Element or HTML string or plain string + * @param {Boolean} notCleaningData If true, inserts the HTML string without refining it with core.cleanHTML. + * @param {Boolean} checkCharCount If true, if "options.maxCharCount" is exceeded when "element" is added, null is returned without addition. + * @param {Boolean} rangeSelection If true, range select the inserted node. + */ + insertHTML: function (html, notCleaningData, checkCharCount, rangeSelection) { + if (typeof html === 'string') { + if (!notCleaningData) html = core.cleanHTML(html, null); + try { + const dom = _d.createRange().createContextualFragment(html); + const domTree = dom.childNodes; + + if (checkCharCount) { + const type = core._charTypeHTML ? 'outerHTML' : 'textContent'; + let checkHTML = ''; + for (let i = 0, len = domTree.length; i < len; i++) { + checkHTML += domTree[i][type]; + } + if (!core.checkCharCount(checkHTML, null)) return; + } + + let c, a, t, firstCon; + while ((c = domTree[0])) { + t = core.insertNode(c, a, false); + a = t.container || t; + if (!firstCon) firstCon = t; + } + + const offset = a.nodeType === 3 ? (t.endOffset || a.textContent.length): a.childNodes.length; + if (rangeSelection) core.setRange(firstCon.container || firstCon, firstCon.startOffset || 0, a, offset); + else core.setRange(a, offset, a, offset); + } catch (error) { + core.execCommand('insertHTML', false, html); + } + } else { + if (util.isComponent(html)) { + core.insertComponent(html, false, checkCharCount, false); + } else { + let afterNode = null; + if (util.isFormatElement(html) || util.isMedia(html)) { + afterNode = util.getFormatElement(core.getSelectionNode(), null); + } + core.insertNode(html, afterNode, checkCharCount); + } + } + + core.effectNode = null; + core.focus(); + + // history stack + core.history.push(false); + }, + + /** + * @description Change the contents of the suneditor + * @param {String|undefined} contents Contents to Input + */ + setContents: function (contents) { + core.setContents(contents); + }, + + /** + * @description Add contents to the suneditor + * @param {String} contents Contents to Input + */ + appendContents: function (contents) { + const convertValue = core.convertContentsForEditor(contents); + + if (!core._variable.isCodeView) { + const temp = util.createElement('DIV'); + temp.innerHTML = convertValue; + + const wysiwyg = context.element.wysiwyg; + const children = temp.children; + for (let i = 0, len = children.length; i < len; i++) { + wysiwyg.appendChild(children[i]); + } + } else { + core._setCodeView(core._getCodeView() + '\n' + core.convertHTMLForCodeView(convertValue)); + } + + // history stack + core.history.push(false); + }, + + /** + * @description Disable the suneditor + */ + disabled: function () { + context.tool.cover.style.display = 'block'; + context.element.wysiwyg.setAttribute('contenteditable', false); + core.isDisabled = true; + + if (options.codeMirrorEditor) { + options.codeMirrorEditor.setOption('readOnly', true); + } else { + context.element.code.setAttribute('disabled', 'disabled'); + } + }, + + /** + * @description Enable the suneditor + */ + enabled: function () { + context.tool.cover.style.display = 'none'; + context.element.wysiwyg.setAttribute('contenteditable', true); + core.isDisabled = false; + + if (options.codeMirrorEditor) { + options.codeMirrorEditor.setOption('readOnly', false); + } else { + context.element.code.removeAttribute('disabled'); + } + }, + + /** + * @description Show the suneditor + */ + show: function () { + const topAreaStyle = context.element.topArea.style; + if (topAreaStyle.display === 'none') topAreaStyle.display = options.display; + }, + + /** + * @description Hide the suneditor + */ + hide: function () { + context.element.topArea.style.display = 'none'; + }, + + /** + * @description Destroy the suneditor + */ + destroy: function () { + /** off menus */ + core.submenuOff(); + core.containerOff(); + core.controllersOff(); + if (core.notice) core.notice.close.call(core); + if (core.modalForm) core.plugins.dialog.close.call(core); + + /** remove history */ + core.history._destroy(); + + /** remove event listeners */ + event._removeEvent(); + + /** remove element */ + util.removeItem(context.element.toolbar); + util.removeItem(context.element.topArea); + + /** remove object reference */ + for (let k in core) { if (util.hasOwn(core, k)) delete core[k]; } + for (let k in event) { if (util.hasOwn(event, k)) delete event[k]; } + for (let k in context) { if (util.hasOwn(context, k)) delete context[k]; } + for (let k in pluginCallButtons) { if (util.hasOwn(pluginCallButtons, k)) delete pluginCallButtons[k]; } + + /** remove user object */ + for (let k in this) { if (util.hasOwn(this, k)) delete this[k]; } + }, + + /** + * @description Toolbar methods + */ + toolbar: { + /** + * @description Disable the toolbar + */ + disabled: function () { + context.tool.cover.style.display = 'block'; + }, + + /** + * @description Enable the toolbar + */ + enabled: function () { + context.tool.cover.style.display = 'none'; + }, + + /** + * @description Show the toolbar + */ + show: function () { + if (core._isInline) { + event._showToolbarInline(); + } else { + context.element.toolbar.style.display = ''; + context.element._stickyDummy.style.display = ''; + } + }, + + /** + * @description Hide the toolbar + */ + hide: function () { + if (core._isInline) { + event._hideToolbar(); + } else { + context.element.toolbar.style.display = 'none'; + context.element._stickyDummy.style.display = 'none'; + } + }, + } + }; + + /************ Core init ************/ + // functions + core.functions = functions; + core.options = options; + + // Create to sibling node + let contextEl = context.element; + let originEl = contextEl.originElement; + let topEl = contextEl.topArea; + originEl.style.display = 'none'; + topEl.style.display = 'block'; + + // init + if (options.iframe) { + contextEl.wysiwygFrame.addEventListener('load', function () { + util._setIframeDocument(this, options); + core._editorInit(false, options.value); + options.value = null; + }); + } + + // insert editor element + if (typeof originEl.nextElementSibling === 'object') { + originEl.parentNode.insertBefore(topEl, originEl.nextElementSibling); + } else { + originEl.parentNode.appendChild(topEl); + } + + contextEl.editorArea.appendChild(contextEl.wysiwygFrame); + contextEl = originEl = topEl = null; + + // init + if (!options.iframe) { + core._editorInit(false, options.value); + options.value = null; + } + + return functions; +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/lib/history.js": +/*!***************************************************!*\ + !*** ./node_modules/suneditor/src/lib/history.js ***! + \***************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2019 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = (function (core, change) { + const _w = core._w; + const util = core.util; + const delayTime = core.options.historyStackDelayTime; + let editor = core.context.element; + let undo = core.context.tool.undo; + let redo = core.context.tool.redo; + + let pushDelay = null; + let stackIndex = 0; + let stack = []; + + function setContentsFromStack () { + const item = stack[stackIndex]; + editor.wysiwyg.innerHTML = item.contents; + + core.setRange(util.getNodeFromPath(item.s.path, editor.wysiwyg), item.s.offset, util.getNodeFromPath(item.e.path, editor.wysiwyg), item.e.offset); + core.focus(); + + if (stackIndex === 0) { + if (undo) undo.setAttribute('disabled', true); + if (redo) redo.removeAttribute('disabled'); + } else if (stackIndex === stack.length - 1) { + if (undo) undo.removeAttribute('disabled'); + if (redo) redo.setAttribute('disabled', true); + } else { + if (undo) undo.removeAttribute('disabled'); + if (redo) redo.removeAttribute('disabled'); + } + + core.controllersOff(); + core._checkComponents(); + core._setCharCount(); + core._resourcesStateChange(); + + // onChange + change(); + } + + function pushStack () { + core._checkComponents(); + const current = core.getContents(true); + if (!current || (!!stack[stackIndex] && current === stack[stackIndex].contents)) return; + + stackIndex++; + const range = core._variable._range; + + if (stack.length > stackIndex) { + stack = stack.slice(0, stackIndex); + if (redo) redo.setAttribute('disabled', true); + } + + if (!range) { + stack[stackIndex] = { + contents: current, + s: { path: [0, 0], offset: [0, 0] }, + e: { path: 0, offset: 0 } + }; + } else { + stack[stackIndex] = { + contents: current, + s: { + path: util.getNodePath(range.startContainer, null, null), + offset: range.startOffset + }, + e: { + path: util.getNodePath(range.endContainer, null, null), + offset: range.endOffset + } + }; + } + + if (stackIndex === 1 && undo) undo.removeAttribute('disabled'); + + core._setCharCount(); + // onChange + change(); + } + + return { + /** + * @description History stack + */ + stack: stack, + + /** + * @description Saving the current status to the history object stack + * If "delay" is true, it will be saved after (options.historyStackDelayTime || 400) miliseconds + * If the function is called again with the "delay" argument true before it is saved, the delay time is renewal + * You can specify the delay time by sending a number. + * @param {Boolean|Number} delay If true, Add stack without delay time. + */ + push: function (delay) { + _w.setTimeout(core._resourcesStateChange.bind(core)); + const time = typeof delay === 'number' ? (delay > 0 ? delay : 0) : (!delay ? 0 : delayTime); + + if (!time || pushDelay) { + _w.clearTimeout(pushDelay); + if (!time) { + pushStack(); + return; + } + } + + pushDelay = _w.setTimeout(function () { + _w.clearTimeout(pushDelay); + pushDelay = null; + pushStack(); + }, time); + }, + + /** + * @description Undo function + */ + undo: function () { + if (stackIndex > 0) { + stackIndex--; + setContentsFromStack(); + } + }, + + /** + * @description Redo function + */ + redo: function () { + if (stack.length - 1 > stackIndex) { + stackIndex++; + setContentsFromStack(); + } + }, + + /** + * @description Go to the history stack for that index. + * If "index" is -1, go to the last stack + * @param {Number} index Stack index + */ + go: function (index) { + stackIndex = index < 0 ? (stack.length - 1) : index; + setContentsFromStack(); + }, + + /** + * @description Reset the history object + */ + reset: function (ignoreChangeEvent) { + if (undo) undo.setAttribute('disabled', true); + if (redo) redo.setAttribute('disabled', true); + core._variable.isChanged = false; + if (core.context.tool.save) core.context.tool.save.setAttribute('disabled', true); + + stack.splice(0); + stackIndex = 0; + + // pushStack + stack[stackIndex] = { + contents: core.getContents(true), + s: { + path: [0, 0], + offset: 0 + }, + e: { + path: [0, 0], + offset: 0 + } + }; + + if (!ignoreChangeEvent) change(); + }, + + /** + * @description Reset the disabled state of the buttons to fit the current stack. + * @private + */ + _resetCachingButton: function () { + editor = core.context.element; + undo = core.context.tool.undo; + redo = core.context.tool.redo; + + if (stackIndex === 0) { + if (undo) undo.setAttribute('disabled', true); + if (redo && stackIndex === stack.length - 1) redo.setAttribute('disabled', true); + core._variable.isChanged = false; + if (core.context.tool.save) core.context.tool.save.setAttribute('disabled', true); + } else if (stackIndex === stack.length - 1) { + if (redo) redo.setAttribute('disabled', true); + } + }, + + /** + * @description Remove all stacks and remove the timeout function. + * @private + */ + _destroy: function () { + if (pushDelay) _w.clearTimeout(pushDelay); + stack = null; + } + }; +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/lib/util.js": +/*!************************************************!*\ + !*** ./node_modules/suneditor/src/lib/util.js ***! + \************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/** + * @description utility function + */ +const util = { + _d: null, + _w: null, + isIE: null, + isIE_Edge: null, + isOSX_IOS: null, + _propertiesInit: function () { + if (this._d) return; + this._d = document; + this._w = window; + this.isIE = navigator.userAgent.indexOf('Trident') > -1; + this.isIE_Edge = (navigator.userAgent.indexOf('Trident') > -1) || (navigator.appVersion.indexOf('Edge') > -1); + this.isOSX_IOS = /(Mac|iPhone|iPod|iPad)/.test(navigator.platform); + }, + + /** + * @description HTML Reserved Word Converter. + * @param {String} contents + * @returns {String} HTML string + * @private + */ + _HTMLConvertor: function (contents) { + const ec = {'&': '&', '\u00A0': ' ', '\'': ''', '"': '"', '<': '<', '>': '>'}; + return contents.replace(/&|\u00A0|'|"|<|>/g, function (m) { + return (typeof ec[m] === 'string') ? ec[m] : m; + }); + }, + + /** + * @description Unicode Character 'ZERO WIDTH SPACE' (\u200B) + */ + zeroWidthSpace: String.fromCharCode(8203), + + /** + * @description Regular expression to find 'zero width space' (/\u200B/g) + */ + zeroWidthRegExp: new RegExp(String.fromCharCode(8203), 'g'), + + /** + * @description Regular expression to find only 'zero width space' (/^\u200B+$/) + */ + onlyZeroWidthRegExp: new RegExp('^' + String.fromCharCode(8203) + '+$'), + + /** + * @description A method that checks If the text is blank or to see if it contains 'ZERO WIDTH SPACE' or empty (util.zeroWidthSpace) + * @param {String|Node} text String value or Node + * @returns {Boolean} + */ + onlyZeroWidthSpace: function (text) { + if (typeof text !== 'string') text = text.textContent; + return text === '' || this.onlyZeroWidthRegExp.test(text); + }, + + /** + * @description Gets XMLHttpRequest object + * @returns {XMLHttpRequest|ActiveXObject} + */ + getXMLHttpRequest: function () { + /** IE */ + if (this._w.ActiveXObject) { + try { + return new ActiveXObject('Msxml2.XMLHTTP'); + } catch (e) { + try { + return new ActiveXObject('Microsoft.XMLHTTP'); + } catch (e1) { + return null; + } + } + } + /** netscape */ + else if (this._w.XMLHttpRequest) { + return new XMLHttpRequest(); + } + /** fail */ + else { + return null; + } + }, + + /** + * @description Create Element node + * @param {String} elementName Element name + * @returns {Element} + */ + createElement: function (elementName) { + return this._d.createElement(elementName); + }, + + /** + * @description Create text node + * @param {String} text text contents + * @returns {Node} + */ + createTextNode: function (text) { + return this._d.createTextNode(text || ''); + }, + + /** + * @description The editor checks tags by string. + * If there is "<" or ">" in the attribute of tag, HTML is broken when checking the tag. + * When using an attribute with "<" or ">", use "HTMLEncoder" to save. (ex: math(katex)) + * @param {String} contents HTML or Text string + * @returns {String} + */ + HTMLEncoder: function (contents) { + const ec = {'<': '$lt;', '>': '$gt;'}; + return contents.replace(/<|>/g, function (m) { + return (typeof ec[m] === 'string') ? ec[m] : m; + }); + }, + + /** + * @description The editor checks tags by string. + * If there is "<" or ">" in the attribute of tag, HTML is broken when checking the tag. + * Decoder of data stored as "HTMLEncoder" (ex: math(katex)) + * @param {String} contents HTML or Text string + * @returns {String} + */ + HTMLDecoder: function (contents) { + const ec = {'$lt;': '<', '$gt;': '>'}; + return contents.replace(/\$lt;|\$gt;/g, function (m) { + return (typeof ec[m] === 'string') ? ec[m] : m; + }); + }, + + /** + * @description This method run Object.prototype.hasOwnProperty.call(obj, key) + * @param {Object} obj Object + * @param {String} key obj.key + * @returns {Boolean} + */ + hasOwn: function (obj, key) { + return this._hasOwn.call(obj, key); + }, + _hasOwn: Object.prototype.hasOwnProperty, + + /** + * @deprecated + * @description Get the the tag path of the arguments value + * If not found, return the first found value + * @param {Array} nameArray File name array + * @param {String} extension js, css + * @returns {String} + */ + getIncludePath: function (nameArray, extension) { + let path = ''; + const pathList = []; + const tagName = extension === 'js' ? 'script' : 'link'; + const src = extension === 'js' ? 'src' : 'href'; + + let fileName = '(?:'; + for (let i = 0, len = nameArray.length; i < len; i++) { + fileName += nameArray[i] + (i < len - 1 ? '|' : ')'); + } + + const regExp = new this._w.RegExp('(^|.*[\\/])' + fileName + '(\\.[^\\/]+)?\.' + extension + '(?:\\?.*|;.*)?$', 'i'); + const extRegExp = new this._w.RegExp('.+\\.' + extension + '(?:\\?.*|;.*)?$', 'i'); + + for (let c = this._d.getElementsByTagName(tagName), i = 0; i < c.length; i++) { + if (extRegExp.test(c[i][src])) { + pathList.push(c[i]); + } + } + + for (let i = 0; i < pathList.length; i++) { + let editorTag = pathList[i][src].match(regExp); + if (editorTag) { + path = editorTag[0]; + break; + } + } + + if (path === '') path = pathList.length > 0 ? pathList[0][src] : ''; + + -1 === path.indexOf(':/') && '//' !== path.slice(0, 2) && (path = 0 === path.indexOf('/') ? location.href.match(/^.*?:\/\/[^\/]*/)[0] + path : location.href.match(/^[^\?]*\/(?:)/)[0] + path); + + if (!path) throw '[SUNEDITOR.util.getIncludePath.fail] The SUNEDITOR installation path could not be automatically detected. (name: +' + name + ', extension: ' + extension + ')'; + + return path; + }, + + /** + * @deprecated + * @description Returns the CSS text that has been applied to the current page. + * @param {Document|null} doc To get the CSS text of an document(core._wd). If null get the current document. + * @returns {String} Styles string + */ + getPageStyle: function (doc) { + let cssText = ''; + const sheets = (doc || this._d).styleSheets; + + for (let i = 0, len = sheets.length, rules; i < len; i++) { + try { + rules = sheets[i].cssRules; + } catch (e) { + continue; + } + + if (rules) { + for (let c = 0, cLen = rules.length; c < cLen; c++) { + cssText += rules[c].cssText; + } + } + } + + return cssText; + }, + + /** + * @description Get the argument iframe's document object + * @param {Element} iframe Iframe element (context.element.wysiwygFrame) + * @returns {Document} + */ + getIframeDocument: function (iframe) { + let wDocument = iframe.contentWindow || iframe.contentDocument; + if (wDocument.document) wDocument = wDocument.document; + return wDocument; + }, + + /** + * @description Get attributes of argument element to string ('class="---" name="---" ') + * @param {Element} element Element object + * @param {Array|null} exceptAttrs Array of attribute names to exclude from the result + * @returns {String} + */ + getAttributesToString: function (element, exceptAttrs) { + if (!element.attributes) return ''; + + const attrs = element.attributes; + let attrString = ''; + + for (let i = 0, len = attrs.length; i < len; i++) { + if (exceptAttrs && exceptAttrs.indexOf(attrs[i].name) > -1) continue; + attrString += attrs[i].name + '="' + attrs[i].value + '" '; + } + + return attrString; + }, + + /** + * @descriptionGets Get the length in bytes of a string. + * referencing code: "https://github.com/shaan1974/myrdin/blob/master/expressions/string.js#L11" + * @param {String} text String text + * @returns {Number} + */ + getByteLength: function(text) { + const encoder = this._w.encodeURIComponent; + let cr, cl; + if (this.isIE_Edge) { + cl = this._w.unescape(encoder(text.toString())).length; + cr = 0; + + if (encoder(text.toString()).match(/(%0A|%0D)/gi) !== null) { + cr = encoder(text.toString()).match(/(%0A|%0D)/gi).length; + } + + return cl + cr; + } else { + cl = (new this._w.TextEncoder('utf-8').encode(text.toString())).length; + cr = 0; + + if (encoder(text.toString()).match(/(%0A|%0D)/gi) !== null) { + cr = encoder(text.toString()).match(/(%0A|%0D)/gi).length; + } + + return cl + cr; + } + }, + + /** + * @description It is judged whether it is the edit region top div element or iframe's body tag. + * @param {Node} element The node to check + * @returns {Boolean} + */ + isWysiwygDiv: function (element) { + return element && element.nodeType === 1 && (this.hasClass(element, 'se-wrapper-wysiwyg') || /^BODY$/i.test(element.nodeName)); + }, + + /** + * @description It is judged whether it is the contenteditable property is false. + * @param {Node} element The node to check + * @returns {Boolean} + */ + isNonEditable: function (element) { + return element && element.nodeType === 1 && element.getAttribute('contenteditable') === 'false'; + }, + + /** + * @description It is judged whether it is a node related to the text style. + * (strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code) + * @param {Node} element The node to check + * @returns {Boolean} + */ + isTextStyleElement: function (element) { + return element && element.nodeType !== 3 && /^(strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code)$/i.test(element.nodeName); + }, + + /** + * @description It is judged whether it is the format element (P, DIV, H[1-6], PRE, LI | class="__se__format__replace_xxx") + * Format element also contain "free format Element" + * @param {Node} element The node to check + * @returns {Boolean} + */ + isFormatElement: function (element) { + return element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)|(\\s|^)__se__format__free_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element); + }, + + /** + * @description It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD | class="__se__format__range_xxx") + * Range format element is wrap the "format element" and "component" + * @param {Node} element The node to check + * @returns {Boolean} + */ + isRangeFormatElement: function (element) { + return element && element.nodeType === 1 && (/^(BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__range_.+(\\s|$)')); + }, + + /** + * @description It is judged whether it is the closure range format element. (TH, TD | class="__se__format__range__closure_xxx") + * Closure range format elements is included in the range format element. + * - Closure range format element is wrap the "format element" and "component" + * ※ You cannot exit this format with the Enter key or Backspace key. + * ※ Use it only in special cases. ([ex] format of table cells) + * @param {Node} element The node to check + * @returns {Boolean} + */ + isClosureRangeFormatElement: function (element) { + return element && element.nodeType === 1 && (/^(TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__range__closure_.+(\\s|$)')); + }, + + /** + * @description It is judged whether it is the free format element. (PRE | class="__se__format__free_xxx") + * Free format elements is included in the format element. + * Free format elements's line break is "BR" tag. + * ※ Entering the Enter key in the space on the last line ends "Free Format" and appends "Format". + * @param {Node} element The node to check + * @returns {Boolean} + */ + isFreeFormatElement: function (element) { + return element && element.nodeType === 1 && (/^PRE$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__free_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element); + }, + + /** + * @description It is judged whether it is the closure free format element. (class="__se__format__free__closure_xxx") + * Closure free format elements is included in the free format element. + * - Closure free format elements's line break is "BR" tag. + * ※ You cannot exit this format with the Enter key or Backspace key. + * ※ Use it only in special cases. ([ex] format of table cells) + * @param {Node} element The node to check + * @returns {Boolean} + */ + isClosureFreeFormatElement: function (element) { + return element && element.nodeType === 1 && this.hasClass(element, '(\\s|^)__se__format__free__closure_.+(\\s|$)'); + }, + + /** + * @description It is judged whether it is the component[img, iframe, video, audio, table] cover(class="se-component") and table, hr + * @param {Node} element The node to check + * @returns {Boolean} + */ + isComponent: function (element) { + return element && (/se-component/.test(element.className) || /^(TABLE|HR)$/.test(element.nodeName)); + }, + + /** + * @description Checks for "__se__uneditable" in the class list. + * Components with class "__se__uneditable" cannot be modified. + * @param {Element} element The element to check + * @returns {Boolean} + */ + isUneditableComponent: function (element) { + return element && this.hasClass(element, '__se__uneditable'); + }, + + /** + * @description It is judged whether it is the component [img, iframe] cover(class="se-component") + * @param {Node} element The node to check + * @returns {Boolean} + */ + isMediaComponent: function (element) { + return element && /se-component/.test(element.className); + }, + + /** + * @description It is judged whether it is the not checking node. (class="katex", "__se__tag") + * @param {Node} element The node to check + * @returns {Boolean} + */ + isNotCheckingNode: function (element) { + return element && /katex|__se__tag/.test(element.className); + }, + + /** + * @description If a parent node that contains an argument node finds a format node (util.isFormatElement), it returns that node. + * @param {Node} element Reference node. + * @param {Function|null} validation Additional validation function. + * @returns {Element|null} + */ + getFormatElement: function (element, validation) { + if (!element) return null; + if (!validation) { + validation = function () { return true; }; + } + + while (element) { + if (this.isWysiwygDiv(element)) return null; + if (this.isRangeFormatElement(element)) element.firstElementChild; + if (this.isFormatElement(element) && validation(element)) return element; + + element = element.parentNode; + } + + return null; + }, + + /** + * @description If a parent node that contains an argument node finds a format node (util.isRangeFormatElement), it returns that node. + * @param {Node} element Reference node. + * @param {Function|null} validation Additional validation function. + * @returns {Element|null} + */ + getRangeFormatElement: function (element, validation) { + if (!element) return null; + if (!validation) { + validation = function () { return true; }; + } + + while (element) { + if (this.isWysiwygDiv(element)) return null; + if (this.isRangeFormatElement(element) && !/^(THEAD|TBODY|TR)$/i.test(element.nodeName) && validation(element)) return element; + element = element.parentNode; + } + + return null; + }, + + /** + * @description If a parent node that contains an argument node finds a free format node (util.isFreeFormatElement), it returns that node. + * @param {Node} element Reference node. + * @param {Function|null} validation Additional validation function. + * @returns {Element|null} + */ + getFreeFormatElement: function (element, validation) { + if (!element) return null; + if (!validation) { + validation = function () { return true; }; + } + + while (element) { + if (this.isWysiwygDiv(element)) return null; + if (this.isFreeFormatElement(element) && validation(element)) return element; + + element = element.parentNode; + } + + return null; + }, + + /** + * @description If a parent node that contains an argument node finds a closure free format node (util.isClosureFreeFormatElement), it returns that node. + * @param {Node} element Reference node. + * @param {Function|null} validation Additional validation function. + * @returns {Element|null} + */ + getClosureFreeFormatElement: function (element, validation) { + if (!element) return null; + if (!validation) { + validation = function () { return true; }; + } + + while (element) { + if (this.isWysiwygDiv(element)) return null; + if (this.isClosureFreeFormatElement(element) && validation(element)) return element; + + element = element.parentNode; + } + + return null; + }, + + /** + * @description Add style and className of copyEl to originEl + * @param {Element} originEl Origin element + * @param {Element} copyEl Element to copy + */ + copyTagAttributes: function (originEl, copyEl) { + if (copyEl.style.cssText) { + originEl.style.cssText += copyEl.style.cssText; + } + + const classes = copyEl.classList; + for (let i = 0, len = classes.length; i < len; i++) { + this.addClass(originEl, classes[i]); + } + + if (!originEl.style.cssText) originEl.removeAttribute('style'); + if (!originEl.className.trim()) originEl.removeAttribute('class'); + }, + + /** + * @description Copy and apply attributes of format tag that should be maintained. (style, class) Ignore "__se__format__" class + * @param {Element} originEl Origin element + * @param {Element} copyEl Element to copy + */ + copyFormatAttributes: function (originEl, copyEl) { + copyEl = copyEl.cloneNode(false); + copyEl.className = copyEl.className.replace(/(\s|^)__se__format__[^\s]+/g, ''); + this.copyTagAttributes(originEl, copyEl); + }, + + /** + * @description Get the item from the array that matches the condition. + * @param {Array|HTMLCollection|NodeList} array Array to get item + * @param {Function|null} validation Conditional function + * @param {Boolean} multi If true, returns all items that meet the criteria otherwise, returns an empty array. + * If false, returns only one item that meet the criteria otherwise return null. + * @returns {Array|Node|null} + */ + getArrayItem: function (array, validation, multi) { + if (!array || array.length === 0) return null; + + validation = validation || function () { return true; }; + const arr = []; + + for (let i = 0, len = array.length, a; i < len; i++) { + a = array[i]; + if (validation(a)) { + if (!multi) return a; + else arr.push(a); + } + } + + return !multi ? null : arr; + }, + + /** + * @description Get the index of the argument value in the element array + * @param {Array|HTMLCollection|NodeList} array element array + * @param {Node} element The element to find index + * @returns {Number} + */ + getArrayIndex: function (array, element) { + let idx = -1; + for (let i = 0, len = array.length; i < len; i++) { + if (array[i] === element) { + idx = i; + break; + } + } + + return idx; + }, + + /** + * @description Get the next index of the argument value in the element array + * @param {Array|HTMLCollection|NodeList} array element array + * @param {Node} item The element to find index + * @returns {Number} + */ + nextIdx: function (array, item) { + let idx = this.getArrayIndex(array, item); + if (idx === -1) return -1; + return idx + 1; + }, + + /** + * @description Get the previous index of the argument value in the element array + * @param {Array|HTMLCollection|NodeList} array Element array + * @param {Node} item The element to find index + * @returns {Number} + */ + prevIdx: function (array, item) { + let idx = this.getArrayIndex(array, item); + if (idx === -1) return -1; + return idx - 1; + }, + + /** + * @description Returns the index compared to other sibling nodes. + * @param {Node} node The Node to find index + * @returns {Number} + */ + getPositionIndex: function (node) { + let idx = 0; + while ((node = node.previousSibling)) { + idx += 1; + } + return idx; + }, + + /** + * @description Returns the position of the "node" in the "parentNode" in a numerical array. + * ex)

aabb

: getNodePath(node: "bb", parentNode: "

") -> [1, 0] + * @param {Node} node The Node to find position path + * @param {Node|null} parentNode Parent node. If null, wysiwyg div area + * @param {Object|null} _newOffsets If you send an object of the form "{s: 0, e: 0}", the text nodes that are attached together are merged into one, centered on the "node" argument. + * "_newOffsets.s" stores the length of the combined characters after "node" and "_newOffsets.e" stores the length of the combined characters before "node". + * Do not use unless absolutely necessary. + * @returns {Array} + */ + getNodePath: function (node, parentNode, _newOffsets) { + const path = []; + let finds = true; + + this.getParentElement(node, function (el) { + if (el === parentNode) finds = false; + if (finds && !this.isWysiwygDiv(el)) { + // merge text nodes + if (_newOffsets && el.nodeType === 3) { + let temp = null, tempText = null; + _newOffsets.s = _newOffsets.e = 0; + + let previous = el.previousSibling; + while (previous && previous.nodeType === 3) { + tempText = previous.textContent.replace(this.zeroWidthRegExp, ''); + _newOffsets.s += tempText.length; + el.textContent = tempText + el.textContent; + temp = previous; + previous = previous.previousSibling; + this.removeItem(temp); + } + + let next = el.nextSibling; + while (next && next.nodeType === 3) { + tempText = next.textContent.replace(this.zeroWidthRegExp, ''); + _newOffsets.e += tempText.length; + el.textContent += tempText; + temp = next; + next = next.nextSibling; + this.removeItem(temp); + } + } + + // index push + path.push(el); + } + return false; + }.bind(this)); + + return path.map(this.getPositionIndex).reverse(); + }, + + /** + * @description Returns the node in the location of the path array obtained from "util.getNodePath". + * @param {Array} offsets Position array, array obtained from "util.getNodePath" + * @param {Node} parentNode Base parent element + * @returns {Node} + */ + getNodeFromPath: function (offsets, parentNode) { + let current = parentNode; + let nodes; + + for (let i = 0, len = offsets.length; i < len; i++) { + nodes = current.childNodes; + if (nodes.length === 0) break; + if (nodes.length <= offsets[i]) { + current = nodes[nodes.length - 1]; + } else { + current = nodes[offsets[i]]; + } + } + + return current; + }, + + /** + * @description Compares the style and class for equal values. + * Returns true if both are text nodes. + * @param {Node} a Node to compare + * @param {Node} b Node to compare + * @returns {Boolean} + */ + isSameAttributes: function (a, b) { + if (a.nodeType === 3 && b.nodeType === 3) return true; + if (a.nodeType === 3 || b.nodeType === 3) return false; + + const style_a = a.style; + const style_b = b.style; + let compStyle = 0; + + for (let i = 0, len = style_a.length; i < len; i++) { + if (style_a[style_a[i]] === style_b[style_a[i]]) compStyle++; + } + + const class_a = a.classList; + const class_b = b.classList; + const reg = this._w.RegExp; + let compClass = 0; + + for (let i = 0, len = class_a.length; i < len; i++) { + if (reg('(\s|^)' + class_a[i] + '(\s|$)').test(class_b.value)) compClass++; + } + + return (compStyle === style_b.length && compStyle === style_a.length) && (compClass === class_b.length && compClass === class_a.length); + }, + + /** + * @description Check the node is a list (ol, ul) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isList: function (node) { + return node && /^(OL|UL)$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Check the node is a list cell (li) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isListCell: function (node) { + return node && /^LI$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Check the node is a table (table, thead, tbody, tr, th, td) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isTable: function (node) { + return node && /^(TABLE|THEAD|TBODY|TR|TH|TD)$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Check the node is a table cell (td, th) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isCell: function (node) { + return node && /^(TD|TH)$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Check the node is a break node (BR) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isBreak: function (node) { + return node && /^BR$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + + /** + * @description Check the node is a anchor node (A) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isAnchor: function (node) { + return node && /^A$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Check the node is a media node (img, iframe, audio, video, canvas) + * @param {Node|String} node The element or element name to check + * @returns {Boolean} + */ + isMedia: function (node) { + return node && /^(IMG|IFRAME|AUDIO|VIDEO|CANVAS)$/i.test(typeof node === 'string' ? node : node.nodeName); + }, + + /** + * @description Checks for numeric (with decimal point). + * @param {String|Number} text Text string or number + * @returns {Boolean} + */ + isNumber: function (text) { + return !!text && /^-?\d+(\.\d+)?$/.test(text + ''); + }, + + /** + * @description Get a number. + * @param {String|Number} text Text string or number + * @param {Number} maxDec Maximum number of decimal places (-1 : Infinity) + * @returns {Number} + */ + getNumber: function (text, maxDec) { + if (!text) return 0; + + let number = (text + '').match(/-?\d+(\.\d+)?/); + if (!number || !number[0]) return 0; + + number = number[0]; + return maxDec < 0 ? number * 1 : maxDec === 0 ? this._w.Math.round(number * 1) : (number * 1).toFixed(maxDec) * 1; + }, + + /** + * @description Get all "children" of the argument value element (Without text nodes) + * @param {Element} element element to get child node + * @param {Function|null} validation Conditional function + * @returns {Array} + */ + getListChildren: function (element, validation) { + const children = []; + if (!element || !element.children || element.children.length === 0) return children; + + validation = validation || function () { return true; }; + + (function recursionFunc(current) { + if (element !== current && validation(current)) { + children.push(current); + } + + for (let i = 0, len = current.children.length; i < len; i++) { + recursionFunc(current.children[i]); + } + })(element); + + return children; + }, + + /** + * @description Get all "childNodes" of the argument value element (Include text nodes) + * @param {Node} element element to get child node + * @param {Function|null} validation Conditional function + * @returns {Array} + */ + getListChildNodes: function (element, validation) { + const children = []; + if (!element || element.childNodes.length === 0) return children; + + validation = validation || function () { return true; }; + + (function recursionFunc(current) { + if (element !== current && validation(current)) { + children.push(current); + } + + for (let i = 0, len = current.childNodes.length; i < len; i++) { + recursionFunc(current.childNodes[i]); + } + })(element); + + return children; + }, + + /** + * @description Returns the number of parents nodes. + * "0" when the parent node is the WYSIWYG area. + * "-1" when the element argument is the WYSIWYG area. + * @param {Node} element The element to check + * @returns {Number} + */ + getElementDepth: function (element) { + if (!element || this.isWysiwygDiv(element)) return -1; + + let depth = 0; + element = element.parentNode; + + while (element && !this.isWysiwygDiv(element)) { + depth += 1; + element = element.parentNode; + } + + return depth; + }, + + /** + * @description Compares two elements to find a common ancestor, and returns the order of the two elements. + * @param {Node} a Node to compare. + * @param {Node} b Node to compare. + * @returns {Object} { ancesstor, a, b, result: (a > b ? 1 : a < b ? -1 : 0) }; + */ + compareElements: function (a, b) { + let aNode = a, bNode = b; + while (aNode && bNode && aNode.parentNode !== bNode.parentNode) { + aNode = aNode.parentNode; + bNode = bNode.parentNode; + } + + if (!aNode || !bNode) return { ancestor: null, a: a, b: b, result: 0 }; + + const children = aNode.parentNode.childNodes; + const aIndex = this.getArrayIndex(children, aNode); + const bIndex = this.getArrayIndex(children, bNode); + + return { + ancestor: aNode.parentNode, + a: aNode, + b: bNode, + result: aIndex > bIndex ? 1 : aIndex < bIndex ? -1 : 0 + }; + }, + + /** + * @description Get the parent element of the argument value. + * A tag that satisfies the query condition is imported. + * Returns null if not found. + * @param {Node} element Reference element + * @param {String|Function} query Query String (nodeName, .className, #ID, :name) or validation function. + * Not use it like jquery. + * Only one condition can be entered at a time. + * @returns {Element|null} + */ + getParentElement: function (element, query) { + let check; + + if (typeof query === 'function') { + check = query; + } else { + let attr; + if (/^\./.test(query)) { + attr = 'className'; + query = query.split('.')[1]; + } else if (/^#/.test(query)) { + attr = 'id'; + query = '^' + query.split('#')[1] + '$'; + } else if (/^:/.test(query)) { + attr = 'name'; + query = '^' + query.split(':')[1] + '$'; + } else { + attr = 'nodeName'; + query = '^' + query + '$'; + } + + const regExp = new this._w.RegExp(query, 'i'); + check = function (el) { + return regExp.test(el[attr]); + }; + } + + while (element && !check(element)) { + if (this.isWysiwygDiv(element)) { + return null; + } + element = element.parentNode; + } + + return element; + }, + + /** + * @description Get the child element of the argument value. + * A tag that satisfies the query condition is imported. + * Returns null if not found. + * @param {Node} element Reference element + * @param {String|Function} query Query String (nodeName, .className, #ID, :name) or validation function. + * @param {Boolean} last If true returns the last node among the found child nodes. (default: first node) + * Not use it like jquery. + * Only one condition can be entered at a time. + * @returns {Element|null} + */ + getChildElement: function (element, query, last) { + let check; + + if (typeof query === 'function') { + check = query; + } else { + let attr; + if (/^\./.test(query)) { + attr = 'className'; + query = query.split('.')[1]; + } else if (/^#/.test(query)) { + attr = 'id'; + query = '^' + query.split('#')[1] + '$'; + } else if (/^:/.test(query)) { + attr = 'name'; + query = '^' + query.split(':')[1] + '$'; + } else { + attr = 'nodeName'; + query = '^' + (query === 'text' ? '#' + query : query) + '$'; + } + + const regExp = new this._w.RegExp(query, 'i'); + check = function (el) { + return regExp.test(el[attr]); + }; + } + + const childList = this.getListChildNodes(element, function (current) { + return check(current); + }); + + return childList[last ? childList.length - 1 : 0]; + }, + + /** + * @description 1. The first node of all the child nodes of the "first" element is returned. + * 2. The last node of all the child nodes of the "last" element is returned. + * 3. When there is no "last" element, the first and last nodes of all the children of the "first" element are returned. + * { sc: "first", ec: "last" } + * @param {Node} first First element + * @param {Node|null} last Last element + * @returns {Object} + */ + getEdgeChildNodes: function (first, last) { + if (!first) return; + if (!last) last = first; + + while (first && first.nodeType === 1 && first.childNodes.length > 0 && !this.isBreak(first)) first = first.firstChild; + while (last && last.nodeType === 1 && last.childNodes.length > 0 && !this.isBreak(last)) last = last.lastChild; + + return { + sc: first, + ec: last || first + }; + }, + + /** + * @description Returns the position of the left and top of argument. {left:0, top:0} + * @param {Node} element Target node + * @param {Element|null} wysiwygFrame When use iframe option, iframe object should be sent (context.element.wysiwygFrame) + * @returns {Object} + */ + getOffset: function (element, wysiwygFrame) { + let offsetLeft = 0; + let offsetTop = 0; + let offsetElement = element.nodeType === 3 ? element.parentElement : element; + const wysiwyg = this.getParentElement(element, this.isWysiwygDiv.bind(this)); + + while (offsetElement && !this.hasClass(offsetElement, 'se-container') && offsetElement !== wysiwyg) { + offsetLeft += offsetElement.offsetLeft; + offsetTop += offsetElement.offsetTop; + offsetElement = offsetElement.offsetParent; + } + + const iframe = wysiwygFrame && /iframe/i.test(wysiwygFrame.nodeName); + + return { + left: offsetLeft + (iframe ? wysiwygFrame.parentElement.offsetLeft : 0), + top: (offsetTop - (wysiwyg ? wysiwyg.scrollTop : 0)) + (iframe ? wysiwygFrame.parentElement.offsetTop : 0) + }; + }, + + /** + * @description It compares the start and end indexes of "a" and "b" and returns the number of overlapping indexes in the range. + * ex) 1, 5, 4, 6 => "2" (4 ~ 5) + * @param {Number} aStart Start index of "a" + * @param {Number} aEnd End index of "a" + * @param {Number} bStart Start index of "b" + * @param {Number} bEnd Start index of "b" + * @returns {Number} + */ + getOverlapRangeAtIndex: function (aStart, aEnd, bStart, bEnd) { + if (aStart <= bEnd ? aEnd < bStart : aEnd > bStart) return 0; + + const overlap = (aStart > bStart ? aStart : bStart) - (aEnd < bEnd ? aEnd : bEnd); + return (overlap < 0 ? overlap * -1 : overlap) + 1; + }, + + /** + * @description Set the text content value of the argument value element + * @param {Node} element Element to replace text content + * @param {String} txt Text to be applied + */ + changeTxt: function (element, txt) { + if (!element || !txt) return; + element.textContent = txt; + }, + + /** + * @description Replace element + * @param {Element} element Target element + * @param {String|Element} newElement String or element of the new element to apply + */ + changeElement: function (element, newElement) { + if (typeof newElement === 'string') { + if (element.outerHTML) { + element.outerHTML = newElement; + } else { + const doc = this.createElement('DIV'); + doc.innerHTML = newElement; + newElement = doc.firstChild; + element.parentNode.replaceChild(newElement, element); + } + } else if (newElement.nodeType === 1) { + element.parentNode.replaceChild(newElement, element); + } + }, + + /** + * @description Set style, if all styles are deleted, the style properties are deleted. + * @param {Element} element Element to set style + * @param {String} styleName Style attribute name (marginLeft, textAlign...) + * @param {String|Number} value Style value + */ + setStyle: function (element, styleName, value) { + element.style[styleName] = value; + + if (!value && !element.style.cssText) { + element.removeAttribute('style'); + } + }, + + /** + * @description Determine whether any of the matched elements are assigned the given class + * @param {Element} element Elements to search class name + * @param {String} className Class name to search for + * @returns {Boolean} + */ + hasClass: function (element, className) { + if (!element) return; + + return (new this._w.RegExp(className)).test(element.className); + }, + + /** + * @description Append the className value of the argument value element + * @param {Element} element Elements to add class name + * @param {String} className Class name to be add + */ + addClass: function (element, className) { + if (!element) return; + + const check = new this._w.RegExp('(\\s|^)' + className + '(\\s|$)'); + if (check.test(element.className)) return; + + element.className += (element.className.length > 0 ? ' ' : '') + className; + }, + + /** + * @description Delete the className value of the argument value element + * @param {Element} element Elements to remove class name + * @param {String} className Class name to be remove + */ + removeClass: function (element, className) { + if (!element) return; + + const check = new this._w.RegExp('(\\s|^)' + className + '(\\s|$)'); + element.className = element.className.replace(check, ' ').trim(); + + if (!element.className.trim()) element.removeAttribute('class'); + }, + + /** + * @description Argument value If there is no class name, insert it and delete the class name if it exists + * @param {Element} element Elements to replace class name + * @param {String} className Class name to be change + * @returns {Boolean|undefined} + */ + toggleClass: function (element, className) { + if (!element) return; + let result = false; + + const check = new this._w.RegExp('(\\s|^)' + className + '(\\s|$)'); + if (check.test(element.className)) { + element.className = element.className.replace(check, ' ').trim(); + } else { + element.className += ' ' + className; + result = true; + } + + if (!element.className.trim()) element.removeAttribute('class'); + + return result; + }, + + /** + * @description In the predefined code view mode, the buttons except the executable button are changed to the 'disabled' state. + * core.codeViewDisabledButtons (An array of buttons whose class name is not "se-code-view-enabled") + * core.resizingDisabledButtons (An array of buttons whose class name is not "se-resizing-enabled") + * @param {Boolean} disabled Disabled value + * @param {Array|HTMLCollection|NodeList} buttonList Button array + */ + setDisabledButtons: function (disabled, buttonList) { + for (let i = 0, len = buttonList.length; i < len; i++) { + buttonList[i].disabled = disabled; + } + }, + + /** + * @description Delete argumenu value element + * @param {Node} item Node to be remove + */ + removeItem: function (item) { + if (!item) return; + try { + item.remove(); + } catch (e) { + if (item.parentNode) item.parentNode.removeChild(item); + } + }, + + /** + * @description Delete all parent nodes that match the condition. + * Returns an {sc: previousSibling, ec: nextSibling}(the deleted node reference) or null. + * @param {Node} item Node to be remove + * @param {Function|null} validation Validation function. default(Deleted if it only have breakLine and blanks) + * @param {Element|null} stopParent Stop when the parent node reaches stopParent + * @returns {Object|null} {sc: previousSibling, ec: nextSibling} + */ + removeItemAllParents: function (item, validation, stopParent) { + if (!item) return null; + let cc = null; + if (!validation) { + validation = function (current) { + if (current === stopParent || this.isComponent(current)) return false; + const text = current.textContent.trim(); + return text.length === 0 || /^(\n|\u200B)+$/.test(text); + }.bind(this); + } + + (function recursionFunc (element) { + if (!util.isWysiwygDiv(element)) { + const parent = element.parentNode; + if (parent && validation(element)) { + cc = { + sc: element.previousElementSibling, + ec: element.nextElementSibling + }; + util.removeItem(element); + recursionFunc(parent); + } + } + }(item)); + + return cc; + }, + + /** + * @description Detach Nested all nested lists under the "baseNode". + * Returns a list with nested removed. + * @param {Node} baseNode Element on which to base. + * @param {Boolean} all If true, it also detach all nested lists of a returned list. + * @returns {Element} + */ + detachNestedList: function (baseNode, all) { + const rNode = this._deleteNestedList(baseNode); + let rangeElement, cNodes; + + if (rNode) { + rangeElement = rNode.cloneNode(false); + cNodes = rNode.childNodes; + const index = this.getPositionIndex(baseNode); + while (cNodes[index]) { + rangeElement.appendChild(cNodes[index]); + } + } else { + rangeElement = baseNode; + } + + let rChildren; + if (!all) { + const depth = this.getElementDepth(baseNode) + 2; + rChildren = this.getListChildren(baseNode, function (current) { return this.isListCell(current) && !current.previousElementSibling && this.getElementDepth(current) === depth; }.bind(this)); + } else { + rChildren = this.getListChildren(rangeElement, function (current) { return this.isListCell(current) && !current.previousElementSibling; }.bind(this)); + } + + for (let i = 0, len = rChildren.length; i < len; i++) { + this._deleteNestedList(rChildren[i]); + } + + if (rNode) { + rNode.parentNode.insertBefore(rangeElement, rNode.nextSibling); + if (cNodes && cNodes.length === 0) this.removeItem(rNode); + } + + return rangeElement === baseNode ? rangeElement.parentNode : rangeElement; + }, + + /** + * @description Sub function of util.detachNestedList method. + * @private + */ + _deleteNestedList: function (baseNode) { + const baseParent = baseNode.parentNode; + let sibling = baseParent; + let parent = sibling.parentNode; + let liSibling, liParent, child, index, c; + + while (this.isListCell(parent)) { + index = this.getPositionIndex(baseNode); + liSibling = parent.nextElementSibling; + liParent = parent.parentNode; + child = sibling; + while(child) { + sibling = sibling.nextSibling; + if (this.isList(child)) { + c = child.childNodes; + while (c[index]) { + liParent.insertBefore(c[index], liSibling); + } + if (c.length === 0) this.removeItem(child); + } else { + liParent.appendChild(child); + } + child = sibling; + } + sibling = liParent; + parent = liParent.parentNode; + } + + if (baseParent.children.length === 0) this.removeItem(baseParent); + + return liParent; + }, + + /** + * @description Split all tags based on "baseNode" + * Returns the last element of the splited tag. + * @param {Node} baseNode Element or text node on which to base + * @param {Number|null} offset Text offset of "baseNode" (Only valid when "baseNode" is a text node) + * @param {Number} depth The nesting depth of the element being split. (default: 0) + * @returns {Element} + */ + splitElement: function (baseNode, offset, depth) { + const bp = baseNode.parentNode; + let index = 0, newEl, children, temp; + let next = true; + if (!depth || depth < 0) depth = 0; + + if (baseNode.nodeType === 3) { + index = this.getPositionIndex(baseNode); + if (offset >= 0) { + baseNode.splitText(offset); + const after = this.getNodeFromPath([index + 1], bp); + if (this.onlyZeroWidthSpace(after)) after.data = this.zeroWidthSpace; + } + } else if (baseNode.nodeType === 1) { + if (!baseNode.previousSibling) { + if (this.getElementDepth(baseNode) === depth) next = false; + } else { + baseNode = baseNode.previousSibling; + } + } + + let depthEl = baseNode; + while (this.getElementDepth(depthEl) > depth) { + index = this.getPositionIndex(depthEl) + 1; + depthEl = depthEl.parentNode; + + temp = newEl; + newEl = depthEl.cloneNode(false); + children = depthEl.childNodes; + + if (temp) { + if (this.isListCell(newEl) && this.isList(temp) && temp.firstElementChild) { + newEl.innerHTML = temp.firstElementChild.innerHTML; + util.removeItem(temp.firstElementChild); + if (temp.children.length > 0) newEl.appendChild(temp); + } else { + newEl.appendChild(temp); + } + } + + while (children[index]) { + newEl.appendChild(children[index]); + } + } + + if (depthEl.childNodes.length <= 1 && (!depthEl.firstChild || depthEl.firstChild.textContent.length === 0)) depthEl.innerHTML = '
'; + + const pElement = depthEl.parentNode; + if (next) depthEl = depthEl.nextSibling; + if (!newEl) return depthEl; + + this.mergeSameTags(newEl, null, false); + this.mergeNestedTags(newEl, function (current) { return this.isList(current); }.bind(this)); + + if (newEl.childNodes.length > 0) pElement.insertBefore(newEl, depthEl); + else newEl = depthEl; + + if (bp.childNodes.length === 0) this.removeItem(bp); + + return newEl; + }, + + /** + * @description Use with "npdePath (util.getNodePath)" to merge the same attributes and tags if they are present and modify the nodepath. + * If "offset" has been changed, it will return as much "offset" as it has been modified. + * An array containing change offsets is returned in the order of the "nodePathArray" array. + * @param {Element} element Element + * @param {Array|null} nodePathArray Array of NodePath object ([util.getNodePath(), ..]) + * @param {Boolean} onlyText If true, non-text nodes(!util._isIgnoreNodeChange) like 'span', 'strong'.. are ignored. + * @returns {Array} [offset, ..] + */ + mergeSameTags: function (element, nodePathArray, onlyText) { + const inst = this; + const nodePathLen = nodePathArray ? nodePathArray.length : 0; + let offsets = null; + + if (nodePathLen) { + offsets = this._w.Array.apply(null, new this._w.Array(nodePathLen)).map(this._w.Number.prototype.valueOf, 0); + } + + (function recursionFunc(current, depth, depthIndex) { + const children = current.childNodes; + + for (let i = 0, len = children.length, child, next; i < len; i++) { + child = children[i]; + next = children[i + 1]; + if (!child) break; + if((onlyText && inst._isIgnoreNodeChange(child)) || (!onlyText && (inst.isTable(child) || inst.isListCell(child) || (inst.isFormatElement(child) && !inst.isFreeFormatElement(child))))) { + if (inst.isTable(child) || inst.isListCell(child)) { + recursionFunc(child, depth + 1, i); + } + continue; + } + if (len === 1 && current.nodeName === child.nodeName && current.parentNode) { + // update nodePath + if (nodePathLen) { + let path, c, p, cDepth, spliceDepth; + for (let n = 0; n < nodePathLen; n++) { + path = nodePathArray[n]; + if (path && path[depth] === i) { + c = child, p = current, cDepth = depth, spliceDepth = true; + while (cDepth >= 0) { + if (inst.getArrayIndex(p.childNodes, c) !== path[cDepth]) { + spliceDepth = false; + break; + } + c = child.parentNode; + p = c.parentNode; + cDepth--; + } + if (spliceDepth) { + path.splice(depth, 1); + path[depth] = i; + } + } + } + } + + // merge tag + inst.copyTagAttributes(child, current); + current.parentNode.insertBefore(child, current); + inst.removeItem(current); + } + if (!next) { + if (child.nodeType === 1) recursionFunc(child, depth + 1, i); + break; + } + + if (child.nodeName === next.nodeName && inst.isSameAttributes(child, next) && child.href === next.href) { + const childs = child.childNodes; + let childLength = 0; + for (let n = 0, nLen = childs.length; n < nLen; n++) { + if (childs[n].textContent.length > 0) childLength++; + } + + const l = child.lastChild; + const r = next.firstChild; + let addOffset = 0; + if (l && r) { + const textOffset = l.nodeType === 3 && r.nodeType === 3; + addOffset = l.textContent.length; + let tempL = l.previousSibling; + while(tempL && tempL.nodeType === 3) { + addOffset += tempL.textContent.length; + tempL = tempL.previousSibling; + } + + if (childLength > 0 && l.nodeType === 3 && r.nodeType === 3 && (l.textContent.length > 0 || r.textContent.length > 0)) childLength--; + + if (nodePathLen) { + let path = null; + for (let n = 0; n < nodePathLen; n++) { + path = nodePathArray[n]; + if (path && path[depth] > i) { + if (depth > 0 && path[depth - 1] !== depthIndex) continue; + + path[depth] -= 1; + if (path[depth + 1] >= 0 && path[depth] === i) { + path[depth + 1] += childLength; + if (textOffset) { + if (l && l.nodeType === 3 && r && r.nodeType === 3) { + offsets[n] += addOffset; + } + } + } + } + } + } + } + + if (child.nodeType === 3) { + addOffset = child.textContent.length; + child.textContent += next.textContent; + if (nodePathLen) { + let path = null; + for (let n = 0; n < nodePathLen; n++) { + path = nodePathArray[n]; + if (path && path[depth] > i) { + if (depth > 0 && path[depth - 1] !== depthIndex) continue; + + path[depth] -= 1; + if (path[depth + 1] >= 0 && path[depth] === i) { + path[depth + 1] += childLength; + offsets[n] += addOffset; + } + } + } + } + } else { + child.innerHTML += next.innerHTML; + } + + inst.removeItem(next); + i--; + } else if (child.nodeType === 1) { + recursionFunc(child, depth + 1, i); + } + } + })(element, 0, 0); + + return offsets; + }, + + /** + * @description Remove nested tags without other child nodes. + * @param {Element} element Element object + * @param {Function|String|null} validation Validation function / String("tag1|tag2..") / If null, all tags are applicable. + */ + mergeNestedTags: function (element, validation) { + if (typeof validation === 'string') { + validation = function (current) { return this.test(current.tagName); }.bind(new this._w.RegExp('^(' + (validation ? validation : '.+') + ')$', 'i')); + } else if (typeof validation !== 'function') { + validation = function () { return true; }; + } + + (function recursionFunc(current) { + let children = current.children; + if (children.length === 1 && children[0].nodeName === current.nodeName && validation(current)) { + const temp = children[0]; + children = temp.children; + while (children[0]) { + current.appendChild(children[0]); + } + current.removeChild(temp); + } + + for (let i = 0, len = current.children.length; i < len; i++) { + recursionFunc(current.children[i]); + } + })(element); + }, + + /** + * @description Delete a empty child node of argument element + * @param {Element} element Element node + * @param {Node|null} notRemoveNode Do not remove node + */ + removeEmptyNode: function (element, notRemoveNode) { + const inst = this; + + if (notRemoveNode) { + notRemoveNode = inst.getParentElement(notRemoveNode, function (current) { + return element === current.parentElement; + }); + } + + (function recursionFunc(current) { + if (inst._notTextNode(current) || current === notRemoveNode || inst.isNonEditable(current)) return 0; + if (current !== element && inst.onlyZeroWidthSpace(current.textContent) && (!current.firstChild || !inst.isBreak(current.firstChild))) { + if (current.parentNode) { + current.parentNode.removeChild(current); + return -1; + } + } else { + const children = current.children; + for (let i = 0, len = children.length, r = 0; i < len; i++) { + if (!children[i + r] || inst.isComponent(children[i + r])) continue; + r += recursionFunc(children[i + r]); + } + } + + return 0; + })(element); + + if (element.childNodes.length === 0) element.innerHTML = '
'; + }, + + /** + * @description Remove whitespace between tags in HTML string. + * @param {String} html HTML string + * @returns {String} + */ + htmlRemoveWhiteSpace: function (html) { + if (!html) return ''; + return html.trim().replace(/<\/?(?!strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code)[^>^<]+>\s+(?=<)/ig, function (m) { return m.trim(); }); + }, + + /** + * @description Sort a element array by depth of element. + * @param {Array} array Array object + * @param {Boolean} des true: descending order / false: ascending order + */ + sortByDepth: function (array, des) { + const t = !des ? -1 : 1; + const f = t * -1; + + array.sort(function (a, b) { + if (!this.isListCell(a) || !this.isListCell(b)) return 0; + a = this.getElementDepth(a); + b = this.getElementDepth(b); + return a > b ? t : a < b ? f : 0; + }.bind(this)); + }, + + /** + * @description Nodes that need to be added without modification when changing text nodes + * @param {Node} element Element to check + * @returns {Boolean} + * @private + */ + _isIgnoreNodeChange: function (element) { + return element && element.nodeType !== 3 && (this.isNonEditable(element) || !this.isTextStyleElement(element)); + }, + + /** + * @description Nodes that must remain undetached when changing text nodes (A, Label, Code) + * @param {Node|String} element Element to check + * @returns {Boolean} + * @private + */ + _isMaintainedNode: function (element) { + return element && element.nodeType !== 3 && /^(a|label|code)$/i.test(typeof element === 'string' ? element : element.nodeName); + }, + + /** + * @description Node with font-size style + * @param {Node} element Element to check + * @returns {Boolean} + * @private + */ + _isSizeNode: function (element) { + return element && element.nodeType !== 3 && this.isTextStyleElement(element) && !!element.style.fontSize; + }, + + /** + * @description Nodes without text + * @param {Node} element Element to check + * @returns {Boolean} + * @private + */ + _notTextNode: function (element) { + return element && element.nodeType !== 3 && (this.isComponent(element) || /^(br|input|select|canvas|img|iframe|audio|video)$/i.test(typeof element === 'string' ? element : element.nodeName)); + }, + + /** + * @description Check disallowed tags + * @param {Node} element Element to check + * @returns {Boolean} + * @private + */ + _disallowedTags: function (element) { + return /^(meta|script|link|style|[a-z]+\:[a-z]+)$/i.test(element.nodeName); + }, + + /** + * @description Create whitelist RegExp object. + * Return RegExp format: new RegExp("<\\/?\\b(?!" + list + ")\\b[^>^<]*+>", "gi") + * @param {String} list Tags list ("br|p|div|pre...") + * @returns {RegExp} + */ + createTagsWhitelist: function (list) { + return new RegExp('<\\/?\\b(?!\\b' + list.replace(/\|/g, '\\b|\\b') + '\\b)[^>]*>', 'gi'); + }, + + /** + * @description Get key of the options.allowStyles + * @param {Node} node Node + * @returns {String} + * @private + */ + _getCheckFormat: function (node) { + return node.nodeType === 3 ? 'null' : + this.isComponent(node) ? 'component' : + this.isClosureFreeFormatElement(node) ? 'closureFreeFormat' : + this.isFreeFormatElement(node) ? 'freeFormat' : + this.isClosureRangeFormatElement(node) ? 'closureRangeFormat' : + this.isRangeFormatElement(node) ? 'rangeFormat' : + this.isFormatElement(node) ? 'format' : node.nodeName.toLowerCase(); + }, + + /** + * @description Fix tags that do not fit the editor format. + * @param {Element} documentFragment Document fragment "DOCUMENT_FRAGMENT_NODE" (nodeType === 11) + * @param {RegExp} htmlCheckWhitelistRegExp Editor tags whitelist (core._htmlCheckWhitelistRegExp) + * @param {Object} allowStyles options.allowStyles + * @private + */ + _consistencyCheckOfHTML: function (documentFragment, htmlCheckWhitelistRegExp, allowStyles) { + /** + * It is can use ".children(util.getListChildren)" to exclude text nodes, but "documentFragment.children" is not supported in IE. + * So check the node type and exclude the text no (current.nodeType !== 1) + */ + const removeTags = [], emptyTags = [], wrongList = [], withoutFormatCells = []; + + // wrong position + const wrongTags = this.getListChildNodes(documentFragment, function (current) { + if (current.nodeType !== 1) return false; + + // white list + if (!htmlCheckWhitelistRegExp.test(current.nodeName) && current.childNodes.length === 0 && this.isNotCheckingNode(current)) { + removeTags.push(current); + return false; + } + + const nrtag = !this.getParentElement(current, this.isNotCheckingNode); + // empty tags + if ((!this.isTable(current) && !this.isListCell(current)) && (this.isFormatElement(current) || this.isRangeFormatElement(current) || this.isTextStyleElement(current)) && current.childNodes.length === 0 && nrtag) { + emptyTags.push(current); + return false; + } + + // wrong list + if (this.isList(current.parentNode) && !this.isList(current) && !this.isListCell(current)) { + wrongList.push(current); + return false; + } + + // table cells + if (this.isCell(current)) { + const fel = current.firstElementChild; + if (!this.isFormatElement(fel) && !this.isRangeFormatElement(fel) && !this.isComponent(fel)) { + withoutFormatCells.push(current); + return false; + } + } + + const result = current.parentNode !== documentFragment && + (this.isFormatElement(current) || this.isComponent(current) || this.isList(current)) && + !this.isRangeFormatElement(current.parentNode) && !this.isListCell(current.parentNode) && + !this.getParentElement(current, this.isComponent) && nrtag; + + // @v3 + // if (!result) { + // const styles = allowStyles[this._getCheckFormat(current)]; + // if (!!styles && styles.length > 0) { + // let s = ''; + // const currentStyle = current.style; + // for (let i = 0, len = styles.length; i < len; i++) { + // s += styles[i] + ':' + currentStyle[styles[i]] + '; '; + // } + + // if (!s) current.removeAttribute('style'); + // else current.style.cssText = s; + // } + // } + + return result; + }.bind(this)); + + for (let i = 0, len = removeTags.length; i < len; i++) { + this.removeItem(removeTags[i]); + } + + const checkTags = []; + for (let i = 0, len = wrongTags.length, t, p; i < len; i++) { + t = wrongTags[i]; + p = t.parentNode; + if (!p || !p.parentNode) continue; + p.parentNode.insertBefore(t, p); + checkTags.push(p); + } + + for (let i = 0, len = checkTags.length, t; i < len; i++) { + t = checkTags[i]; + if (this.onlyZeroWidthSpace(t.textContent.trim())) { + this.removeItem(t); + } + } + + for (let i = 0, len = emptyTags.length; i < len; i++) { + this.removeItem(emptyTags[i]); + } + + for (let i = 0, len = wrongList.length, t, tp, children, p; i < len; i++) { + t = wrongList[i]; + + tp = this.createElement('LI'); + children = t.childNodes; + while (children[0]) { + tp.appendChild(children[0]); + } + + p = t.parentNode; + if (!p) continue; + p.insertBefore(tp, t); + this.removeItem(t); + } + + for (let i = 0, len = withoutFormatCells.length, t, f; i < len; i++) { + t = withoutFormatCells[i]; + f = this.createElement('DIV'); + f.innerHTML = (t.textContent.trim().length === 0 && t.children.length === 0) ? '
' : t.innerHTML; + t.innerHTML = f.outerHTML; + } + }, + + _setDefaultOptionStyle: function (options, defaultStyle) { + let optionStyle = ''; + if (options.height) optionStyle += 'height:' + options.height + ';'; + if (options.minHeight) optionStyle += 'min-height:' + options.minHeight + ';'; + if (options.maxHeight) optionStyle += 'max-height:' + options.maxHeight + ';'; + if (options.position) optionStyle += 'position:' + options.position + ';'; + if (options.width) optionStyle += 'width:' + options.width + ';'; + if (options.minWidth) optionStyle += 'min-width:' + options.minWidth + ';'; + if (options.maxWidth) optionStyle += 'max-width:' + options.maxWidth + ';'; + + let top = '', frame = '', editor = ''; + defaultStyle = optionStyle + defaultStyle; + const styleArr = defaultStyle.split(';'); + for (let i = 0, len = styleArr.length, s; i < len; i++) { + s = styleArr[i].trim(); + if (!s) continue; + if (/^(min-|max-)?width\s*:/.test(s)) { + top += s + ';'; + continue; + } + if (/^(min-|max-)?height\s*:/.test(s)) { + if (/^height/.test(s) && s.split(':')[1].trim() === 'auto') { + options.height = 'auto'; + } + frame += s + ';'; + continue; + } + editor += s + ';'; + } + + return { + top: top, + frame: frame, + editor: editor + }; + }, + + _setIframeDocument: function (frame, options) { + frame.setAttribute('scrolling', 'auto'); + frame.contentDocument.head.innerHTML = '' + + '' + + '' + + this._setIframeCssTags(options); + frame.contentDocument.body.className = options._editableClass; + frame.contentDocument.body.setAttribute('contenteditable', true); + }, + + _setIframeCssTags: function (options) { + const linkNames = options.iframeCSSFileName; + const wRegExp = this._w.RegExp; + let tagString = ''; + + for (let f = 0, len = linkNames.length, path; f < len; f++) { + path = []; + + if (/(^https?:\/\/)|(^data:text\/css,)/.test(linkNames[f])) { + path.push(linkNames[f]); + } else { + const CSSFileName = new wRegExp('(^|.*[\\/])' + linkNames[f] + '(\\..+)?\\.css(?:\\?.*|;.*)?$', 'i'); + for (let c = document.getElementsByTagName('link'), i = 0, len = c.length, styleTag; i < len; i++) { + styleTag = c[i].href.match(CSSFileName); + if (styleTag) path.push(styleTag[0]); + } + } + + if (!path || path.length === 0) throw '[SUNEDITOR.constructor.iframe.fail] The suneditor CSS files installation path could not be automatically detected. Please set the option property "iframeCSSFileName" before creating editor instances.'; + + for (let i = 0, len = path.length; i < len; i++) { + tagString += ''; + } + } + + return tagString + (options.height === 'auto' ? '' : ''); + } +}; + +/* harmony default export */ __webpack_exports__["default"] = (util); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/command/blockquote.js": +/*!******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/command/blockquote.js ***! + \******************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'blockquote', + display: 'command', + add: function (core, targetElement) { + const context = core.context; + context.blockquote = { + targetButton: targetElement, + tag: core.util.createElement('BLOCKQUOTE') + }; + }, + + /** + * @Override core + */ + active: function (element) { + if (!element) { + this.util.removeClass(this.context.blockquote.targetButton, 'active'); + } else if (/blockquote/i.test(element.nodeName)) { + this.util.addClass(this.context.blockquote.targetButton, 'active'); + return true; + } + + return false; + }, + + /** + * @Override core + */ + action: function () { + const currentBlockquote = this.util.getParentElement(this.getSelectionNode(), 'blockquote'); + + if (currentBlockquote) { + this.detachRangeFormatElement(currentBlockquote, null, null, false, false); + } else { + this.applyRangeFormatElement(this.context.blockquote.tag.cloneNode(false)); + } + } +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/dialog/audio.js": +/*!************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/dialog/audio.js ***! + \************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/dialog */ "./node_modules/suneditor/src/plugins/modules/dialog.js"); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_dialog__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/component */ "./node_modules/suneditor/src/plugins/modules/component.js"); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_modules_component__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/fileManager */ "./node_modules/suneditor/src/plugins/modules/fileManager.js"); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_modules_fileManager__WEBPACK_IMPORTED_MODULE_2__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'audio', + display: 'dialog', + add: function (core) { + core.addModule([_modules_dialog__WEBPACK_IMPORTED_MODULE_0___default.a, _modules_component__WEBPACK_IMPORTED_MODULE_1___default.a, _modules_fileManager__WEBPACK_IMPORTED_MODULE_2___default.a]); + + const context = core.context; + const contextAudio = context.audio = { + _infoList: [], // @Override fileManager + _infoIndex: 0, // @Override fileManager + _uploadFileLength: 0, // @Override fileManager + focusElement: null, // @Override dialog // This element has focus when the dialog is opened. + targetSelect: null, + _origin_w: core.options.audioWidth, + _origin_h: core.options.audioHeight, + _linkValue: '', + // @require @Override component + _element: null, + _cover: null, + _container: null, + }; + + /** dialog */ + let audio_dialog = this.setDialog(core); + contextAudio.modal = audio_dialog; + contextAudio.audioInputFile = audio_dialog.querySelector('._se_audio_files'); + contextAudio.audioUrlFile = audio_dialog.querySelector('.se-input-url'); + contextAudio.focusElement = contextAudio.audioInputFile || contextAudio.audioUrlFile; + contextAudio.preview = audio_dialog.querySelector('.se-link-preview'); + + /** controller */ + let audio_controller = this.setController(core); + contextAudio.controller = audio_controller; + + /** add event listeners */ + audio_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core)); + if (contextAudio.audioInputFile) audio_dialog.querySelector('.se-dialog-files-edge-button').addEventListener('click', this._removeSelectedFiles.bind(contextAudio.audioInputFile, contextAudio.audioUrlFile, contextAudio.preview)); + if (contextAudio.audioInputFile && contextAudio.audioUrlFile) contextAudio.audioInputFile.addEventListener('change', this._fileInputChange.bind(contextAudio)); + audio_controller.addEventListener('click', this.onClick_controller.bind(core)); + if (contextAudio.audioUrlFile) contextAudio.audioUrlFile.addEventListener('input', this._onLinkPreview.bind(contextAudio.preview, contextAudio, core.options.linkProtocol)); + + /** append html */ + context.dialog.modal.appendChild(audio_dialog); + + /** append controller */ + context.element.relative.appendChild(audio_controller); + + /** empty memory */ + audio_dialog = null, audio_controller = null; + }, + + /** HTML - dialog */ + setDialog: function (core) { + const option = core.options; + const lang = core.lang; + const dialog = core.util.createElement('DIV'); + + dialog.className = 'se-dialog-content'; + dialog.style.display = 'none'; + let html = '' + + '

' + + '
' + + '' + + '' + lang.dialogBox.audioBox.title + '' + + '
' + + '
'; + + if (option.audioFileInput) { + html += '' + + '
' + + '' + + '
' + + '' + + '' + + '
' + + '
'; + } + + if (option.audioUrlInput) { + html += '' + + '
' + + '' + + '' + + '' + + '
'; + } + + html += '' + + '
' + + '' + + '
'; + + dialog.innerHTML = html; + + return dialog; + }, + + /** HTML - controller */ + setController: function (core) { + const lang = core.lang; + const icons = core.icons; + const link_btn = core.util.createElement('DIV'); + + link_btn.className = 'se-controller se-controller-link'; + link_btn.innerHTML = '' + + '
' + + ''; + + return link_btn; + }, + + // Disable url input when uploading files + _fileInputChange: function () { + if (!this.audioInputFile.value) { + this.audioUrlFile.removeAttribute('disabled'); + this.preview.style.textDecoration = ''; + } else { + this.audioUrlFile.setAttribute('disabled', true); + this.preview.style.textDecoration = 'line-through'; + } + }, + + // Disable url input when uploading files + _removeSelectedFiles: function (urlInput, preview) { + this.value = ''; + if (urlInput) { + urlInput.removeAttribute('disabled'); + preview.style.textDecoration = ''; + } + }, + + // create new audio tag + _createAudioTag: function () { + const oAudio = this.util.createElement('AUDIO'); + this.plugins.audio._setTagAttrs.call(this, oAudio); + + const w = this.context.audio._origin_w; + const h = this.context.audio._origin_h; + oAudio.setAttribute('origin-size', w + ',' + h); + oAudio.style.cssText = (w ? ('width:' + w + '; ') : '') + (h ? ('height:' + h + ';') : ''); + + return oAudio; + }, + + _setTagAttrs: function (element) { + element.setAttribute('controls', true); + + const attrs = this.options.audioTagAttrs; + if (!attrs) return; + + for (let key in attrs) { + if (!this.util.hasOwn(attrs, key)) continue; + element.setAttribute(key, attrs[key]); + } + }, + + _onLinkPreview: function (context, protocol, e) { + const value = e.target.value.trim(); + context._linkValue = this.textContent = !value ? '' : (protocol && value.indexOf('://') === -1 && value.indexOf('#') !== 0) ? protocol + value : value.indexOf('://') === -1 ? '/' + value : value; + }, + + /** + * @Required @Override fileManager + */ + fileTags: ['audio'], + + /** + * @Override core, fileManager, resizing + * @description It is called from core.selectComponent. + * @param {Element} element Target element + */ + select: function (element) { + this.plugins.audio.onModifyMode.call(this, element); + }, + + /** + * @Override fileManager, resizing + */ + destroy: function (element) { + element = element || this.context.audio._element; + const container = this.util.getParentElement(element, this.util.isComponent) || element; + const dataIndex = element.getAttribute('data-index') * 1; + const focusEl = (container.previousElementSibling || container.nextElementSibling); + + const emptyDiv = container.parentNode; + this.util.removeItem(container); + this.plugins.audio.init.call(this); + this.controllersOff(); + + if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null); + + // focus + this.focusEdge(focusEl); + + // fileManager event + this.plugins.fileManager.deleteInfo.call(this, 'audio', dataIndex, this.functions.onAudioUpload); + + // history stack + this.history.push(false); + }, + + /** + * @Override fileManager + */ + checkFileInfo: function () { + this.plugins.fileManager.checkInfo.call(this, 'audio', ['audio'], this.functions.onAudioUpload, this.plugins.audio.updateCover.bind(this), false); + }, + + /** + * @Override fileManager + */ + resetFileInfo: function () { + this.plugins.fileManager.resetInfo.call(this, 'audio', this.functions.onAudioUpload); + }, + + /** + * @Required @Override dialog + */ + on: function (update) { + const contextAudio = this.context.audio; + + if (!update) { + this.plugins.audio.init.call(this); + if (contextAudio.audioInputFile && this.options.audioMultipleFile) contextAudio.audioInputFile.setAttribute('multiple', 'multiple'); + } else if (contextAudio._element) { + this.context.dialog.updateModal = true; + contextAudio._linkValue = contextAudio.preview.textContent = contextAudio.audioUrlFile.value = contextAudio._element.src; + if (contextAudio.audioInputFile && this.options.audioMultipleFile) contextAudio.audioInputFile.removeAttribute('multiple'); + } else { + if (contextAudio.audioInputFile && this.options.audioMultipleFile) contextAudio.audioInputFile.removeAttribute('multiple'); + } + }, + + /** + * @Required @Override dialog + */ + open: function () { + this.plugins.dialog.open.call(this, 'audio', 'audio' === this.currentControllerName); + }, + + submit: function (e) { + const contextAudio = this.context.audio; + + e.preventDefault(); + e.stopPropagation(); + + try { + if (contextAudio.audioInputFile && contextAudio.audioInputFile.files.length > 0) { + this.showLoading(); + this.plugins.audio.submitAction.call(this, contextAudio.audioInputFile.files); + } else if (contextAudio.audioUrlFile && contextAudio._linkValue.length > 0) { + this.showLoading(); + this.plugins.audio.setupUrl.call(this, contextAudio._linkValue); + } + } catch (error) { + this.closeLoading(); + throw Error('[SUNEDITOR.audio.submit.fail] cause : "' + error.message + '"'); + } finally { + this.plugins.dialog.close.call(this); + } + + return false; + }, + + submitAction: function (fileList) { + if (fileList.length === 0) return; + + let fileSize = 0; + let files = []; + for (let i = 0, len = fileList.length; i < len; i++) { + if (/audio/i.test(fileList[i].type)) { + files.push(fileList[i]); + fileSize += fileList[i].size; + } + } + + const limitSize = this.options.audioUploadSizeLimit; + if (limitSize > 0) { + let infoSize = 0; + const audiosInfo = this.context.audio._infoList; + for (let i = 0, len = audiosInfo.length; i < len; i++) { + infoSize += audiosInfo[i].size * 1; + } + + if ((fileSize + infoSize) > limitSize) { + this.closeLoading(); + const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable total audios: ' + (limitSize/1000) + 'KB'; + if (typeof this.functions.onAudioUploadError !== 'function' || this.functions.onAudioUploadError(err, { 'limitSize': limitSize, 'currentSize': infoSize, 'uploadSize': fileSize }, this)) { + this.functions.noticeOpen(err); + } + return; + } + } + + const contextAudio = this.context.audio; + contextAudio._uploadFileLength = files.length; + + const info = { + isUpdate: this.context.dialog.updateModal, + element: contextAudio._element + }; + + if (typeof this.functions.onAudioUploadBefore === 'function') { + const result = this.functions.onAudioUploadBefore(files, info, this, function (data) { + if (data && this._w.Array.isArray(data.result)) { + this.plugins.audio.register.call(this, info, data); + } else { + this.plugins.audio.upload.call(this, info, data); + } + }.bind(this)); + + if (typeof result === 'undefined') return; + if (!result) { + this.closeLoading(); + return; + } + if (typeof result === 'object' && result.length > 0) files = result; + } + + this.plugins.audio.upload.call(this, info, files); + }, + + error: function (message, response) { + this.closeLoading(); + if (typeof this.functions.onAudioUploadError !== 'function' || this.functions.onAudioUploadError(message, response, this)) { + this.functions.noticeOpen(message); + throw Error('[SUNEDITOR.plugin.audio.exception] response: ' + message); + } + }, + + upload: function (info, files) { + if (!files) { + this.closeLoading(); + return; + } + if (typeof files === 'string') { + this.plugins.audio.error.call(this, files, null); + return; + } + + const audioUploadUrl = this.options.audioUploadUrl; + const filesLen = this.context.dialog.updateModal ? 1 : files.length; + + // create formData + const formData = new FormData(); + for (let i = 0; i < filesLen; i++) { + formData.append('file-' + i, files[i]); + } + + // server upload + this.plugins.fileManager.upload.call(this, audioUploadUrl, this.options.audioUploadHeader, formData, this.plugins.audio.callBack_upload.bind(this, info), this.functions.onAudioUploadError); + }, + + callBack_upload: function (info, xmlHttp) { + if (typeof this.functions.audioUploadHandler === 'function') { + this.functions.audioUploadHandler(xmlHttp, info, this); + } else { + const response = JSON.parse(xmlHttp.responseText); + if (response.errorMessage) { + this.plugins.audio.error.call(this, response.errorMessage, response); + } else { + this.plugins.audio.register.call(this, info, response); + } + } + }, + + register: function (info, response) { + const fileList = response.result; + + for (let i = 0, len = fileList.length, file, oAudio; i < len; i++) { + if (info.isUpdate) oAudio = info.element; + else oAudio = this.plugins.audio._createAudioTag.call(this); + + file = { name: fileList[i].name, size: fileList[i].size }; + this.plugins.audio.create_audio.call(this, oAudio, fileList[i].url, file, info.isUpdate); + } + + this.closeLoading(); + }, + + setupUrl: function (src) { + try { + if (src.length === 0) return false; + this.plugins.audio.create_audio.call(this, this.plugins.audio._createAudioTag.call(this), src, null, this.context.dialog.updateModal); + } catch (error) { + throw Error('[SUNEDITOR.audio.audio.fail] cause : "' + error.message + '"'); + } finally { + this.closeLoading(); + } + }, + + create_audio: function (element, src, file, isUpdate) { + const contextAudio = this.context.audio; + + // create new tag + if (!isUpdate) { + element.src = src; + const cover = this.plugins.component.set_cover.call(this, element); + const container = this.plugins.component.set_container.call(this, cover, ''); + if (!this.insertComponent(container, false, true, !this.options.mediaAutoSelect)) { + this.focus(); + return; + } + if (!this.options.mediaAutoSelect) { + const line = this.appendFormatTag(container, null); + this.setRange(line, 0, line, 0); + } + } // update + else { + if (contextAudio._element) element = contextAudio._element; + if (element && element.src !== src) { + element.src = src; + this.selectComponent(element, 'audio'); + } else { + this.selectComponent(element, 'audio'); + return; + } + } + + this.plugins.fileManager.setInfo.call(this, 'audio', element, this.functions.onAudioUpload, file, false); + if (isUpdate) this.history.push(false); + }, + + updateCover: function (element) { + const contextAudio = this.context.audio; + this.plugins.audio._setTagAttrs.call(this, element); + + // find component element + const existElement = this.util.getParentElement(element, this.util.isMediaComponent) || + this.util.getParentElement(element, function (current) { + return this.isWysiwygDiv(current.parentNode); + }.bind(this.util)); + + // clone element + contextAudio._element = element = element.cloneNode(false); + const cover = this.plugins.component.set_cover.call(this, element); + const container = this.plugins.component.set_container.call(this, cover, 'se-audio-container'); + + existElement.parentNode.replaceChild(container, existElement); + this.plugins.fileManager.setInfo.call(this, 'audio', element, this.functions.onAudioUpload, null, false); + }, + + /** + * @Required @Override fileManager, resizing + */ + onModifyMode: function (selectionTag) { + const contextAudio = this.context.audio; + + this.setControllerPosition(contextAudio.controller, selectionTag, 'bottom', {left: 0, top: 0}); + this.controllersOn(contextAudio.controller, selectionTag, this.plugins.audio.onControllerOff.bind(this, selectionTag), 'audio'); + + this.util.addClass(selectionTag, 'active'); + contextAudio._element = selectionTag; + contextAudio._cover = this.util.getParentElement(selectionTag, 'FIGURE'); + contextAudio._container = this.util.getParentElement(selectionTag, this.util.isComponent); + }, + + /** + * @Required @Override fileManager, resizing + */ + openModify: function (notOpen) { + if (this.context.audio.audioUrlFile) { + const contextAudio = this.context.audio; + contextAudio._linkValue = contextAudio.preview.textContent = contextAudio.audioUrlFile.value = contextAudio._element.src; + } + if (!notOpen) this.plugins.dialog.open.call(this, 'audio', true); + }, + + onClick_controller: function (e) { + e.stopPropagation(); + + const command = e.target.getAttribute('data-command'); + if (!command) return; + + e.preventDefault(); + + if (/update/.test(command)) { + this.plugins.audio.openModify.call(this, false); + } + else { /** delete */ + this.plugins.audio.destroy.call(this, this.context.audio._element); + } + + this.controllersOff(); + }, + + onControllerOff: function (selectionTag) { + this.util.removeClass(selectionTag, 'active'); + this.context.audio.controller.style.display = 'none'; + }, + + /** + * @Required @Override dialog + */ + init: function () { + if (this.context.dialog.updateModal) return; + const contextAudio = this.context.audio; + + if (contextAudio.audioInputFile) contextAudio.audioInputFile.value = ''; + if (contextAudio.audioUrlFile) contextAudio._linkValue = contextAudio.preview.textContent = contextAudio.audioUrlFile.value = ''; + if (contextAudio.audioInputFile && contextAudio.audioUrlFile) { + contextAudio.audioUrlFile.removeAttribute('disabled'); + contextAudio.preview.style.textDecoration = ''; + } + + contextAudio._element = null; + } +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/dialog/image.js": +/*!************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/dialog/image.js ***! + \************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/dialog */ "./node_modules/suneditor/src/plugins/modules/dialog.js"); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_dialog__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _modules_anchor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/_anchor */ "./node_modules/suneditor/src/plugins/modules/_anchor.js"); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/component */ "./node_modules/suneditor/src/plugins/modules/component.js"); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_modules_component__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _modules_resizing__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/resizing */ "./node_modules/suneditor/src/plugins/modules/resizing.js"); +/* harmony import */ var _modules_resizing__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_modules_resizing__WEBPACK_IMPORTED_MODULE_3__); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/fileManager */ "./node_modules/suneditor/src/plugins/modules/fileManager.js"); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_modules_fileManager__WEBPACK_IMPORTED_MODULE_4__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'image', + display: 'dialog', + add: function (core) { + core.addModule([_modules_dialog__WEBPACK_IMPORTED_MODULE_0___default.a, _modules_anchor__WEBPACK_IMPORTED_MODULE_1__["default"], _modules_component__WEBPACK_IMPORTED_MODULE_2___default.a, _modules_resizing__WEBPACK_IMPORTED_MODULE_3___default.a, _modules_fileManager__WEBPACK_IMPORTED_MODULE_4___default.a]); + + const options = core.options; + const context = core.context; + const contextImage = context.image = { + _infoList: [], // @Override fileManager + _infoIndex: 0, // @Override fileManager + _uploadFileLength: 0, // @Override fileManager + focusElement: null, // @Override dialog // This element has focus when the dialog is opened. + sizeUnit: options._imageSizeUnit, + _linkElement: '', + _altText: '', + _align: 'none', + _floatClassRegExp: '__se__float\\-[a-z]+', + _v_src: {_linkValue: ''}, + svgDefaultSize: '30%', + base64RenderIndex: 0, + // @require @Override component + _element: null, + _cover: null, + _container: null, + // @Override resizing properties + inputX: null, + inputY: null, + _element_w: 1, + _element_h: 1, + _element_l: 0, + _element_t: 0, + _defaultSizeX: 'auto', + _defaultSizeY: 'auto', + _origin_w: options.imageWidth === 'auto' ? '' : options.imageWidth, + _origin_h: options.imageHeight === 'auto' ? '' : options.imageHeight, + _proportionChecked: true, + _resizing: options.imageResizing, + _resizeDotHide: !options.imageHeightShow, + _rotation: options.imageRotation, + _onlyPercentage: options.imageSizeOnlyPercentage, + _ratio: false, + _ratioX: 1, + _ratioY: 1, + _captionShow: true, + _captionChecked: false, + _caption: null, + captionCheckEl: null + }; + + /** image dialog */ + let image_dialog = this.setDialog(core); + contextImage.modal = image_dialog; + contextImage.imgInputFile = image_dialog.querySelector('._se_image_file'); + contextImage.imgUrlFile = image_dialog.querySelector('._se_image_url'); + contextImage.focusElement = contextImage.imgInputFile || contextImage.imgUrlFile; + contextImage.altText = image_dialog.querySelector('._se_image_alt'); + contextImage.captionCheckEl = image_dialog.querySelector('._se_image_check_caption'); + contextImage.previewSrc = image_dialog.querySelector('._se_tab_content_image .se-link-preview'); + + /** add event listeners */ + image_dialog.querySelector('.se-dialog-tabs').addEventListener('click', this.openTab.bind(core)); + image_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core)); + if (contextImage.imgInputFile) image_dialog.querySelector('.se-file-remove').addEventListener('click', this._removeSelectedFiles.bind(contextImage.imgInputFile, contextImage.imgUrlFile, contextImage.previewSrc)); + if (contextImage.imgUrlFile) contextImage.imgUrlFile.addEventListener('input', this._onLinkPreview.bind(contextImage.previewSrc, contextImage._v_src, options.linkProtocol)); + if (contextImage.imgInputFile && contextImage.imgUrlFile) contextImage.imgInputFile.addEventListener('change', this._fileInputChange.bind(contextImage)); + + const imageGalleryButton = image_dialog.querySelector('.__se__gallery'); + if (imageGalleryButton) imageGalleryButton.addEventListener('click', this._openGallery.bind(core)); + + contextImage.proportion = {}; + contextImage.inputX = {}; + contextImage.inputY = {}; + if (options.imageResizing) { + contextImage.proportion = image_dialog.querySelector('._se_image_check_proportion'); + contextImage.inputX = image_dialog.querySelector('._se_image_size_x'); + contextImage.inputY = image_dialog.querySelector('._se_image_size_y'); + contextImage.inputX.value = options.imageWidth; + contextImage.inputY.value = options.imageHeight; + + contextImage.inputX.addEventListener('keyup', this.setInputSize.bind(core, 'x')); + contextImage.inputY.addEventListener('keyup', this.setInputSize.bind(core, 'y')); + + contextImage.inputX.addEventListener('change', this.setRatio.bind(core)); + contextImage.inputY.addEventListener('change', this.setRatio.bind(core)); + contextImage.proportion.addEventListener('change', this.setRatio.bind(core)); + + image_dialog.querySelector('.se-dialog-btn-revert').addEventListener('click', this.sizeRevert.bind(core)); + } + + /** append html */ + context.dialog.modal.appendChild(image_dialog); + + /** link event */ + core.plugins.anchor.initEvent.call(core, 'image', image_dialog.querySelector('._se_tab_content_url')); + contextImage.anchorCtx = core.context.anchor.caller.image; + + /** empty memory */ + image_dialog = null; + }, + + /** dialog */ + setDialog: function (core) { + const option = core.options; + const lang = core.lang; + const dialog = core.util.createElement('DIV'); + + dialog.className = 'se-dialog-content se-dialog-image'; + dialog.style.display = 'none'; + + let html = '' + + '
' + + '' + + '' + lang.dialogBox.imageBox.title + '' + + '
' + + '
' + + '' + + '' + + '
' + + '
' + + '
' + + '
'; + + if (option.imageFileInput) { + html += '' + + '
' + + '' + + '
' + + '' + + '' + + '
' + + '
' ; + } + + if (option.imageUrlInput) { + html += '' + + '
' + + '' + + '
' + + '' + + ((option.imageGalleryUrl && core.plugins.imageGallery) ? '' : '') + + '
' + + '' + + '
'; + } + + html += '
' + + '
' + + '' + + '
'; + + if (option.imageResizing) { + const onlyPercentage = option.imageSizeOnlyPercentage; + const onlyPercentDisplay = onlyPercentage ? ' style="display: none !important;"' : ''; + const heightDisplay = !option.imageHeightShow ? ' style="display: none !important;"' : ''; + html += '
'; + if (onlyPercentage || !option.imageHeightShow) { + html += '' + + '
' + + '' + + '
'; + } else { + html += '' + + '
' + + '' + + '' + + '' + + '
'; + } + html += '' + + '' + + '' + + '' + + ' ' + lang.dialogBox.proportion + '' + + '' + + '
' ; + } + + html += '' + + '' + + '
' + + '
' + + '' + + '' + + '
'; + + dialog.innerHTML = html; + + return dialog; + }, + + _fileInputChange: function () { + if (!this.imgInputFile.value) { + this.imgUrlFile.removeAttribute('disabled'); + this.previewSrc.style.textDecoration = ''; + } else { + this.imgUrlFile.setAttribute('disabled', true); + this.previewSrc.style.textDecoration = 'line-through'; + } + }, + + _removeSelectedFiles: function (urlInput, previewSrc) { + this.value = ''; + if (urlInput) { + urlInput.removeAttribute('disabled'); + previewSrc.style.textDecoration = ''; + } + }, + + _openGallery: function () { + this.callPlugin('imageGallery', this.plugins.imageGallery.open.bind(this, this.plugins.image._setUrlInput.bind(this.context.image)), null); + }, + + _setUrlInput: function (target) { + this.altText.value = target.alt; + this._v_src._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.src; + this.imgUrlFile.focus(); + }, + + _onLinkPreview: function (context, protocol, e) { + const value = e.target.value.trim(); + context._linkValue = this.textContent = !value ? '' : (protocol && value.indexOf('://') === -1 && value.indexOf('#') !== 0) ? protocol + value : value.indexOf('://') === -1 ? '/' + value : value; + }, + + /** + * @Override @Required fileManager + */ + fileTags: ['img'], + + /** + * @Override core, fileManager, resizing + * @description It is called from core.selectComponent. + * @param {Element} element Target element + */ + select: function (element) { + this.plugins.image.onModifyMode.call(this, element, this.plugins.resizing.call_controller_resize.call(this, element, 'image')); + }, + + /** + * @Override fileManager, resizing + */ + destroy: function (element) { + const imageEl = element || this.context.image._element; + const imageContainer = this.util.getParentElement(imageEl, this.util.isMediaComponent) || imageEl; + const dataIndex = imageEl.getAttribute('data-index') * 1; + let focusEl = (imageContainer.previousElementSibling || imageContainer.nextElementSibling); + + const emptyDiv = imageContainer.parentNode; + this.util.removeItem(imageContainer); + this.plugins.image.init.call(this); + this.controllersOff(); + + if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null); + + // focus + this.focusEdge(focusEl); + + // event + this.plugins.fileManager.deleteInfo.call(this, 'image', dataIndex, this.functions.onImageUpload); + + // history stack + this.history.push(false); + }, + + /** + * @Required @Override dialog + */ + on: function (update) { + const contextImage = this.context.image; + + if (!update) { + contextImage.inputX.value = contextImage._origin_w = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth; + contextImage.inputY.value = contextImage._origin_h = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight; + if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.setAttribute('multiple', 'multiple'); + } else { + if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.removeAttribute('multiple'); + } + this.plugins.anchor.on.call(this, contextImage.anchorCtx, update); + }, + + /** + * @Required @Override dialog + */ + open: function () { + this.plugins.dialog.open.call(this, 'image', 'image' === this.currentControllerName); + }, + + openTab: function (e) { + const modal = this.context.image.modal; + const targetElement = (e === 'init' ? modal.querySelector('._se_tab_link') : e.target); + + if (!/^BUTTON$/i.test(targetElement.tagName)) { + return false; + } + + // Declare all variables + const tabName = targetElement.getAttribute('data-tab-link'); + const contentClassName = '_se_tab_content'; + let i, tabContent, tabLinks; + + // Get all elements with class="tabcontent" and hide them + tabContent = modal.getElementsByClassName(contentClassName); + for (i = 0; i < tabContent.length; i++) { + tabContent[i].style.display = 'none'; + } + + // Get all elements with class="tablinks" and remove the class "active" + tabLinks = modal.getElementsByClassName('_se_tab_link'); + for (i = 0; i < tabLinks.length; i++) { + this.util.removeClass(tabLinks[i], 'active'); + } + + // Show the current tab, and add an "active" class to the button that opened the tab + modal.querySelector('.' + contentClassName + '_' + tabName).style.display = 'block'; + this.util.addClass(targetElement, 'active'); + + // focus + if (tabName === 'image' && this.context.image.focusElement) { + this.context.image.focusElement.focus(); + } else if (tabName === 'url') { + this.context.anchor.caller.image.urlInput.focus(); + } + + return false; + }, + + submit: function (e) { + const contextImage = this.context.image; + const imagePlugin = this.plugins.image; + + e.preventDefault(); + e.stopPropagation(); + + contextImage._altText = contextImage.altText.value; + contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value; + contextImage._captionChecked = contextImage.captionCheckEl.checked; + if (contextImage._resizing) contextImage._proportionChecked = contextImage.proportion.checked; + + try { + if (this.context.dialog.updateModal) { + imagePlugin.update_image.call(this, false, true, false); + } + + if (contextImage.imgInputFile && contextImage.imgInputFile.files.length > 0) { + this.showLoading(); + imagePlugin.submitAction.call(this, this.context.image.imgInputFile.files); + } else if (contextImage.imgUrlFile && contextImage._v_src._linkValue.length > 0) { + this.showLoading(); + imagePlugin.onRender_imgUrl.call(this); + } + } catch (error) { + this.closeLoading(); + throw Error('[SUNEDITOR.image.submit.fail] cause : "' + error.message + '"'); + } finally { + this.plugins.dialog.close.call(this); + } + + return false; + }, + + submitAction: function (fileList) { + if (fileList.length === 0) return; + + let fileSize = 0; + let files = []; + for (let i = 0, len = fileList.length; i < len; i++) { + if (/image/i.test(fileList[i].type)) { + files.push(fileList[i]); + fileSize += fileList[i].size; + } + } + + const limitSize = this.options.imageUploadSizeLimit; + if (limitSize > 0) { + let infoSize = 0; + const imagesInfo = this.context.image._infoList; + for (let i = 0, len = imagesInfo.length; i < len; i++) { + infoSize += imagesInfo[i].size * 1; + } + + if ((fileSize + infoSize) > limitSize) { + this.closeLoading(); + const err = '[SUNEDITOR.imageUpload.fail] Size of uploadable total images: ' + (limitSize/1000) + 'KB'; + if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(err, { 'limitSize': limitSize, 'currentSize': infoSize, 'uploadSize': fileSize }, this)) { + this.functions.noticeOpen(err); + } + return; + } + } + + const contextImage = this.context.image; + contextImage._uploadFileLength = files.length; + + const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true); + const info = { + anchor: anchor, + inputWidth: contextImage.inputX.value, + inputHeight: contextImage.inputY.value, + align: contextImage._align, + isUpdate: this.context.dialog.updateModal, + element: contextImage._element + }; + + if (typeof this.functions.onImageUploadBefore === 'function') { + const result = this.functions.onImageUploadBefore(files, info, this, function (data) { + if (data && this._w.Array.isArray(data.result)) { + this.plugins.image.register.call(this, info, data); + } else { + this.plugins.image.upload.call(this, info, data); + } + }.bind(this)); + + if (typeof result === 'undefined') return; + if (!result) { + this.closeLoading(); + return; + } + if (this._w.Array.isArray(result) && result.length > 0) files = result; + } + + this.plugins.image.upload.call(this, info, files); + }, + + error: function (message, response) { + this.closeLoading(); + if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(message, response, this)) { + this.functions.noticeOpen(message); + throw Error('[SUNEDITOR.plugin.image.error] response: ' + message); + } + }, + + upload: function (info, files) { + if (!files) { + this.closeLoading(); + return; + } + if (typeof files === 'string') { + this.plugins.image.error.call(this, files, null); + return; + } + + const imageUploadUrl = this.options.imageUploadUrl; + const filesLen = this.context.dialog.updateModal ? 1 : files.length; + + // server upload + if (typeof imageUploadUrl === 'string' && imageUploadUrl.length > 0) { + const formData = new FormData(); + for (let i = 0; i < filesLen; i++) { + formData.append('file-' + i, files[i]); + } + this.plugins.fileManager.upload.call(this, imageUploadUrl, this.options.imageUploadHeader, formData, this.plugins.image.callBack_imgUpload.bind(this, info), this.functions.onImageUploadError); + } else { // base64 + this.plugins.image.setup_reader.call(this, files, info.anchor, info.inputWidth, info.inputHeight, info.align, filesLen, info.isUpdate); + } + }, + + callBack_imgUpload: function (info, xmlHttp) { + if (typeof this.functions.imageUploadHandler === 'function') { + this.functions.imageUploadHandler(xmlHttp, info, this); + } else { + const response = JSON.parse(xmlHttp.responseText); + if (response.errorMessage) { + this.plugins.image.error.call(this, response.errorMessage, response); + } else { + this.plugins.image.register.call(this, info, response); + } + } + }, + + register: function (info, response) { + const fileList = response.result; + + for (let i = 0, len = fileList.length, file; i < len; i++) { + file = { name: fileList[i].name, size: fileList[i].size }; + if (info.isUpdate) { + this.plugins.image.update_src.call(this, fileList[i].url, info.element, file); + break; + } else { + this.plugins.image.create_image.call(this, fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file); + } + } + + this.closeLoading(); + }, + + setup_reader: function (files, anchor, width, height, align, filesLen, isUpdate) { + try { + this.context.image.base64RenderIndex = filesLen; + const wFileReader = this._w.FileReader; + const filesStack = [filesLen]; + this.context.image.inputX.value = width; + this.context.image.inputY.value = height; + + for (let i = 0, reader, file; i < filesLen; i++) { + reader = new wFileReader(); + file = files[i]; + + reader.onload = function (reader, update, updateElement, file, index) { + filesStack[index] = { result: reader.result, file: file }; + + if (--this.context.image.base64RenderIndex === 0) { + this.plugins.image.onRender_imgBase64.call(this, update, filesStack, updateElement, anchor, width, height, align); + this.closeLoading(); + } + }.bind(this, reader, isUpdate, this.context.image._element, file, i); + + reader.readAsDataURL(file); + } + } catch (e) { + this.closeLoading(); + throw Error('[SUNEDITOR.image.setup_reader.fail] cause : "' + e.message + '"'); + } + }, + + onRender_imgBase64: function (update, filesStack, updateElement, anchor, width, height, align) { + const updateMethod = this.plugins.image.update_src; + const createMethod = this.plugins.image.create_image; + + for (let i = 0, len = filesStack.length; i < len; i++) { + if (update) { + this.context.image._element.setAttribute('data-file-name', filesStack[i].file.name); + this.context.image._element.setAttribute('data-file-size', filesStack[i].file.size); + updateMethod.call(this, filesStack[i].result, updateElement, filesStack[i].file); + } else { + createMethod.call(this, filesStack[i].result, anchor, width, height, align, filesStack[i].file); + } + } + }, + + onRender_imgUrl: function () { + const contextImage = this.context.image; + if (contextImage._v_src._linkValue.length === 0) return false; + + try { + const file = {name: contextImage._v_src._linkValue.split('/').pop(), size: 0}; + if (this.context.dialog.updateModal) this.plugins.image.update_src.call(this, contextImage._v_src._linkValue, contextImage._element, file); + else this.plugins.image.create_image.call(this, contextImage._v_src._linkValue, this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true), contextImage.inputX.value, contextImage.inputY.value, contextImage._align, file); + } catch (e) { + throw Error('[SUNEDITOR.image.URLRendering.fail] cause : "' + e.message + '"'); + } finally { + this.closeLoading(); + } + }, + + onRender_link: function (imgTag, anchor) { + if (anchor) { + anchor.setAttribute('data-image-link', 'image'); + imgTag.setAttribute('data-image-link', anchor.href); + anchor.appendChild(imgTag); + return anchor; + } + + return imgTag; + }, + + /** + * @Override resizing + * @param {String} xy 'x': width, 'y': height + * @param {KeyboardEvent} e Event object + */ + setInputSize: function (xy, e) { + if (e && e.keyCode === 32) { + e.preventDefault(); + return; + } + + this.plugins.resizing._module_setInputSize.call(this, this.context.image, xy); + }, + + /** + * @Override resizing + */ + setRatio: function () { + this.plugins.resizing._module_setRatio.call(this, this.context.image); + }, + + /** + * @Override fileManager + */ + checkFileInfo: function () { + const imagePlugin = this.plugins.image; + + const modifyHandler = function (tag) { + imagePlugin.onModifyMode.call(this, tag, null); + imagePlugin.openModify.call(this, true); + imagePlugin.update_image.call(this, true, false, true); + }.bind(this); + + this.plugins.fileManager.checkInfo.call(this, 'image', ['img'], this.functions.onImageUpload, modifyHandler, true); + }, + + /** + * @Override fileManager + */ + resetFileInfo: function () { + this.plugins.fileManager.resetInfo.call(this, 'image', this.functions.onImageUpload); + }, + + create_image: function (src, anchor, width, height, align, file) { + const imagePlugin = this.plugins.image; + const contextImage = this.context.image; + this.context.resizing._resize_plugin = 'image'; + + let oImg = this.util.createElement('IMG'); + oImg.src = src; + oImg.alt = contextImage._altText; + oImg.setAttribute('data-rotate', '0'); + anchor = imagePlugin.onRender_link.call(this, oImg, anchor); + + if (contextImage._resizing) { + oImg.setAttribute('data-proportion', contextImage._proportionChecked); + } + + const cover = this.plugins.component.set_cover.call(this, anchor); + const container = this.plugins.component.set_container.call(this, cover, 'se-image-container'); + + // caption + if (contextImage._captionChecked) { + contextImage._caption = this.plugins.component.create_caption.call(this); + contextImage._caption.setAttribute('contenteditable', false); + cover.appendChild(contextImage._caption); + } + + contextImage._element = oImg; + contextImage._cover = cover; + contextImage._container = container; + + // set size + imagePlugin.applySize.call(this, width, height); + + // align + imagePlugin.setAlign.call(this, align, oImg, cover, container); + + oImg.onload = imagePlugin._image_create_onload.bind(this, oImg, contextImage.svgDefaultSize, container); + if (this.insertComponent(container, true, true, true)) this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true); + this.context.resizing._resize_plugin = ''; + }, + + _image_create_onload: function (oImg, svgDefaultSize, container) { + // svg exception handling + if (oImg.offsetWidth === 0) this.plugins.image.applySize.call(this, svgDefaultSize, ''); + if (this.options.mediaAutoSelect) { + this.selectComponent(oImg, 'image'); + } else { + const line = this.appendFormatTag(container, null); + this.setRange(line, 0, line, 0); + } + }, + + update_image: function (init, openController, notHistoryPush) { + const contextImage = this.context.image; + let imageEl = contextImage._element; + let cover = contextImage._cover; + let container = contextImage._container; + let isNewContainer = false; + + if (cover === null) { + isNewContainer = true; + imageEl = contextImage._element.cloneNode(true); + cover = this.plugins.component.set_cover.call(this, imageEl); + } + + if (container === null) { + cover = cover.cloneNode(true); + imageEl = cover.querySelector('img'); + isNewContainer = true; + container = this.plugins.component.set_container.call(this, cover, 'se-image-container'); + } else if (isNewContainer) { + container.innerHTML = ''; + container.appendChild(cover); + contextImage._cover = cover; + contextImage._element = imageEl; + isNewContainer = false; + } + + // check size + let changeSize; + const x = this.util.isNumber(contextImage.inputX.value) ? contextImage.inputX.value + contextImage.sizeUnit : contextImage.inputX.value; + const y = this.util.isNumber(contextImage.inputY.value) ? contextImage.inputY.value + contextImage.sizeUnit : contextImage.inputY.value; + if (/%$/.test(imageEl.style.width)) { + changeSize = x !== container.style.width || y !== container.style.height; + } else { + changeSize = x !== imageEl.style.width || y !== imageEl.style.height; + } + + // alt + imageEl.alt = contextImage._altText; + + // caption + let modifiedCaption = false; + if (contextImage._captionChecked) { + if (!contextImage._caption) { + contextImage._caption = this.plugins.component.create_caption.call(this); + cover.appendChild(contextImage._caption); + modifiedCaption = true; + } + } else { + if (contextImage._caption) { + this.util.removeItem(contextImage._caption); + contextImage._caption = null; + modifiedCaption = true; + } + } + + // link + const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true); + if (anchor) { + contextImage._linkElement = anchor; + cover.insertBefore(this.plugins.image.onRender_link.call(this, imageEl, anchor), contextImage._caption); + } else if (contextImage._linkElement !== null) { + const imageElement = imageEl; + + imageElement.setAttribute('data-image-link', ''); + const newEl = imageElement.cloneNode(true); + cover.removeChild(contextImage._linkElement); + cover.insertBefore(newEl, contextImage._caption); + imageEl = newEl; + } + + if (isNewContainer) { + const existElement = (this.util.isRangeFormatElement(contextImage._element.parentNode) || this.util.isWysiwygDiv(contextImage._element.parentNode)) ? + contextImage._element : + /^A$/i.test(contextImage._element.parentNode.nodeName) ? contextImage._element.parentNode : this.util.getFormatElement(contextImage._element) || contextImage._element; + + if (this.util.isFormatElement(existElement) && existElement.textContent.length > 0) { + existElement.parentNode.insertBefore(container, existElement.nextElementSibling); + this.util.removeItem(contextImage._element); + } else { + existElement.parentNode.replaceChild(container, existElement); + } + + imageEl = container.querySelector('img'); + + contextImage._element = imageEl; + contextImage._cover = cover; + contextImage._container = container; + } + + // transform + if (modifiedCaption || (!contextImage._onlyPercentage && changeSize)) { + if (!init && (/\d+/.test(imageEl.style.height) || (this.context.resizing._rotateVertical && contextImage._captionChecked))) { + if (/%$/.test(contextImage.inputX.value) || /%$/.test(contextImage.inputY.value)) { + this.plugins.resizing.resetTransform.call(this, imageEl); + } else { + this.plugins.resizing.setTransformSize.call(this, imageEl, this.util.getNumber(contextImage.inputX.value, 0), this.util.getNumber(contextImage.inputY.value, 0)); + } + } + } + + // size + let isPercent = false; + if (contextImage._resizing) { + imageEl.setAttribute('data-proportion', contextImage._proportionChecked); + if (changeSize) { + this.plugins.image.applySize.call(this); + } + } + + // align + if (!(isPercent && contextImage._align === 'center')) { + this.plugins.image.setAlign.call(this, null, imageEl, null, null); + } + + // set imagesInfo + if (init) { + this.plugins.fileManager.setInfo.call(this, 'image', imageEl, this.functions.onImageUpload, null, true); + } + + if (openController) { + this.selectComponent(imageEl, 'image'); + } + + // history stack + if (!notHistoryPush) this.history.push(false); + }, + + update_src: function (src, element, file) { + element.src = src; + this._w.setTimeout(this.plugins.fileManager.setInfo.bind(this, 'image', element, this.functions.onImageUpload, file, true)); + this.selectComponent(element, 'image'); + }, + + /** + * @Required @Override fileManager, resizing + */ + onModifyMode: function (element, size) { + if (!element) return; + + const contextImage = this.context.image; + contextImage._linkElement = contextImage.anchorCtx.linkAnchor = /^A$/i.test(element.parentNode.nodeName) ? element.parentNode : null; + contextImage._element = element; + contextImage._cover = this.util.getParentElement(element, 'FIGURE'); + contextImage._container = this.util.getParentElement(element, this.util.isMediaComponent); + contextImage._caption = this.util.getChildElement(contextImage._cover, 'FIGCAPTION'); + contextImage._align = element.style.float || element.getAttribute('data-align') || 'none'; + element.style.float = ''; + + if (size) { + contextImage._element_w = size.w; + contextImage._element_h = size.h; + contextImage._element_t = size.t; + contextImage._element_l = size.l; + } + + let userSize = contextImage._element.getAttribute('data-size') || contextImage._element.getAttribute('data-origin'); + if (userSize) { + userSize = userSize.split(','); + contextImage._origin_w = userSize[0]; + contextImage._origin_h = userSize[1]; + } else if (size) { + contextImage._origin_w = size.w; + contextImage._origin_h = size.h; + } + }, + + /** + * @Required @Override fileManager, resizing + */ + openModify: function (notOpen) { + const contextImage = this.context.image; + if (contextImage.imgUrlFile) { + contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = contextImage._element.src; + } + contextImage._altText = contextImage.altText.value = contextImage._element.alt; + contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="' + contextImage._align + '"]').checked = true; + contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value; + contextImage._captionChecked = contextImage.captionCheckEl.checked = !!contextImage._caption; + + if (contextImage._resizing) { + this.plugins.resizing._module_setModifyInputSize.call(this, contextImage, this.plugins.image); + } + + if (!notOpen) this.plugins.dialog.open.call(this, 'image', true); + }, + + /** + * @Override fileManager + */ + applySize: function (w, h) { + const contextImage = this.context.image; + + if (!w) w = contextImage.inputX.value || this.options.imageWidth; + if (!h) h = contextImage.inputY.value || this.options.imageHeight; + + if ((contextImage._onlyPercentage && !!w) || /%$/.test(w)) { + this.plugins.image.setPercentSize.call(this, w, h); + return true; + } else if ((!w || w === 'auto') && (!h || h === 'auto')) { + this.plugins.image.setAutoSize.call(this); + } else { + this.plugins.image.setSize.call(this, w, h, false); + } + + return false; + }, + + /** + * @Override resizing + */ + sizeRevert: function () { + this.plugins.resizing._module_sizeRevert.call(this, this.context.image); + }, + + /** + * @Override resizing + */ + setSize: function (w, h, notResetPercentage, direction) { + const contextImage = this.context.image; + const onlyW = /^(rw|lw)$/.test(direction); + const onlyH = /^(th|bh)$/.test(direction); + + if (!onlyH) { + contextImage._element.style.width = this.util.isNumber(w) ? w + contextImage.sizeUnit : w; + this.plugins.image.cancelPercentAttr.call(this); + } + if (!onlyW) { + contextImage._element.style.height = this.util.isNumber(h) ? h + contextImage.sizeUnit : /%$/.test(h) ? '' : h; + } + + if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null); + if (!notResetPercentage) contextImage._element.removeAttribute('data-percentage'); + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextImage); + }, + + /** + * @Override resizing + */ + setAutoSize: function () { + const contextImage = this.context.image; + + this.plugins.resizing.resetTransform.call(this, contextImage._element); + this.plugins.image.cancelPercentAttr.call(this); + + contextImage._element.style.maxWidth = ''; + contextImage._element.style.width = ''; + contextImage._element.style.height = ''; + contextImage._cover.style.width = ''; + contextImage._cover.style.height = ''; + + this.plugins.image.setAlign.call(this, null, null, null, null); + contextImage._element.setAttribute('data-percentage', 'auto,auto'); + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextImage); + }, + + /** + * @Override resizing + */ + setOriginSize: function () { + const contextImage = this.context.image; + contextImage._element.removeAttribute('data-percentage'); + + this.plugins.resizing.resetTransform.call(this, contextImage._element); + this.plugins.image.cancelPercentAttr.call(this); + + const originSize = (contextImage._element.getAttribute('data-origin') || '').split(','); + const w = originSize[0]; + const h = originSize[1]; + + if (originSize) { + if (contextImage._onlyPercentage || (/%$/.test(w) && (/%$/.test(h) || !/\d/.test(h)))) { + this.plugins.image.setPercentSize.call(this, w, h); + } else { + this.plugins.image.setSize.call(this, w, h); + } + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextImage); + } + }, + + /** + * @Override resizing + */ + setPercentSize: function (w, h) { + const contextImage = this.context.image; + h = !!h && !/%$/.test(h) && !this.util.getNumber(h, 0) ? this.util.isNumber(h) ? h + '%' : h : this.util.isNumber(h) ? h + contextImage.sizeUnit : (h || ''); + const heightPercentage = /%$/.test(h); + + contextImage._container.style.width = this.util.isNumber(w) ? w + '%' : w; + contextImage._container.style.height = ''; + contextImage._cover.style.width = '100%'; + contextImage._cover.style.height = !heightPercentage ? '' : h; + contextImage._element.style.width = '100%'; + contextImage._element.style.height = heightPercentage ? '' : h; + contextImage._element.style.maxWidth = ''; + + if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null); + + contextImage._element.setAttribute('data-percentage', w + ',' + h); + this.plugins.resizing.setCaptionPosition.call(this, contextImage._element); + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextImage); + }, + + /** + * @Override resizing + */ + cancelPercentAttr: function () { + const contextImage = this.context.image; + + contextImage._cover.style.width = ''; + contextImage._cover.style.height = ''; + contextImage._container.style.width = ''; + contextImage._container.style.height = ''; + + this.util.removeClass(contextImage._container, this.context.image._floatClassRegExp); + this.util.addClass(contextImage._container, '__se__float-' + contextImage._align); + + if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null); + }, + + /** + * @Override resizing + */ + setAlign: function (align, element, cover, container) { + const contextImage = this.context.image; + + if (!align) align = contextImage._align; + if (!element) element = contextImage._element; + if (!cover) cover = contextImage._cover; + if (!container) container = contextImage._container; + + if (align && align !== 'none') { + cover.style.margin = 'auto'; + } else { + cover.style.margin = '0'; + } + + if (/%$/.test(element.style.width) && align === 'center') { + container.style.minWidth = '100%'; + cover.style.width = container.style.width; + } else { + container.style.minWidth = ''; + cover.style.width = this.context.resizing._rotateVertical ? (element.style.height || element.offsetHeight) : ((!element.style.width || element.style.width === 'auto') ? '' : element.style.width || '100%'); + } + + if (!this.util.hasClass(container, '__se__float-' + align)) { + this.util.removeClass(container, contextImage._floatClassRegExp); + this.util.addClass(container, '__se__float-' + align); + } + + element.setAttribute('data-align', align); + }, + + /** + * @Override dialog + */ + init: function () { + const contextImage = this.context.image; + if (contextImage.imgInputFile) contextImage.imgInputFile.value = ''; + if (contextImage.imgUrlFile) contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = ''; + if (contextImage.imgInputFile && contextImage.imgUrlFile) { + contextImage.imgUrlFile.removeAttribute('disabled'); + contextImage.previewSrc.style.textDecoration = ''; + } + + contextImage.altText.value = ''; + contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]').checked = true; + contextImage.captionCheckEl.checked = false; + contextImage._element = null; + this.plugins.image.openTab.call(this, 'init'); + + if (contextImage._resizing) { + contextImage.inputX.value = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth; + contextImage.inputY.value = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight; + contextImage.proportion.checked = true; + contextImage._ratio = false; + contextImage._ratioX = 1; + contextImage._ratioY = 1; + } + + this.plugins.anchor.init.call(this, contextImage.anchorCtx); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/dialog/link.js": +/*!***********************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/dialog/link.js ***! + \***********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/dialog */ "./node_modules/suneditor/src/plugins/modules/dialog.js"); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_dialog__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _modules_anchor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/_anchor */ "./node_modules/suneditor/src/plugins/modules/_anchor.js"); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'link', + display: 'dialog', + add: function (core) { + core.addModule([_modules_dialog__WEBPACK_IMPORTED_MODULE_0___default.a, _modules_anchor__WEBPACK_IMPORTED_MODULE_1__["default"]]); + + const context = core.context; + const contextLink = context.link = { + focusElement: null, // @Override dialog // This element has focus when the dialog is opened. + _linkAnchor: null, + anchorCtx: null + }; + + /** link dialog */ + let link_dialog = this.setDialog(core); + contextLink.modal = link_dialog; + + /** link controller */ + let link_controller = this.setController_LinkButton(core); + contextLink.linkController = link_controller; + + link_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core)); + link_controller.addEventListener('click', this.onClick_linkController.bind(core)); + + /** append html */ + context.dialog.modal.appendChild(link_dialog); + + /** append controller */ + context.element.relative.appendChild(link_controller); + + /** link event */ + core.plugins.anchor.initEvent.call(core, 'link', link_dialog); + contextLink.focusElement = context.anchor.caller.link.urlInput; + + /** empty memory */ + link_dialog = null, link_controller = null; + }, + + /** dialog */ + setDialog: function (core) { + const lang = core.lang; + const dialog = core.util.createElement('DIV'); + const icons = core.icons; + + dialog.className = 'se-dialog-content'; + dialog.style.display = 'none'; + let html = '' + + '
' + + '
' + + '' + + '' + lang.dialogBox.linkBox.title + '' + + '
' + + core.context.anchor.forms.innerHTML + + '' + + '
'; + + dialog.innerHTML = html; + return dialog; + }, + + /** modify controller button */ + setController_LinkButton: function (core) { + const lang = core.lang; + const icons = core.icons; + const link_btn = core.util.createElement('DIV'); + + link_btn.className = 'se-controller se-controller-link'; + link_btn.innerHTML = '' + + '
' + + ''; + + return link_btn; + }, + + /** + * @Override dialog + */ + open: function () { + this.plugins.dialog.open.call(this, 'link', 'link' === this.currentControllerName); + }, + + submit: function (e) { + this.showLoading(); + + e.preventDefault(); + e.stopPropagation(); + + try { + const oA = this.plugins.anchor.createAnchor.call(this, this.context.anchor.caller.link, false); + + if (!this.context.dialog.updateModal) { + const selectedFormats = this.getSelectedElements(); + if (selectedFormats.length > 1) { + const oFormat = this.util.createElement(selectedFormats[0].nodeName); + oFormat.appendChild(oA); + if (!this.insertNode(oFormat, null, true)) return; + } else { + if (!this.insertNode(oA, null, true)) return; + } + + this.setRange(oA.childNodes[0], 0, oA.childNodes[0], oA.textContent.length); + } else { + // set range + const textNode = this.context.link._linkAnchor.childNodes[0]; + this.setRange(textNode, 0, textNode, textNode.textContent.length); + } + } finally { + this.plugins.dialog.close.call(this); + this.closeLoading(); + // history stack + this.history.push(false); + } + + return false; + }, + + /** + * @Override core + */ + active: function (element) { + if (!element) { + if (this.controllerArray.indexOf(this.context.link.linkController) > -1) { + this.controllersOff(); + } + } else if (this.util.isAnchor(element) && element.getAttribute('data-image-link') === null) { + if (this.controllerArray.indexOf(this.context.link.linkController) < 0) { + this.plugins.link.call_controller.call(this, element); + } + return true; + } + + return false; + }, + + /** + * @Override dialog + */ + on: function (update) { + this.plugins.anchor.on.call(this, this.context.anchor.caller.link, update); + }, + + call_controller: function (selectionATag) { + this.editLink = this.context.link._linkAnchor = this.context.anchor.caller.link.linkAnchor = selectionATag; + const linkBtn = this.context.link.linkController; + const link = linkBtn.querySelector('a'); + + link.href = selectionATag.href; + link.title = selectionATag.textContent; + link.textContent = selectionATag.textContent; + + this.util.addClass(selectionATag, 'on'); + this.setControllerPosition(linkBtn, selectionATag, 'bottom', {left: 0, top: 0}); + this.controllersOn(linkBtn, selectionATag, 'link', this.util.removeClass.bind(this.util, this.context.link._linkAnchor, 'on')); + }, + + onClick_linkController: function (e) { + e.stopPropagation(); + + const command = e.target.getAttribute('data-command') || e.target.parentNode.getAttribute('data-command'); + if (!command) return; + + e.preventDefault(); + + if (/update/.test(command)) { + this.plugins.dialog.open.call(this, 'link', true); + } else if (/unlink/.test(command)) { + const sc = this.util.getChildElement(this.context.link._linkAnchor, function (current) { return current.childNodes.length === 0 || current.nodeType === 3; }, false); + const ec = this.util.getChildElement(this.context.link._linkAnchor, function (current) { return current.childNodes.length === 0 || current.nodeType === 3; }, true); + this.setRange(sc, 0, ec, ec.textContent.length); + this.nodeChange(null, null, ['A'], false); + } else { + /** delete */ + this.util.removeItem(this.context.link._linkAnchor); + this.context.anchor.caller.link.linkAnchor = null; + this.focus(); + + // history stack + this.history.push(false); + } + + this.controllersOff(); + }, + + /** + * @Override dialog + */ + init: function () { + this.context.link.linkController.style.display = 'none'; + this.plugins.anchor.init.call(this, this.context.anchor.caller.link); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/dialog/math.js": +/*!***********************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/dialog/math.js ***! + \***********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/dialog */ "./node_modules/suneditor/src/plugins/modules/dialog.js"); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_dialog__WEBPACK_IMPORTED_MODULE_0__); + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'math', + display: 'dialog', + add: function (core) { + core.addModule([_modules_dialog__WEBPACK_IMPORTED_MODULE_0___default.a]); + + const context = core.context; + context.math = { + focusElement: null, // @Override dialog // This element has focus when the dialog is opened. + previewElement: null, + fontSizeElement: null, + _mathExp: null + }; + + /** math dialog */ + let math_dialog = this.setDialog(core); + context.math.modal = math_dialog; + context.math.focusElement = math_dialog.querySelector('.se-math-exp'); + context.math.previewElement = math_dialog.querySelector('.se-math-preview'); + context.math.fontSizeElement = math_dialog.querySelector('.se-math-size'); + context.math.focusElement.addEventListener('keyup', this._renderMathExp.bind(core, context.math), false); + context.math.focusElement.addEventListener('change', this._renderMathExp.bind(core, context.math), false); + context.math.fontSizeElement.addEventListener('change', function (e) { this.fontSize = e.target.value; }.bind(context.math.previewElement.style), false); + + /** math controller */ + let math_controller = this.setController_MathButton(core); + context.math.mathController = math_controller; + context.math._mathExp = null; + + /** add event listeners */ + math_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core), false); + math_controller.addEventListener('click', this.onClick_mathController.bind(core)); + + /** append html */ + context.dialog.modal.appendChild(math_dialog); + context.element.relative.appendChild(math_controller); + + /** empty memory */ + math_dialog = null, math_controller = null; + }, + + /** dialog */ + setDialog: function (core) { + const lang = core.lang; + const dialog = core.util.createElement('DIV'); + + dialog.className = 'se-dialog-content'; + dialog.style.display = 'none'; + dialog.innerHTML = '' + + '
' + + '
' + + '' + + '' + lang.dialogBox.mathBox.title + '' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '
' + + '' + + '' + + '
' + + '
' + + '' + + '

' + + '
' + + '
' + + '' + + '
'; + + return dialog; + }, + + /** modify controller button */ + setController_MathButton: function (core) { + const lang = core.lang; + const math_btn = core.util.createElement('DIV'); + + math_btn.className = 'se-controller se-controller-link'; + math_btn.innerHTML = '' + + '
' + + '' + + ''; + + return math_btn; + }, + + /** + * @Required @Override dialog + */ + open: function () { + this.plugins.dialog.open.call(this, 'math', 'math' === this.currentControllerName); + }, + + /** + * @Override core - managedTagsInfo + */ + managedTags: function () { + return { + className: 'katex', + method: function (element) { + if (!element.getAttribute('data-exp')) return; + const dom = this._d.createRange().createContextualFragment(this.plugins.math._renderer.call(this, this.util.HTMLDecoder(element.getAttribute('data-exp')))); + element.innerHTML = dom.querySelector('.katex').innerHTML; + } + }; + }, + + _renderer: function (exp) { + const katex = this.options.katex; + return katex.src.renderToString(exp, katex.options); + }, + + _renderMathExp: function (contextMath, e) { + contextMath.previewElement.innerHTML = this.plugins.math._renderer.call(this, e.target.value); + }, + + submit: function (e) { + this.showLoading(); + + e.preventDefault(); + e.stopPropagation(); + + const submitAction = function () { + if (this.context.math.focusElement.value.trim().length === 0) return false; + + const contextMath = this.context.math; + const mathExp = contextMath.focusElement.value; + const katexEl = contextMath.previewElement.querySelector('.katex'); + + if (!katexEl) return false; + katexEl.className = '__se__katex ' + katexEl.className; + katexEl.setAttribute('contenteditable', false); + katexEl.setAttribute('data-exp', this.util.HTMLEncoder(mathExp)); + katexEl.setAttribute('data-font-size', contextMath.fontSizeElement.value); + katexEl.style.fontSize = contextMath.fontSizeElement.value; + + if (!this.context.dialog.updateModal) { + const selectedFormats = this.getSelectedElements(); + + if (selectedFormats.length > 1) { + const oFormat = this.util.createElement(selectedFormats[0].nodeName); + oFormat.appendChild(katexEl); + if (!this.insertNode(oFormat, null, true)) return false; + } else { + if (!this.insertNode(katexEl, null, true)) return false; + } + + const empty = this.util.createTextNode(this.util.zeroWidthSpace); + katexEl.parentNode.insertBefore(empty, katexEl.nextSibling); + this.setRange(katexEl, 0, katexEl, 1); + } else { + const containerEl = this.util.getParentElement(contextMath._mathExp, '.katex'); + containerEl.parentNode.replaceChild(katexEl, containerEl); + this.setRange(katexEl, 0, katexEl, 1); + } + + contextMath.focusElement.value = ''; + contextMath.fontSizeElement.value = '1em'; + contextMath.previewElement.style.fontSize = '1em'; + contextMath.previewElement.innerHTML = ''; + + return true; + }.bind(this); + + try { + if (submitAction()) { + this.plugins.dialog.close.call(this); + // history stack + this.history.push(false); + } + } catch (e) { + this.plugins.dialog.close.call(this); + } finally { + this.closeLoading(); + } + + return false; + }, + + active: function (element) { + if (!element) { + if (this.controllerArray.indexOf(this.context.math.mathController) > -1) { + this.controllersOff(); + } + } else if (element.getAttribute('data-exp')) { + if (this.controllerArray.indexOf(this.context.math.mathController) < 0) { + this.setRange(element, 0, element, 1); + this.plugins.math.call_controller.call(this, element); + } + return true; + } + + return false; + }, + + on: function (update) { + if (!update) { + this.plugins.math.init.call(this); + } else { + const contextMath = this.context.math; + if (contextMath._mathExp) { + const exp = this.util.HTMLDecoder(contextMath._mathExp.getAttribute('data-exp')); + const fontSize = contextMath._mathExp.getAttribute('data-font-size') || '1em'; + this.context.dialog.updateModal = true; + contextMath.focusElement.value = exp; + contextMath.fontSizeElement.value = fontSize; + contextMath.previewElement.innerHTML = this.plugins.math._renderer.call(this, exp); + contextMath.previewElement.style.fontSize = fontSize; + } + } + }, + + call_controller: function (mathTag) { + this.context.math._mathExp = mathTag; + const mathBtn = this.context.math.mathController; + + this.setControllerPosition(mathBtn, mathTag, 'bottom', {left: 0, top: 0}); + this.controllersOn(mathBtn, mathTag, 'math'); + }, + + onClick_mathController: function (e) { + e.stopPropagation(); + + const command = e.target.getAttribute('data-command') || e.target.parentNode.getAttribute('data-command'); + if (!command) return; + + e.preventDefault(); + + if (/update/.test(command)) { + this.context.math.focusElement.value = this.util.HTMLDecoder(this.context.math._mathExp.getAttribute('data-exp')); + this.plugins.dialog.open.call(this, 'math', true); + } else { + /** delete */ + this.util.removeItem(this.context.math._mathExp); + this.context.math._mathExp = null; + this.focus(); + + // history stack + this.history.push(false); + } + + this.controllersOff(); + }, + + init: function () { + const contextMath = this.context.math; + contextMath.mathController.style.display = 'none'; + contextMath._mathExp = null; + contextMath.focusElement.value = ''; + contextMath.previewElement.innerHTML = ''; + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/dialog/video.js": +/*!************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/dialog/video.js ***! + \************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/dialog */ "./node_modules/suneditor/src/plugins/modules/dialog.js"); +/* harmony import */ var _modules_dialog__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_dialog__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/component */ "./node_modules/suneditor/src/plugins/modules/component.js"); +/* harmony import */ var _modules_component__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_modules_component__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var _modules_resizing__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/resizing */ "./node_modules/suneditor/src/plugins/modules/resizing.js"); +/* harmony import */ var _modules_resizing__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_modules_resizing__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/fileManager */ "./node_modules/suneditor/src/plugins/modules/fileManager.js"); +/* harmony import */ var _modules_fileManager__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_modules_fileManager__WEBPACK_IMPORTED_MODULE_3__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'video', + display: 'dialog', + add: function (core) { + core.addModule([_modules_dialog__WEBPACK_IMPORTED_MODULE_0___default.a, _modules_component__WEBPACK_IMPORTED_MODULE_1___default.a, _modules_resizing__WEBPACK_IMPORTED_MODULE_2___default.a, _modules_fileManager__WEBPACK_IMPORTED_MODULE_3___default.a]); + + const options = core.options; + const context = core.context; + const contextVideo = context.video = { + _infoList: [], // @Override fileManager + _infoIndex: 0, // @Override fileManager + _uploadFileLength: 0, // @Override fileManager + focusElement: null, // @Override dialog // This element has focus when the dialog is opened. + sizeUnit: options._videoSizeUnit, + _align: 'none', + _floatClassRegExp: '__se__float\\-[a-z]+', + _youtubeQuery: options.youtubeQuery, + _videoRatio: (options.videoRatio * 100) + '%', + _defaultRatio: (options.videoRatio * 100) + '%', + _linkValue: '', + // @require @Override component + _element: null, + _cover: null, + _container: null, + // @Override resizing properties + inputX: null, + inputY: null, + _element_w: 1, + _element_h: 1, + _element_l: 0, + _element_t: 0, + _defaultSizeX: '100%', + _defaultSizeY: (options.videoRatio * 100) + '%', + _origin_w: options.videoWidth === '100%' ? '' : options.videoWidth, + _origin_h: options.videoHeight === '56.25%' ? '' : options.videoHeight, + _proportionChecked: true, + _resizing: options.videoResizing, + _resizeDotHide: !options.videoHeightShow, + _rotation: options.videoRotation, + _onlyPercentage: options.videoSizeOnlyPercentage, + _ratio: false, + _ratioX: 1, + _ratioY: 1, + _captionShow: false + }; + + /** video dialog */ + let video_dialog = this.setDialog(core); + contextVideo.modal = video_dialog; + contextVideo.videoInputFile = video_dialog.querySelector('._se_video_file'); + contextVideo.videoUrlFile = video_dialog.querySelector('.se-input-url'); + contextVideo.focusElement = contextVideo.videoUrlFile || contextVideo.videoInputFile; + contextVideo.preview = video_dialog.querySelector('.se-link-preview'); + + /** add event listeners */ + video_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core)); + if (contextVideo.videoInputFile) video_dialog.querySelector('.se-dialog-files-edge-button').addEventListener('click', this._removeSelectedFiles.bind(contextVideo.videoInputFile, contextVideo.videoUrlFile, contextVideo.preview)); + if (contextVideo.videoInputFile && contextVideo.videoUrlFile) contextVideo.videoInputFile.addEventListener('change', this._fileInputChange.bind(contextVideo)); + if (contextVideo.videoUrlFile) contextVideo.videoUrlFile.addEventListener('input', this._onLinkPreview.bind(contextVideo.preview, contextVideo, options.linkProtocol)); + + contextVideo.proportion = {}; + contextVideo.videoRatioOption = {}; + contextVideo.inputX = {}; + contextVideo.inputY = {}; + if (options.videoResizing) { + contextVideo.proportion = video_dialog.querySelector('._se_video_check_proportion'); + contextVideo.videoRatioOption = video_dialog.querySelector('.se-video-ratio'); + contextVideo.inputX = video_dialog.querySelector('._se_video_size_x'); + contextVideo.inputY = video_dialog.querySelector('._se_video_size_y'); + contextVideo.inputX.value = options.videoWidth; + contextVideo.inputY.value = options.videoHeight; + + contextVideo.inputX.addEventListener('keyup', this.setInputSize.bind(core, 'x')); + contextVideo.inputY.addEventListener('keyup', this.setInputSize.bind(core, 'y')); + + contextVideo.inputX.addEventListener('change', this.setRatio.bind(core)); + contextVideo.inputY.addEventListener('change', this.setRatio.bind(core)); + contextVideo.proportion.addEventListener('change', this.setRatio.bind(core)); + contextVideo.videoRatioOption.addEventListener('change', this.setVideoRatio.bind(core)); + + video_dialog.querySelector('.se-dialog-btn-revert').addEventListener('click', this.sizeRevert.bind(core)); + } + + /** append html */ + context.dialog.modal.appendChild(video_dialog); + + /** empty memory */ + video_dialog = null; + }, + + /** dialog */ + setDialog: function (core) { + const option = core.options; + const lang = core.lang; + const dialog = core.util.createElement('DIV'); + + dialog.className = 'se-dialog-content'; + dialog.style.display = 'none'; + let html = '' + + '
' + + '
' + + '' + + '' + lang.dialogBox.videoBox.title + '' + + '
' + + '
'; + + if (option.videoFileInput) { + html += '' + + '
' + + '' + + '
' + + '' + + '' + + '
' + + '
' ; + } + + if (option.videoUrlInput) { + html += '' + + '
' + + '' + + '' + + '' + + '
'; + } + + if (option.videoResizing) { + const ratioList = option.videoRatioList || [{name: '16:9', value: 0.5625}, {name: '4:3', value: 0.75}, {name: '21:9', value: 0.4285}]; + const ratio = option.videoRatio; + const onlyPercentage = option.videoSizeOnlyPercentage; + const onlyPercentDisplay = onlyPercentage ? ' style="display: none !important;"' : ''; + const heightDisplay = !option.videoHeightShow ? ' style="display: none !important;"' : ''; + const ratioDisplay = !option.videoRatioShow ? ' style="display: none !important;"' : ''; + const onlyWidthDisplay = !onlyPercentage && !option.videoHeightShow && !option.videoRatioShow ? ' style="display: none !important;"' : ''; + html += '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '' + + '' + + '' + + '' + + '' + + '
' + + ''; + } + + html += '' + + '
' + + '' + + '
'; + + dialog.innerHTML = html; + + return dialog; + }, + + _fileInputChange: function () { + if (!this.videoInputFile.value) { + this.videoUrlFile.removeAttribute('disabled'); + this.preview.style.textDecoration = ''; + } else { + this.videoUrlFile.setAttribute('disabled', true); + this.preview.style.textDecoration = 'line-through'; + } + }, + + _removeSelectedFiles: function (urlInput, preview) { + this.value = ''; + if (urlInput) { + urlInput.removeAttribute('disabled'); + preview.style.textDecoration = ''; + } + }, + + _onLinkPreview: function (context, protocol, e) { + const value = e.target.value.trim(); + if (/^$/.test(value)) { + context._linkValue = value; + this.textContent = ''; + } else { + context._linkValue = this.textContent = !value ? '' : (protocol && value.indexOf('://') === -1 && value.indexOf('#') !== 0) ? protocol + value : value.indexOf('://') === -1 ? '/' + value : value; + } + }, + + _setTagAttrs: function (element) { + element.setAttribute('controls', true); + + const attrs = this.options.videoTagAttrs; + if (!attrs) return; + + for (let key in attrs) { + if (!this.util.hasOwn(attrs, key)) continue; + element.setAttribute(key, attrs[key]); + } + }, + + createVideoTag: function () { + const videoTag = this.util.createElement('VIDEO'); + this.plugins.video._setTagAttrs.call(this, videoTag); + return videoTag; + }, + + _setIframeAttrs: function (element) { + element.frameBorder = '0'; + element.allowFullscreen = true; + + const attrs = this.options.videoIframeAttrs; + if (!attrs) return; + + for (let key in attrs) { + if (!this.util.hasOwn(attrs, key)) continue; + element.setAttribute(key, attrs[key]); + } + }, + + createIframeTag: function () { + const iframeTag = this.util.createElement('IFRAME'); + this.plugins.video._setIframeAttrs.call(this, iframeTag); + return iframeTag; + }, + + /** + * @Override @Required fileManager + */ + fileTags: ['iframe', 'video'], + + /** + * @Override core, resizing, fileManager + * @description It is called from core.selectComponent. + * @param {Element} element Target element + */ + select: function (element) { + this.plugins.video.onModifyMode.call(this, element, this.plugins.resizing.call_controller_resize.call(this, element, 'video')); + }, + + /** + * @Override fileManager, resizing + */ + destroy: function (element) { + const frame = element || this.context.video._element; + const container = this.context.video._container; + const dataIndex = frame.getAttribute('data-index') * 1; + let focusEl = (container.previousElementSibling || container.nextElementSibling); + + const emptyDiv = container.parentNode; + this.util.removeItem(container); + this.plugins.video.init.call(this); + this.controllersOff(); + + if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null); + + // focus + this.focusEdge(focusEl); + + // event + this.plugins.fileManager.deleteInfo.call(this, 'video', dataIndex, this.functions.onVideoUpload); + + // history stack + this.history.push(false); + }, + + /** + * @Required @Override dialog + */ + on: function (update) { + const contextVideo = this.context.video; + + if (!update) { + contextVideo.inputX.value = contextVideo._origin_w = this.options.videoWidth === contextVideo._defaultSizeX ? '' : this.options.videoWidth; + contextVideo.inputY.value = contextVideo._origin_h = this.options.videoHeight === contextVideo._defaultSizeY ? '' : this.options.videoHeight; + contextVideo.proportion.disabled = true; + if (contextVideo.videoInputFile && this.options.videoMultipleFile) contextVideo.videoInputFile.setAttribute('multiple', 'multiple'); + } else { + if (contextVideo.videoInputFile && this.options.videoMultipleFile) contextVideo.videoInputFile.removeAttribute('multiple'); + } + + if (contextVideo._resizing) { + this.plugins.video.setVideoRatioSelect.call(this, contextVideo._origin_h || contextVideo._defaultRatio); + } + }, + + /** + * @Required @Override dialog + */ + open: function () { + this.plugins.dialog.open.call(this, 'video', 'video' === this.currentControllerName); + }, + + setVideoRatio: function (e) { + const contextVideo = this.context.video; + const value = e.target.options[e.target.selectedIndex].value; + + contextVideo._defaultSizeY = contextVideo._videoRatio = !value ? contextVideo._defaultSizeY : (value * 100) + '%'; + contextVideo.inputY.placeholder = !value ? '' : (value * 100) + '%'; + contextVideo.inputY.value = ''; + }, + + /** + * @Override resizing + * @param {String} xy 'x': width, 'y': height + * @param {KeyboardEvent} e Event object + */ + setInputSize: function (xy, e) { + if (e && e.keyCode === 32) { + e.preventDefault(); + return; + } + + const contextVideo = this.context.video; + this.plugins.resizing._module_setInputSize.call(this, contextVideo, xy); + + if (xy === 'y') { + this.plugins.video.setVideoRatioSelect.call(this, e.target.value || contextVideo._defaultRatio); + } + }, + + /** + * @Override resizing + */ + setRatio: function () { + this.plugins.resizing._module_setRatio.call(this, this.context.video); + }, + + submit: function (e) { + const contextVideo = this.context.video; + const videoPlugin = this.plugins.video; + + e.preventDefault(); + e.stopPropagation(); + + contextVideo._align = contextVideo.modal.querySelector('input[name="suneditor_video_radio"]:checked').value; + + try { + if (contextVideo.videoInputFile && contextVideo.videoInputFile.files.length > 0) { + this.showLoading(); + videoPlugin.submitAction.call(this, this.context.video.videoInputFile.files); + } else if (contextVideo.videoUrlFile && contextVideo._linkValue.length > 0) { + this.showLoading(); + videoPlugin.setup_url.call(this); + } + } catch (error) { + this.closeLoading(); + throw Error('[SUNEDITOR.video.submit.fail] cause : "' + error.message + '"'); + } finally { + this.plugins.dialog.close.call(this); + } + + return false; + }, + + submitAction: function (fileList) { + if (fileList.length === 0) return; + + let fileSize = 0; + let files = []; + for (let i = 0, len = fileList.length; i < len; i++) { + if (/video/i.test(fileList[i].type)) { + files.push(fileList[i]); + fileSize += fileList[i].size; + } + } + + const limitSize = this.options.videoUploadSizeLimit; + if (limitSize > 0) { + let infoSize = 0; + const videosInfo = this.context.video._infoList; + for (let i = 0, len = videosInfo.length; i < len; i++) { + infoSize += videosInfo[i].size * 1; + } + + if ((fileSize + infoSize) > limitSize) { + this.closeLoading(); + const err = '[SUNEDITOR.videoUpload.fail] Size of uploadable total videos: ' + (limitSize/1000) + 'KB'; + if (typeof this.functions.onVideoUploadError !== 'function' || this.functions.onVideoUploadError(err, { 'limitSize': limitSize, 'currentSize': infoSize, 'uploadSize': fileSize }, this)) { + this.functions.noticeOpen(err); + } + return; + } + } + + const contextVideo = this.context.video; + contextVideo._uploadFileLength = files.length; + + const info = { + inputWidth: contextVideo.inputX.value, + inputHeight: contextVideo.inputY.value, + align: contextVideo._align, + isUpdate: this.context.dialog.updateModal, + element: contextVideo._element + }; + + if (typeof this.functions.onVideoUploadBefore === 'function') { + const result = this.functions.onVideoUploadBefore(files, info, this, function (data) { + if (data && this._w.Array.isArray(data.result)) { + this.plugins.video.register.call(this, info, data); + } else { + this.plugins.video.upload.call(this, info, data); + } + }.bind(this)); + + if (typeof result === 'undefined') return; + if (!result) { + this.closeLoading(); + return; + } + if (typeof result === 'object' && result.length > 0) files = result; + } + + this.plugins.video.upload.call(this, info, files); + }, + + error: function (message, response) { + this.closeLoading(); + if (typeof this.functions.onVideoUploadError !== 'function' || this.functions.onVideoUploadError(message, response, this)) { + this.functions.noticeOpen(message); + throw Error('[SUNEDITOR.plugin.video.error] response: ' + message); + } + }, + + upload: function (info, files) { + if (!files) { + this.closeLoading(); + return; + } + if (typeof files === 'string') { + this.plugins.video.error.call(this, files, null); + return; + } + + const videoUploadUrl = this.options.videoUploadUrl; + const filesLen = this.context.dialog.updateModal ? 1 : files.length; + + // server upload + if (typeof videoUploadUrl === 'string' && videoUploadUrl.length > 0) { + const formData = new FormData(); + for (let i = 0; i < filesLen; i++) { + formData.append('file-' + i, files[i]); + } + this.plugins.fileManager.upload.call(this, videoUploadUrl, this.options.videoUploadHeader, formData, this.plugins.video.callBack_videoUpload.bind(this, info), this.functions.onVideoUploadError); + } else { + throw Error('[SUNEDITOR.videoUpload.fail] cause : There is no "videoUploadUrl" option.'); + } + }, + + callBack_videoUpload: function (info, xmlHttp) { + if (typeof this.functions.videoUploadHandler === 'function') { + this.functions.videoUploadHandler(xmlHttp, info, this); + } else { + const response = JSON.parse(xmlHttp.responseText); + if (response.errorMessage) { + this.plugins.video.error.call(this, response.errorMessage, response); + } else { + this.plugins.video.register.call(this, info, response); + } + } + }, + + register: function (info, response) { + const fileList = response.result; + const videoTag = this.plugins.video.createVideoTag.call(this); + + for (let i = 0, len = fileList.length, file; i < len; i++) { + file = { name: fileList[i].name, size: fileList[i].size }; + this.plugins.video.create_video.call(this, (info.isUpdate ? info.element : videoTag.cloneNode(false)), fileList[i].url, info.inputWidth, info.inputHeight, info.align, file, info.isUpdate); + } + + this.closeLoading(); + }, + + setup_url: function () { + try { + const contextVideo = this.context.video; + let url = contextVideo._linkValue; + + if (url.length === 0) return false; + + /** iframe source */ + if (/^$/.test(url)) { + const oIframe = (new this._w.DOMParser()).parseFromString(url, 'text/html').querySelector('iframe'); + url = oIframe.src; + if (url.length === 0) return false; + } + + /** youtube */ + if (/youtu\.?be/.test(url)) { + if (!/^http/.test(url)) url = 'https://' + url; + url = url.replace('watch?v=', ''); + if (!/^\/\/.+\/embed\//.test(url)) { + url = url.replace(url.match(/\/\/.+\//)[0], '//www.youtube.com/embed/').replace('&', '?&'); + } + + if (contextVideo._youtubeQuery.length > 0) { + if (/\?/.test(url)) { + const splitUrl = url.split('?'); + url = splitUrl[0] + '?' + contextVideo._youtubeQuery + '&' + splitUrl[1]; + } else { + url += '?' + contextVideo._youtubeQuery; + } + } + } else if (/vimeo\.com/.test(url)) { + if (url.endsWith('/')) { + url = url.slice(0, -1); + } + url = 'https://player.vimeo.com/video/' + url.slice(url.lastIndexOf('/') + 1); + } + + this.plugins.video.create_video.call(this, this.plugins.video.createIframeTag.call(this), url, contextVideo.inputX.value, contextVideo.inputY.value, contextVideo._align, null, this.context.dialog.updateModal); + } catch (error) { + throw Error('[SUNEDITOR.video.upload.fail] cause : "' + error.message + '"'); + } finally { + this.closeLoading(); + } + }, + + create_video: function (oFrame, src, width, height, align, file, isUpdate) { + this.context.resizing._resize_plugin = 'video'; + const contextVideo = this.context.video; + + let cover = null; + let container = null; + let init = false; + + /** update */ + if (isUpdate) { + oFrame = contextVideo._element; + if (oFrame.src !== src) { + init = true; + const isYoutube = /youtu\.?be/.test(src); + const isVimeo = /vimeo\.com/.test(src); + if ((isYoutube || isVimeo) && !/^iframe$/i.test(oFrame.nodeName)) { + const newTag = this.plugins.video.createIframeTag.call(this); + newTag.src = src; + oFrame.parentNode.replaceChild(newTag, oFrame); + contextVideo._element = oFrame = newTag; + } else if (!isYoutube && !isVimeo && !/^videoo$/i.test(oFrame.nodeName)) { + const newTag = this.plugins.video.createVideoTag.call(this); + newTag.src = src; + oFrame.parentNode.replaceChild(newTag, oFrame); + contextVideo._element = oFrame = newTag; + } else { + oFrame.src = src; + } + } + container = contextVideo._container; + cover = this.util.getParentElement(oFrame, 'FIGURE'); + } + /** create */ + else { + init = true; + oFrame.src = src; + contextVideo._element = oFrame; + cover = this.plugins.component.set_cover.call(this, oFrame); + container = this.plugins.component.set_container.call(this, cover, 'se-video-container'); + } + + /** rendering */ + contextVideo._cover = cover; + contextVideo._container = container; + + const inputUpdate = (this.plugins.resizing._module_getSizeX.call(this, contextVideo) !== (width || contextVideo._defaultSizeX)) || (this.plugins.resizing._module_getSizeY.call(this, contextVideo) !== (height || contextVideo._videoRatio)); + const changeSize = !isUpdate || inputUpdate; + + if (contextVideo._resizing) { + this.context.video._proportionChecked = contextVideo.proportion.checked; + oFrame.setAttribute('data-proportion', contextVideo._proportionChecked); + } + + // size + let isPercent = false; + if (changeSize) { + isPercent = this.plugins.video.applySize.call(this); + } + + // align + if (!(isPercent && align === 'center')) { + this.plugins.video.setAlign.call(this, null, oFrame, cover, container); + } + + let changed = true; + if (!isUpdate) { + changed = this.insertComponent(container, false, true, !this.options.mediaAutoSelect); + if (!this.options.mediaAutoSelect) { + const line = this.appendFormatTag(container, null); + this.setRange(line, 0, line, 0); + } + } else if (contextVideo._resizing && this.context.resizing._rotateVertical && changeSize) { + this.plugins.resizing.setTransformSize.call(this, oFrame, null, null); + } + + if (changed) { + if (init) { + this.plugins.fileManager.setInfo.call(this, 'video', oFrame, this.functions.onVideoUpload, file, true); + } + if (isUpdate) { + this.selectComponent(oFrame, 'video'); + // history stack + this.history.push(false); + } + } + + this.context.resizing._resize_plugin = ''; + }, + + _update_videoCover: function (oFrame) { + if (!oFrame) return; + + const contextVideo = this.context.video; + + if (/^video$/i.test(oFrame.nodeName)) this.plugins.video._setTagAttrs.call(this, oFrame); + else this.plugins.video._setIframeAttrs.call(this, oFrame); + + const existElement = this.util.getParentElement(oFrame, this.util.isMediaComponent) || + this.util.getParentElement(oFrame, function (current) { + return this.isWysiwygDiv(current.parentNode); + }.bind(this.util)); + + contextVideo._element = oFrame = oFrame.cloneNode(true); + const cover = contextVideo._cover = this.plugins.component.set_cover.call(this, oFrame); + const container = contextVideo._container = this.plugins.component.set_container.call(this, cover, 'se-video-container'); + + const figcaption = existElement.querySelector('figcaption'); + let caption = null; + if (!!figcaption) { + caption = this.util.createElement('DIV'); + caption.innerHTML = figcaption.innerHTML; + this.util.removeItem(figcaption); + } + + const size = (oFrame.getAttribute('data-size') || oFrame.getAttribute('data-origin') || '').split(','); + this.plugins.video.applySize.call(this, size[0], size[1]); + + if (this.util.isFormatElement(existElement) && existElement.textContent.length > 0) { + existElement.parentNode.insertBefore(container, existElement.nextElementSibling); + this.util.removeItem(contextVideo._element); + contextVideo._element = oFrame; + } else { + existElement.parentNode.replaceChild(container, existElement); + } + + if (!!caption) existElement.parentNode.insertBefore(caption, container.nextElementSibling); + this.plugins.fileManager.setInfo.call(this, 'video', oFrame, this.functions.onVideoUpload, null, true); + }, + + /** + * @Required @Override fileManager, resizing + */ + onModifyMode: function (element, size) { + const contextVideo = this.context.video; + contextVideo._element = element; + contextVideo._cover = this.util.getParentElement(element, 'FIGURE'); + contextVideo._container = this.util.getParentElement(element, this.util.isMediaComponent); + contextVideo._align = element.style.float || element.getAttribute('data-align') || 'none'; + element.style.float = ''; + + if (size) { + contextVideo._element_w = size.w; + contextVideo._element_h = size.h; + contextVideo._element_t = size.t; + contextVideo._element_l = size.l; + } + + let origin = contextVideo._element.getAttribute('data-size') || contextVideo._element.getAttribute('data-origin'); + if (origin) { + origin = origin.split(','); + contextVideo._origin_w = origin[0]; + contextVideo._origin_h = origin[1]; + } else if (size) { + contextVideo._origin_w = size.w; + contextVideo._origin_h = size.h; + } + }, + + /** + * @Required @Override fileManager, resizing + */ + openModify: function (notOpen) { + const contextVideo = this.context.video; + + if (contextVideo.videoUrlFile) contextVideo._linkValue = contextVideo.preview.textContent = contextVideo.videoUrlFile.value = (contextVideo._element.src || (contextVideo._element.querySelector('source') || '').src || ''); + contextVideo.modal.querySelector('input[name="suneditor_video_radio"][value="' + contextVideo._align + '"]').checked = true; + + if (contextVideo._resizing) { + this.plugins.resizing._module_setModifyInputSize.call(this, contextVideo, this.plugins.video); + + const y = contextVideo._videoRatio = this.plugins.resizing._module_getSizeY.call(this, contextVideo); + const ratioSelected = this.plugins.video.setVideoRatioSelect.call(this, y); + if (!ratioSelected) contextVideo.inputY.value = contextVideo._onlyPercentage ? this.util.getNumber(y, 2) : y; + } + + if (!notOpen) this.plugins.dialog.open.call(this, 'video', true); + }, + + setVideoRatioSelect: function (value) { + let ratioSelected = false; + const contextVideo = this.context.video; + const ratioOptions = contextVideo.videoRatioOption.options; + + if (/%$/.test(value) || contextVideo._onlyPercentage) value = (this.util.getNumber(value, 2) / 100) + ''; + else if (!this.util.isNumber(value) || (value * 1) >= 1) value = ''; + + contextVideo.inputY.placeholder = ''; + for (let i = 0, len = ratioOptions.length; i < len; i++) { + if (ratioOptions[i].value === value) { + ratioSelected = ratioOptions[i].selected = true; + contextVideo.inputY.placeholder = !value ? '' : (value * 100) + '%'; + } + else ratioOptions[i].selected = false; + } + + return ratioSelected; + }, + + /** + * @Override fileManager + */ + checkFileInfo: function () { + this.plugins.fileManager.checkInfo.call(this, 'video', ['iframe', 'video'], this.functions.onVideoUpload, this.plugins.video._update_videoCover.bind(this), true); + }, + + /** + * @Override fileManager + */ + resetFileInfo: function () { + this.plugins.fileManager.resetInfo.call(this, 'video', this.functions.onVideoUpload); + }, + + /** + * @Override fileManager + */ + applySize: function (w, h) { + const contextVideo = this.context.video; + + if (!w) w = contextVideo.inputX.value || this.options.videoWidth; + if (!h) h = contextVideo.inputY.value || this.options.videoHeight; + + if (contextVideo._onlyPercentage || /%$/.test(w) || !w) { + this.plugins.video.setPercentSize.call(this, (w || '100%'), (h || (/%$/.test(contextVideo._videoRatio) ? contextVideo._videoRatio : contextVideo._defaultRatio))); + return true; + } else if ((!w || w === 'auto') && (!h || h === 'auto')) { + this.plugins.video.setAutoSize.call(this); + } else { + this.plugins.video.setSize.call(this, w, (h || contextVideo._videoRatio || contextVideo._defaultRatio), false); + } + + return false; + }, + + /** + * @Override resizing + */ + sizeRevert: function () { + this.plugins.resizing._module_sizeRevert.call(this, this.context.video); + }, + + /** + * @Override resizing + */ + setSize: function (w, h, notResetPercentage, direction) { + const contextVideo = this.context.video; + const onlyW = /^(rw|lw)$/.test(direction); + const onlyH = /^(th|bh)$/.test(direction); + + if (!onlyH) w = this.util.getNumber(w, 0); + if (!onlyW) h = this.util.isNumber(h) ? h + contextVideo.sizeUnit : !h ? '' : h; + + if (!onlyH) contextVideo._element.style.width = w ? w + contextVideo.sizeUnit : ''; + if (!onlyW) contextVideo._cover.style.paddingBottom = contextVideo._cover.style.height = h; + + if (!onlyH && !/%$/.test(w)) { + contextVideo._cover.style.width = ''; + contextVideo._container.style.width = ''; + } + + if (!onlyW && !/%$/.test(h)) { + contextVideo._element.style.height = h; + } else { + contextVideo._element.style.height = ''; + } + + if (!notResetPercentage) contextVideo._element.removeAttribute('data-percentage'); + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextVideo); + }, + + /** + * @Override resizing + */ + setAutoSize: function () { + this.plugins.video.setPercentSize.call(this, 100, this.context.video._defaultRatio); + }, + + /** + * @Override resizing + */ + setOriginSize: function (dataSize) { + const contextVideo = this.context.video; + contextVideo._element.removeAttribute('data-percentage'); + + this.plugins.resizing.resetTransform.call(this, contextVideo._element); + this.plugins.video.cancelPercentAttr.call(this); + + const originSize = ((dataSize ? contextVideo._element.getAttribute('data-size') : '') || contextVideo._element.getAttribute('data-origin') || '').split(','); + + if (originSize) { + const w = originSize[0]; + const h = originSize[1]; + + if (contextVideo._onlyPercentage || (/%$/.test(w) && (/%$/.test(h) || !/\d/.test(h)))) { + this.plugins.video.setPercentSize.call(this, w, h); + } else { + this.plugins.video.setSize.call(this, w, h); + } + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextVideo); + } + }, + + /** + * @Override resizing + */ + setPercentSize: function (w, h) { + const contextVideo = this.context.video; + h = !!h && !/%$/.test(h) && !this.util.getNumber(h, 0) ? this.util.isNumber(h) ? h + '%' : h : this.util.isNumber(h) ? h + contextVideo.sizeUnit : (h || contextVideo._defaultRatio); + + contextVideo._container.style.width = this.util.isNumber(w) ? w + '%' : w; + contextVideo._container.style.height = ''; + contextVideo._cover.style.width = '100%'; + contextVideo._cover.style.height = h; + contextVideo._cover.style.paddingBottom = h; + contextVideo._element.style.width = '100%'; + contextVideo._element.style.height = '100%'; + contextVideo._element.style.maxWidth = ''; + + if (contextVideo._align === 'center') this.plugins.video.setAlign.call(this, null, null, null, null); + contextVideo._element.setAttribute('data-percentage', w + ',' + h); + + // save current size + this.plugins.resizing._module_saveCurrentSize.call(this, contextVideo); + }, + + /** + * @Override resizing + */ + cancelPercentAttr: function () { + const contextVideo = this.context.video; + + contextVideo._cover.style.width = ''; + contextVideo._cover.style.height = ''; + contextVideo._cover.style.paddingBottom = ''; + contextVideo._container.style.width = ''; + contextVideo._container.style.height = ''; + + this.util.removeClass(contextVideo._container, this.context.video._floatClassRegExp); + this.util.addClass(contextVideo._container, '__se__float-' + contextVideo._align); + + if (contextVideo._align === 'center') this.plugins.video.setAlign.call(this, null, null, null, null); + }, + + /** + * @Override resizing + */ + setAlign: function (align, element, cover, container) { + const contextVideo = this.context.video; + + if (!align) align = contextVideo._align; + if (!element) element = contextVideo._element; + if (!cover) cover = contextVideo._cover; + if (!container) container = contextVideo._container; + + if (align && align !== 'none') { + cover.style.margin = 'auto'; + } else { + cover.style.margin = '0'; + } + + if (/%$/.test(element.style.width) && align === 'center') { + container.style.minWidth = '100%'; + cover.style.width = container.style.width; + cover.style.height = cover.style.height; + cover.style.paddingBottom = !/%$/.test(cover.style.height) ? cover.style.height : this.util.getNumber((this.util.getNumber(cover.style.height, 2) / 100) * this.util.getNumber(cover.style.width, 2), 2) + '%'; + } else { + container.style.minWidth = ''; + cover.style.width = this.context.resizing._rotateVertical ? (element.style.height || element.offsetHeight) : (element.style.width || '100%'); + cover.style.paddingBottom = cover.style.height; + } + + if (!this.util.hasClass(container, '__se__float-' + align)) { + this.util.removeClass(container, contextVideo._floatClassRegExp); + this.util.addClass(container, '__se__float-' + align); + } + + element.setAttribute('data-align', align); + }, + + /** + * @Override dialog + */ + init: function () { + const contextVideo = this.context.video; + if (contextVideo.videoInputFile) contextVideo.videoInputFile.value = ''; + if (contextVideo.videoUrlFile) contextVideo._linkValue = contextVideo.preview.textContent = contextVideo.videoUrlFile.value = ''; + if (contextVideo.videoInputFile && contextVideo.videoUrlFile) { + contextVideo.videoUrlFile.removeAttribute('disabled'); + contextVideo.preview.style.textDecoration = ''; + } + + contextVideo._origin_w = this.options.videoWidth; + contextVideo._origin_h = this.options.videoHeight; + contextVideo.modal.querySelector('input[name="suneditor_video_radio"][value="none"]').checked = true; + + if (contextVideo._resizing) { + contextVideo.inputX.value = this.options.videoWidth === contextVideo._defaultSizeX ? '' : this.options.videoWidth; + contextVideo.inputY.value = this.options.videoHeight === contextVideo._defaultSizeY ? '' : this.options.videoHeight; + contextVideo.proportion.checked = true; + contextVideo.proportion.disabled = true; + this.plugins.video.setVideoRatioSelect.call(this, contextVideo._defaultRatio); + } + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/fileBrowser/imageGallery.js": +/*!************************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/fileBrowser/imageGallery.js ***! + \************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_fileBrowser__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/fileBrowser */ "./node_modules/suneditor/src/plugins/modules/fileBrowser.js"); +/* harmony import */ var _modules_fileBrowser__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_modules_fileBrowser__WEBPACK_IMPORTED_MODULE_0__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'imageGallery', + /** + * @description Constructor + * @param {Object} core Core object + */ + add: function (core) { + core.addModule([_modules_fileBrowser__WEBPACK_IMPORTED_MODULE_0___default.a]); + + const context = core.context; + context.imageGallery = { + title: core.lang.toolbar.imageGallery, // @Required @Override fileBrowser - File browser window title. + url: core.options.imageGalleryUrl, // @Required @Override fileBrowser - File server url. + listClass: 'se-image-list', // @Required @Override fileBrowser - Class name of list div. + itemTemplateHandler: this.drawItems, // @Required @Override fileBrowser - Function that defines the HTML of an file item. + selectorHandler: this.setImage.bind(core), // @Required @Override fileBrowser - Function that action when item click. + columnSize: 4 // @Option @Override fileBrowser - Number of "div.se-file-item-column" to be created (default: 4) + }; + }, + + /** + * @Required @Override fileBrowser + * @description Open a file browser. + * @param {Function|null} selectorHandler When the function comes as an argument value, it substitutes "context.selectorHandler". + */ + open: function (selectorHandler) { + this.plugins.fileBrowser.open.call(this, 'imageGallery', selectorHandler); + }, + + /** + * @Required @Override fileBrowser + * @description Define the HTML of the item to be put in "div.se-file-item-column". + * Format: [ + * { src: "image src", name: "name(@option)", alt: "image alt(@option)", tag: "tag name(@option)" } + * ] + * @param {Object} item Item of the response data's array + */ + drawItems: function (item) { + const srcName = item.src.split('/').pop(); + return '
' + (item.alt || srcName) + '' + + '
' + + '
' + (item.name || srcName) + '
' + + '
'; + }, + + setImage: function (target) { + this.callPlugin('image', function () { + const file = {name: target.parentNode.querySelector('.__se__img_name').textContent, size: 0}; + this.context.image._altText = target.alt; + this.plugins.image.create_image.call(this, target.src, null, this.context.image._origin_w, this.context.image._origin_h, 'none', file); + }.bind(this), null); + } +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/index.js": +/*!*****************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/index.js ***! + \*****************************************************/ +/*! exports provided: blockquote, align, font, fontSize, fontColor, hiliteColor, horizontalRule, list, table, formatBlock, lineHeight, template, paragraphStyle, textStyle, link, image, video, audio, math, imageGallery, default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _command_blockquote__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./command/blockquote */ "./node_modules/suneditor/src/plugins/command/blockquote.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "blockquote", function() { return _command_blockquote__WEBPACK_IMPORTED_MODULE_0__["default"]; }); + +/* harmony import */ var _submenu_align__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./submenu/align */ "./node_modules/suneditor/src/plugins/submenu/align.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "align", function() { return _submenu_align__WEBPACK_IMPORTED_MODULE_1__["default"]; }); + +/* harmony import */ var _submenu_font__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./submenu/font */ "./node_modules/suneditor/src/plugins/submenu/font.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "font", function() { return _submenu_font__WEBPACK_IMPORTED_MODULE_2__["default"]; }); + +/* harmony import */ var _submenu_fontSize__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./submenu/fontSize */ "./node_modules/suneditor/src/plugins/submenu/fontSize.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "fontSize", function() { return _submenu_fontSize__WEBPACK_IMPORTED_MODULE_3__["default"]; }); + +/* harmony import */ var _submenu_fontColor__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./submenu/fontColor */ "./node_modules/suneditor/src/plugins/submenu/fontColor.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "fontColor", function() { return _submenu_fontColor__WEBPACK_IMPORTED_MODULE_4__["default"]; }); + +/* harmony import */ var _submenu_hiliteColor__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./submenu/hiliteColor */ "./node_modules/suneditor/src/plugins/submenu/hiliteColor.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "hiliteColor", function() { return _submenu_hiliteColor__WEBPACK_IMPORTED_MODULE_5__["default"]; }); + +/* harmony import */ var _submenu_horizontalRule__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./submenu/horizontalRule */ "./node_modules/suneditor/src/plugins/submenu/horizontalRule.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "horizontalRule", function() { return _submenu_horizontalRule__WEBPACK_IMPORTED_MODULE_6__["default"]; }); + +/* harmony import */ var _submenu_list__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./submenu/list */ "./node_modules/suneditor/src/plugins/submenu/list.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "list", function() { return _submenu_list__WEBPACK_IMPORTED_MODULE_7__["default"]; }); + +/* harmony import */ var _submenu_table__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./submenu/table */ "./node_modules/suneditor/src/plugins/submenu/table.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "table", function() { return _submenu_table__WEBPACK_IMPORTED_MODULE_8__["default"]; }); + +/* harmony import */ var _submenu_formatBlock__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./submenu/formatBlock */ "./node_modules/suneditor/src/plugins/submenu/formatBlock.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "formatBlock", function() { return _submenu_formatBlock__WEBPACK_IMPORTED_MODULE_9__["default"]; }); + +/* harmony import */ var _submenu_lineHeight__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./submenu/lineHeight */ "./node_modules/suneditor/src/plugins/submenu/lineHeight.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "lineHeight", function() { return _submenu_lineHeight__WEBPACK_IMPORTED_MODULE_10__["default"]; }); + +/* harmony import */ var _submenu_template__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./submenu/template */ "./node_modules/suneditor/src/plugins/submenu/template.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "template", function() { return _submenu_template__WEBPACK_IMPORTED_MODULE_11__["default"]; }); + +/* harmony import */ var _submenu_paragraphStyle__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./submenu/paragraphStyle */ "./node_modules/suneditor/src/plugins/submenu/paragraphStyle.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "paragraphStyle", function() { return _submenu_paragraphStyle__WEBPACK_IMPORTED_MODULE_12__["default"]; }); + +/* harmony import */ var _submenu_textStyle__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./submenu/textStyle */ "./node_modules/suneditor/src/plugins/submenu/textStyle.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "textStyle", function() { return _submenu_textStyle__WEBPACK_IMPORTED_MODULE_13__["default"]; }); + +/* harmony import */ var _dialog_link__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./dialog/link */ "./node_modules/suneditor/src/plugins/dialog/link.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "link", function() { return _dialog_link__WEBPACK_IMPORTED_MODULE_14__["default"]; }); + +/* harmony import */ var _dialog_image__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./dialog/image */ "./node_modules/suneditor/src/plugins/dialog/image.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "image", function() { return _dialog_image__WEBPACK_IMPORTED_MODULE_15__["default"]; }); + +/* harmony import */ var _dialog_video__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./dialog/video */ "./node_modules/suneditor/src/plugins/dialog/video.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "video", function() { return _dialog_video__WEBPACK_IMPORTED_MODULE_16__["default"]; }); + +/* harmony import */ var _dialog_audio__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./dialog/audio */ "./node_modules/suneditor/src/plugins/dialog/audio.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audio", function() { return _dialog_audio__WEBPACK_IMPORTED_MODULE_17__["default"]; }); + +/* harmony import */ var _dialog_math__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./dialog/math */ "./node_modules/suneditor/src/plugins/dialog/math.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "math", function() { return _dialog_math__WEBPACK_IMPORTED_MODULE_18__["default"]; }); + +/* harmony import */ var _fileBrowser_imageGallery__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./fileBrowser/imageGallery */ "./node_modules/suneditor/src/plugins/fileBrowser/imageGallery.js"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "imageGallery", function() { return _fileBrowser_imageGallery__WEBPACK_IMPORTED_MODULE_19__["default"]; }); + + + +// command + + +// submenu + + + + + + + + + + + + + + +// dialog + + + + + + +// file browser + + + +/* harmony default export */ __webpack_exports__["default"] = ({ blockquote: _command_blockquote__WEBPACK_IMPORTED_MODULE_0__["default"], align: _submenu_align__WEBPACK_IMPORTED_MODULE_1__["default"], font: _submenu_font__WEBPACK_IMPORTED_MODULE_2__["default"], fontSize: _submenu_fontSize__WEBPACK_IMPORTED_MODULE_3__["default"], fontColor: _submenu_fontColor__WEBPACK_IMPORTED_MODULE_4__["default"], hiliteColor: _submenu_hiliteColor__WEBPACK_IMPORTED_MODULE_5__["default"], horizontalRule: _submenu_horizontalRule__WEBPACK_IMPORTED_MODULE_6__["default"], list: _submenu_list__WEBPACK_IMPORTED_MODULE_7__["default"], table: _submenu_table__WEBPACK_IMPORTED_MODULE_8__["default"], formatBlock: _submenu_formatBlock__WEBPACK_IMPORTED_MODULE_9__["default"], lineHeight: _submenu_lineHeight__WEBPACK_IMPORTED_MODULE_10__["default"], template: _submenu_template__WEBPACK_IMPORTED_MODULE_11__["default"], paragraphStyle: _submenu_paragraphStyle__WEBPACK_IMPORTED_MODULE_12__["default"], textStyle: _submenu_textStyle__WEBPACK_IMPORTED_MODULE_13__["default"], link: _dialog_link__WEBPACK_IMPORTED_MODULE_14__["default"], image: _dialog_image__WEBPACK_IMPORTED_MODULE_15__["default"], video: _dialog_video__WEBPACK_IMPORTED_MODULE_16__["default"], audio: _dialog_audio__WEBPACK_IMPORTED_MODULE_17__["default"], math: _dialog_math__WEBPACK_IMPORTED_MODULE_18__["default"], imageGallery: _fileBrowser_imageGallery__WEBPACK_IMPORTED_MODULE_19__["default"] }); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/_anchor.js": +/*!***************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/_anchor.js ***! + \***************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'anchor', + add: function (core) { + core.context.anchor = { + caller: {}, + forms: this.setDialogForm(core), + host: core._w.location.origin + core._w.location.pathname + }; + }, + + /** dialog */ + setDialogForm: function (core) { + const lang = core.lang; + const relList = core.options.linkRel; + const defaultRel = (core.options.linkRelDefault.default || '').split(' '); + const icons = core.icons; + const forms = core.util.createElement('DIV'); + + let html = '
' + + '
' + + '' + + '
' + + '' + + '' + + '
' + + '
' + + '' + icons.bookmark + '' + + '' + icons.download + '' + + '' + + '
' + + '
' + + '
' + + '' + + '
' + + '
'; + + forms.innerHTML = html; + return forms; + }, + + initEvent: function (pluginName, forms) { + const anchorPlugin = this.plugins.anchor; + const context = this.context.anchor.caller[pluginName] = { + modal: forms, + urlInput: null, + linkDefaultRel: this.options.linkRelDefault, + defaultRel: this.options.linkRelDefault.default || '', + currentRel: [], + linkAnchor: null, + linkValue: '' + }; + + if (typeof context.linkDefaultRel.default === 'string') context.linkDefaultRel.default = context.linkDefaultRel.default.trim(); + if (typeof context.linkDefaultRel.check_new_window === 'string') context.linkDefaultRel.check_new_window = context.linkDefaultRel.check_new_window.trim(); + if (typeof context.linkDefaultRel.check_bookmark === 'string') context.linkDefaultRel.check_bookmark = context.linkDefaultRel.check_bookmark.trim(); + + context.urlInput = forms.querySelector('.se-input-url'); + context.anchorText = forms.querySelector('._se_anchor_text'); + context.newWindowCheck = forms.querySelector('._se_anchor_check'); + context.downloadCheck = forms.querySelector('._se_anchor_download'); + context.download = forms.querySelector('._se_anchor_download_icon'); + context.preview = forms.querySelector('.se-link-preview'); + context.bookmark = forms.querySelector('._se_anchor_bookmark_icon'); + context.bookmarkButton = forms.querySelector('._se_bookmark_button'); + + /** rel */ + if (this.options.linkRel.length > 0) { + context.relButton = forms.querySelector('.se-anchor-rel-btn'); + context.relList = forms.querySelector('.se-list-layer'); + context.relPreview = forms.querySelector('.se-anchor-rel-preview'); + context.relButton.addEventListener('click', anchorPlugin.onClick_relButton.bind(this, context)); + context.relList.addEventListener('click', anchorPlugin.onClick_relList.bind(this, context)); + } + + context.newWindowCheck.addEventListener('change', anchorPlugin.onChange_newWindowCheck.bind(this, context)); + context.downloadCheck.addEventListener('change', anchorPlugin.onChange_downloadCheck.bind(this, context)); + context.urlInput.addEventListener('input', anchorPlugin.setLinkPreview.bind(this, context, this.options.linkProtocol)); + context.bookmarkButton.addEventListener('click', anchorPlugin.onClick_bookmarkButton.bind(this, context)); + }, + + on: function (contextAnchor, update) { + if (!update) { + this.plugins.anchor.init.call(this, contextAnchor); + contextAnchor.anchorText.value = this.getSelection().toString(); + } else if (contextAnchor.linkAnchor) { + this.context.dialog.updateModal = true; + contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = (contextAnchor.linkAnchor.id ? '#' + contextAnchor.linkAnchor.id : contextAnchor.linkAnchor.href); + contextAnchor.anchorText.value = contextAnchor.linkAnchor.getAttribute('alt') || contextAnchor.linkAnchor.textContent; + contextAnchor.newWindowCheck.checked = (/_blank/i.test(contextAnchor.linkAnchor.target) ? true : false); + contextAnchor.downloadCheck.checked = contextAnchor.linkAnchor.download; + } + + this.plugins.anchor.setRel.call(this, contextAnchor, (update && contextAnchor.linkAnchor) ? contextAnchor.linkAnchor.rel : contextAnchor.defaultRel); + this.plugins.anchor.setLinkPreview.call(this, contextAnchor, this.options.linkProtocol, contextAnchor.linkValue); + }, + + _closeRelMenu: null, + toggleRelList: function (contextAnchor, show) { + if (!show) { + if (this.plugins.anchor._closeRelMenu) this.plugins.anchor._closeRelMenu(); + } else { + const target = contextAnchor.relButton; + const relList = contextAnchor.relList; + this.util.addClass(target, 'active'); + relList.style.visibility = 'hidden'; + relList.style.display = 'block'; + if (!this.options.rtl) relList.style.left = (target.offsetLeft + target.offsetWidth + 1) + 'px'; + else relList.style.left = (target.offsetLeft - relList.offsetWidth - 1) + 'px'; + relList.style.top = (target.offsetTop + (target.offsetHeight / 2) - (relList.offsetHeight / 2)) + 'px'; + relList.style.visibility = ''; + + this.plugins.anchor._closeRelMenu = function (context, target, e) { + if (e && (context.relButton.contains(e.target) || context.relList.contains(e.target))) return; + this.util.removeClass(target, 'active'); + context.relList.style.display = 'none'; + this.modalForm.removeEventListener('click', this.plugins.anchor._closeRelMenu); + this.plugins.anchor._closeRelMenu = null; + }.bind(this, contextAnchor, target); + + this.modalForm.addEventListener('click', this.plugins.anchor._closeRelMenu); + } + }, + + onClick_relButton: function (contextAnchor, e) { + this.plugins.anchor.toggleRelList.call(this, contextAnchor, !this.util.hasClass(e.target, 'active')); + }, + + onClick_relList: function (contextAnchor, e) { + const target = e.target; + const cmd = target.getAttribute('data-command'); + if (!cmd) return; + + const current = contextAnchor.currentRel; + const checked = this.util.toggleClass(target, 'se-checked'); + const index = current.indexOf(cmd); + if (checked) { + if (index === -1) current.push(cmd); + } else { + if (index > -1) current.splice(index, 1); + } + + contextAnchor.relPreview.title = contextAnchor.relPreview.textContent = current.join(' '); + }, + + setRel: function (contextAnchor, relAttr) { + const relListEl = contextAnchor.relList; + const rels = contextAnchor.currentRel = !relAttr ? [] : relAttr.split(' '); + if (!relListEl) return; + + const checkedRel = relListEl.querySelectorAll('button'); + for (let i = 0, len = checkedRel.length, cmd; i < len; i++) { + cmd = checkedRel[i].getAttribute('data-command'); + if (rels.indexOf(cmd) > -1) { + this.util.addClass(checkedRel[i], 'se-checked'); + } else { + this.util.removeClass(checkedRel[i], 'se-checked'); + } + } + + contextAnchor.relPreview.title = contextAnchor.relPreview.textContent = rels.join(' '); + }, + + setLinkPreview: function (context, protocol, e) { + const preview = context.preview; + const value = typeof e === 'string' ? e : e.target.value.trim(); + const reservedProtocol = /^(mailto\:|https*\:\/\/)/.test(value); + const sameProtocol = !protocol ? false : this._w.RegExp('^' + value.substr(0, protocol.length)).test(protocol); + context.linkValue = preview.textContent = !value ? '' : (protocol && !reservedProtocol && !sameProtocol) ? protocol + value : reservedProtocol ? value : /^www\./.test(value) ? 'http://' + value : this.context.anchor.host + (/^\//.test(value) ? '' : '/') + value; + + if (value.indexOf('#') === 0) { + context.bookmark.style.display = 'block'; + this.util.addClass(context.bookmarkButton, 'active'); + } else { + context.bookmark.style.display = 'none'; + this.util.removeClass(context.bookmarkButton, 'active'); + } + + if (value.indexOf('#') === -1 && context.downloadCheck.checked) { + context.download.style.display = 'block'; + } else { + context.download.style.display = 'none'; + } + }, + + updateAnchor: function (anchor, url, alt, contextAnchor, notText) { + // bookmark + if (/^\#/.test(url)) { + anchor.id = url.substr(1); + } else { + anchor.removeAttribute('id'); + } + + // download + if (!/^\#/.test(url) && contextAnchor.downloadCheck.checked) { + anchor.setAttribute('download', alt || url); + } else { + anchor.removeAttribute('download'); + } + + // new window + if (contextAnchor.newWindowCheck.checked) anchor.target = '_blank'; + else anchor.removeAttribute('target'); + + // rel + const rel = contextAnchor.currentRel.join(' '); + if (!rel) anchor.removeAttribute('rel'); + else anchor.rel = rel; + + // est url, alt + anchor.href = url; + anchor.setAttribute('alt', alt); + anchor.textContent = notText ? '' : alt; + }, + + createAnchor: function (contextAnchor, notText) { + if (contextAnchor.linkValue.length === 0) return null; + + const url = contextAnchor.linkValue; + const anchor = contextAnchor.anchorText; + const anchorText = anchor.value.length === 0 ? url : anchor.value; + + const oA = contextAnchor.linkAnchor || this.util.createElement('A'); + this.plugins.anchor.updateAnchor(oA, url, anchorText, contextAnchor, notText); + + contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = contextAnchor.anchorText.value = ''; + + return oA; + }, + + onClick_bookmarkButton: function (contextAnchor) { + let url = contextAnchor.urlInput.value; + if (/^\#/.test(url)) { + url = url.substr(1); + contextAnchor.bookmark.style.display = 'none'; + this.util.removeClass(contextAnchor.bookmarkButton, 'active'); + } else { + url = '#' + url; + contextAnchor.bookmark.style.display = 'block'; + this.util.addClass(contextAnchor.bookmarkButton, 'active'); + contextAnchor.downloadCheck.checked = false; + contextAnchor.download.style.display = 'none'; + } + + contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = url; + contextAnchor.urlInput.focus(); + }, + + onChange_newWindowCheck: function (contextAnchor, e) { + if (typeof contextAnchor.linkDefaultRel.check_new_window !== 'string') return; + if (e.target.checked) { + this.plugins.anchor.setRel.call(this, contextAnchor, this.plugins.anchor._relMerge.call(this, contextAnchor, contextAnchor.linkDefaultRel.check_new_window)); + } else { + this.plugins.anchor.setRel.call(this, contextAnchor, this.plugins.anchor._relDelete.call(this, contextAnchor, contextAnchor.linkDefaultRel.check_new_window)); + } + }, + + onChange_downloadCheck: function (contextAnchor, e) { + if (e.target.checked) { + contextAnchor.download.style.display = 'block'; + contextAnchor.bookmark.style.display = 'none'; + this.util.removeClass(contextAnchor.bookmarkButton, 'active'); + contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = contextAnchor.urlInput.value.replace(/^\#+/, ''); + if (typeof contextAnchor.linkDefaultRel.check_bookmark === 'string') { + this.plugins.anchor.setRel.call(this, contextAnchor, this.plugins.anchor._relMerge.call(this, contextAnchor, contextAnchor.linkDefaultRel.check_bookmark)); + } + } else { + contextAnchor.download.style.display = 'none'; + if (typeof contextAnchor.linkDefaultRel.check_bookmark === 'string') { + this.plugins.anchor.setRel.call(this, contextAnchor, this.plugins.anchor._relDelete.call(this, contextAnchor, contextAnchor.linkDefaultRel.check_bookmark)); + } + } + }, + + _relMerge: function (contextAnchor, relAttr) { + const current = contextAnchor.currentRel; + if (!relAttr) return current.join(' '); + + if (/^only\:/.test(relAttr)) { + relAttr = relAttr.replace(/^only\:/, '').trim(); + contextAnchor.currentRel = relAttr.split(' '); + return relAttr; + } + + const rels = relAttr.split(' '); + for (let i = 0, len = rels.length, index; i < len; i++) { + index = current.indexOf(rels[i]); + if (index === -1) current.push(rels[i]); + } + + return current.join(' '); + }, + + _relDelete: function (contextAnchor, relAttr) { + if (!relAttr) return contextAnchor.currentRel.join(' '); + if (/^only\:/.test(relAttr)) relAttr = relAttr.replace(/^only\:/, '').trim(); + + const rels = contextAnchor.currentRel.join(' ').replace(this._w.RegExp(relAttr + '\\s*'), ''); + contextAnchor.currentRel = rels.split(' '); + return rels; + }, + + init: function (contextAnchor) { + contextAnchor.linkAnchor = null; + contextAnchor.linkValue = contextAnchor.preview.textContent = contextAnchor.urlInput.value = ''; + contextAnchor.anchorText.value = ''; + contextAnchor.newWindowCheck.checked = false; + contextAnchor.downloadCheck.checked = false; + this.plugins.anchor.setRel.call(this, contextAnchor, contextAnchor.defaultRel); + if (contextAnchor.relList) { + this.plugins.anchor.toggleRelList.call(this, contextAnchor, false); + } + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/_colorPicker.js": +/*!********************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/_colorPicker.js ***! + \********************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2018 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'colorPicker', + /** + * @description Constructor + * @param {Object} core Core object + */ + add: function (core) { + const context = core.context; + context.colorPicker = { + colorListHTML: '', + _colorInput: '', + _defaultColor: '#000', + _styleProperty: 'color', + _currentColor: '', + _colorList: [] + }; + + /** set submenu */ + context.colorPicker.colorListHTML = this.createColorList(core, this._makeColorList); + }, + + /** + * @description Create color list + * @param {Object} core Core object + * @param {Function} makeColor this._makeColorList + * @returns {String} HTML string + */ + createColorList: function (core, makeColor) { + const option = core.options; + const lang = core.lang; + const colorList = !option.colorList || option.colorList.length === 0 ? + [ + '#ff0000', '#ff5e00', '#ffe400', '#abf200', '#00d8ff', '#0055ff', '#6600ff', '#ff00dd', '#000000', + '#ffd8d8', '#fae0d4', '#faf4c0', '#e4f7ba', '#d4f4fa', '#d9e5ff', '#e8d9ff', '#ffd9fa', '#f1f1f1', + '#ffa7a7', '#ffc19e', '#faed7d', '#cef279', '#b2ebf4', '#b2ccff', '#d1b2ff', '#ffb2f5', '#bdbdbd', + '#f15f5f', '#f29661', '#e5d85c', '#bce55c', '#5cd1e5', '#6699ff', '#a366ff', '#f261df', '#8c8c8c', + '#980000', '#993800', '#998a00', '#6b9900', '#008299', '#003399', '#3d0099', '#990085', '#353535', + '#670000', '#662500', '#665c00', '#476600', '#005766', '#002266', '#290066', '#660058', '#222222' + ] : option.colorList; + + let colorArr = []; + let list = '
'; + for (let i = 0, len = colorList.length, color; i < len; i++) { + color = colorList[i]; + if (!color) continue; + + if (typeof color === 'string') { + colorArr.push(color); + if (i < len - 1) continue; + } + if (colorArr.length > 0) { + list += '
' + makeColor(colorArr) + '
'; + colorArr = []; + } + if (typeof color === 'object') { + list += '
' + makeColor(color) + '
'; + } + } + list += '' + + '
' + + '' + + '' + + '' + + '
' + + '
'; + + return list; + }, + + /** + * @description Internal function used by this.createColorList + * @param {Array} colorList Color list + * @private + */ + _makeColorList: function (colorList) { + let list = ''; + + list += '
    '; + for (let i = 0, len = colorList.length, color; i < len; i++) { + color = colorList[i]; + if (typeof color === 'string') { + list += '
  • ' + + '' + + '
  • '; + } + } + list += '
'; + + return list; + }, + + /** + * @description Displays or resets the currently selected color at color list. + * @param {Node} node Current Selected node + * @param {String|null} color Color value + */ + init: function (node, color) { + const colorPicker = this.plugins.colorPicker; + let fillColor = color ? color : colorPicker.getColorInNode.call(this, node) || this.context.colorPicker._defaultColor; + fillColor = colorPicker.isHexColor(fillColor) ? fillColor : colorPicker.rgb2hex(fillColor) || fillColor; + + const colorList = this.context.colorPicker._colorList; + if (colorList) { + for (let i = 0, len = colorList.length; i < len; i++) { + if (fillColor.toLowerCase() === colorList[i].getAttribute('data-value').toLowerCase()) { + this.util.addClass(colorList[i], 'active'); + } else { + this.util.removeClass(colorList[i], 'active'); + } + } + } + + colorPicker.setInputText.call(this, colorPicker.colorName2hex.call(this, fillColor)); + }, + + /** + * @description Store color values + * @param {String} hexColorStr Hax color value + */ + setCurrentColor: function (hexColorStr) { + this.context.colorPicker._currentColor = hexColorStr; + this.context.colorPicker._colorInput.style.borderColor = hexColorStr; + }, + + /** + * @description Set color at input element + * @param {String} hexColorStr Hax color value + */ + setInputText: function (hexColorStr) { + hexColorStr = /^#/.test(hexColorStr) ? hexColorStr : '#' + hexColorStr; + this.context.colorPicker._colorInput.value = hexColorStr; + this.plugins.colorPicker.setCurrentColor.call(this, hexColorStr); + }, + + /** + * @description Gets color value at color property of node + * @param {Node} node Selected node + * @returns {String} + */ + getColorInNode: function (node) { + let findColor = ''; + const styleProperty = this.context.colorPicker._styleProperty; + + while (node && !this.util.isWysiwygDiv(node) && findColor.length === 0) { + if (node.nodeType === 1 && node.style[styleProperty]) findColor = node.style[styleProperty]; + node = node.parentNode; + } + + return findColor; + }, + + /** + * @description Function to check hex format color + * @param {String} str Color value + */ + isHexColor: function (str) { + return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(str); + }, + + /** + * @description Function to convert hex format to a rgb color + * @param {String} rgb RGB color format + * @returns {String} + */ + rgb2hex: function (rgb) { + const rgbMatch = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); + + return (rgbMatch && rgbMatch.length === 4) ? "#" + + ("0" + parseInt(rgbMatch[1],10).toString(16)).slice(-2) + + ("0" + parseInt(rgbMatch[2],10).toString(16)).slice(-2) + + ("0" + parseInt(rgbMatch[3],10).toString(16)).slice(-2) : ''; + }, + + /** + * @description Converts color values of other formats to hex color values and returns. + * @param {String} colorName Color value + * @returns {String} + */ + colorName2hex: function (colorName) { + if (/^#/.test(colorName)) return colorName; + var temp = this.util.createElement('div'); + temp.style.display = 'none'; + temp.style.color = colorName; + var colors = this._w.getComputedStyle(this._d.body.appendChild(temp)).color.match(/\d+/g).map(function (a) { return parseInt(a,10); }); + this.util.removeItem(temp); + return (colors.length >= 3) ? '#' + (((1 << 24) + (colors[0] << 16) + (colors[1] << 8) + colors[2]).toString(16).substr(1)) : false; + } +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/_notice.js": +/*!***************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/_notice.js ***! + \***************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'notice', + /** + * @description Constructor + * @param {Object} core Core object + */ + add: function (core) { + const context = core.context; + context.notice = {}; + + /** dialog */ + let notice_div = core.util.createElement('DIV'); + let notice_span = core.util.createElement('SPAN'); + let notice_button = core.util.createElement('BUTTON'); + + notice_div.className = 'se-notice'; + notice_button.className = 'close'; + notice_button.setAttribute('aria-label', 'Close'); + notice_button.setAttribute('title', core.lang.dialogBox.close); + notice_button.innerHTML = core.icons.cancel; + + notice_div.appendChild(notice_span); + notice_div.appendChild(notice_button); + + context.notice.modal = notice_div; + context.notice.message = notice_span; + + /** add event listeners */ + notice_button.addEventListener('click', this.onClick_cancel.bind(core)); + + /** append html */ + context.element.editorArea.appendChild(notice_div); + + /** empty memory */ + notice_div = null; + }, + + /** + * @description Event when clicking the cancel button + * @param {MouseEvent} e Event object + */ + onClick_cancel: function (e) { + e.preventDefault(); + e.stopPropagation(); + this.plugins.notice.close.call(this); + }, + + /** + * @description Open the notice panel + * @param {String} text Notice message + */ + open: function (text) { + this.context.notice.message.textContent = text; + this.context.notice.modal.style.display = 'block'; + }, + + /** + * @description Open the notice panel + */ + close: function () { + this.context.notice.modal.style.display = 'none'; + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/component.js": +/*!*****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/component.js ***! + \*****************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +(function (global, factory) { + if ( true && typeof module.exports === 'object') { + module.exports = global.document ? + factory(global, true) : + function (w) { + if (!w.document) { + throw new Error('SUNEDITOR_MODULES a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } +}(typeof window !== 'undefined' ? window : this, function (window, noGlobal) { + const component = { + name: 'component', + /** + * @description Create a container for the resizing component and insert the element. + * @param {Element} cover Cover element (FIGURE) + * @param {String} className Class name of container (fixed: se-component) + * @returns {Element} Created container element + */ + set_container: function (cover, className) { + const container = this.util.createElement('DIV'); + container.className = 'se-component ' + className; + container.setAttribute('contenteditable', false); + container.appendChild(cover); + + return container; + }, + + /** + * @description Cover the target element with a FIGURE element. + * @param {Element} element Target element + */ + set_cover: function (element) { + const cover = this.util.createElement('FIGURE'); + cover.appendChild(element); + + return cover; + }, + + /** + * @description Return HTML string of caption(FIGCAPTION) element + * @returns {String} + */ + create_caption: function () { + const caption = this.util.createElement('FIGCAPTION'); + caption.setAttribute('contenteditable', true); + caption.innerHTML = '
' + this.lang.dialogBox.caption + '
'; + return caption; + } + }; + + if (typeof noGlobal === typeof undefined) { + if (!window.SUNEDITOR_MODULES) { + Object.defineProperty(window, 'SUNEDITOR_MODULES', { + enumerable: true, + writable: false, + configurable: false, + value: {} + }); + } + + Object.defineProperty(window.SUNEDITOR_MODULES, 'component', { + enumerable: true, + writable: false, + configurable: false, + value: component + }); + } + + return component; +})); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/dialog.js": +/*!**************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/dialog.js ***! + \**************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +(function (global, factory) { + if ( true && typeof module.exports === 'object') { + module.exports = global.document ? + factory(global, true) : + function (w) { + if (!w.document) { + throw new Error('SUNEDITOR_MODULES a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } +}(typeof window !== 'undefined' ? window : this, function (window, noGlobal) { + const dialog = { + name: 'dialog', + /** + * @description Constructor + * @param {Object} core Core object + */ + add: function (core) { + const context = core.context; + context.dialog = { + kind: '', + updateModal: false, + _closeSignal: false + }; + + /** dialog */ + let dialog_div = core.util.createElement('DIV'); + dialog_div.className = 'se-dialog sun-editor-common'; + + let dialog_back = core.util.createElement('DIV'); + dialog_back.className = 'se-dialog-back'; + dialog_back.style.display = 'none'; + + let dialog_area = core.util.createElement('DIV'); + dialog_area.className = 'se-dialog-inner'; + dialog_area.style.display = 'none'; + + dialog_div.appendChild(dialog_back); + dialog_div.appendChild(dialog_area); + + context.dialog.modalArea = dialog_div; + context.dialog.back = dialog_back; + context.dialog.modal = dialog_area; + + /** add event listeners */ + context.dialog.modal.addEventListener('mousedown', this._onMouseDown_dialog.bind(core)); + context.dialog.modal.addEventListener('click', this._onClick_dialog.bind(core)); + + /** append html */ + context.element.relative.appendChild(dialog_div); + + /** empty memory */ + dialog_div = null, dialog_back = null, dialog_area = null; + }, + + /** + * @description Event to control the behavior of closing the dialog + * @param {MouseEvent} e Event object + * @private + */ + _onMouseDown_dialog: function (e) { + if (/se-dialog-inner/.test(e.target.className)) { + this.context.dialog._closeSignal = true; + } else { + this.context.dialog._closeSignal = false; + } + }, + + /** + * @description Event to close the window when the outside area of the dialog or close button is click + * @param {MouseEvent} e Event object + * @private + */ + _onClick_dialog: function (e) { + if (/close/.test(e.target.getAttribute('data-command')) || this.context.dialog._closeSignal) { + this.plugins.dialog.close.call(this); + } + }, + + /** + * @description Open a Dialog plugin + * @param {String} kind Dialog plugin name + * @param {Boolean} update Whether it will open for update ('image' === this.currentControllerName) + */ + open: function (kind, update) { + if (this.modalForm) return false; + if (this.plugins.dialog._bindClose) { + this._d.removeEventListener('keydown', this.plugins.dialog._bindClose); + this.plugins.dialog._bindClose = null; + } + + this.plugins.dialog._bindClose = function (e) { + if (!/27/.test(e.keyCode)) return; + this.plugins.dialog.close.call(this); + }.bind(this); + this._d.addEventListener('keydown', this.plugins.dialog._bindClose); + + this.context.dialog.updateModal = update; + + if (this.options.popupDisplay === 'full') { + this.context.dialog.modalArea.style.position = 'fixed'; + } else { + this.context.dialog.modalArea.style.position = 'absolute'; + } + + this.context.dialog.kind = kind; + this.modalForm = this.context[kind].modal; + const focusElement = this.context[kind].focusElement; + + if (typeof this.plugins[kind].on === 'function') this.plugins[kind].on.call(this, update); + + this.context.dialog.modalArea.style.display = 'block'; + this.context.dialog.back.style.display = 'block'; + // this.context.dialog.modal.style.display = 'flex'; @v3 + this.context.dialog.modal.style.display = 'block'; + this.modalForm.style.display = 'block'; + + if (focusElement) focusElement.focus(); + }, + + _bindClose: null, + + /** + * @description Close a Dialog plugin + * The plugin's "init" method is called. + */ + close: function () { + if (this.plugins.dialog._bindClose) { + this._d.removeEventListener('keydown', this.plugins.dialog._bindClose); + this.plugins.dialog._bindClose = null; + } + + const kind = this.context.dialog.kind; + this.modalForm.style.display = 'none'; + this.context.dialog.back.style.display = 'none'; + this.context.dialog.modalArea.style.display = 'none'; + this.context.dialog.updateModal = false; + if (typeof this.plugins[kind].init === 'function') this.plugins[kind].init.call(this); + this.context.dialog.kind = ''; + this.modalForm = null; + this.focus(); + } + }; + + if (typeof noGlobal === typeof undefined) { + if (!window.SUNEDITOR_MODULES) { + Object.defineProperty(window, 'SUNEDITOR_MODULES', { + enumerable: true, + writable: false, + configurable: false, + value: {} + }); + } + + Object.defineProperty(window.SUNEDITOR_MODULES, 'dialog', { + enumerable: true, + writable: false, + configurable: false, + value: dialog + }); + } + + return dialog; +})); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/fileBrowser.js": +/*!*******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/fileBrowser.js ***! + \*******************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +(function (global, factory) { + if ( true && typeof module.exports === 'object') { + module.exports = global.document ? + factory(global, true) : + function (w) { + if (!w.document) { + throw new Error('SUNEDITOR_MODULES a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } +}(typeof window !== 'undefined' ? window : this, function (window, noGlobal) { + const fileBrowser = { + name: 'fileBrowser', + _xmlHttp: null, + _loading: null, + + /** + * @description Constructor + * @param {Object} core Core object + */ + add: function (core) { + const context = core.context; + context.fileBrowser = { + _closeSignal: false, + area: null, + header: null, + tagArea: null, + body: null, + list: null, + tagElements: null, + items: [], + selectedTags: [], + selectorHandler: null, + contextPlugin: '', + columnSize: 4 + }; + + /** fileBrowser */ + let browser_div = core.util.createElement('DIV'); + browser_div.className = 'se-file-browser sun-editor-common'; + + let back = core.util.createElement('DIV'); + back.className = 'se-file-browser-back'; + + let content = core.util.createElement('DIV'); + content.className = 'se-file-browser-inner'; + content.innerHTML = this.set_browser(core); + + browser_div.appendChild(back); + browser_div.appendChild(content); + this._loading = browser_div.querySelector('.se-loading-box'); + + context.fileBrowser.area = browser_div; + context.fileBrowser.header = content.querySelector('.se-file-browser-header'); + context.fileBrowser.titleArea = content.querySelector('.se-file-browser-title'); + context.fileBrowser.tagArea = content.querySelector('.se-file-browser-tags'); + context.fileBrowser.body = content.querySelector('.se-file-browser-body'); + context.fileBrowser.list = content.querySelector('.se-file-browser-list'); + + /** add event listeners */ + context.fileBrowser.tagArea.addEventListener('click', this.onClickTag.bind(core)); + context.fileBrowser.list.addEventListener('click', this.onClickFile.bind(core)); + content.addEventListener('mousedown', this._onMouseDown_browser.bind(core)); + content.addEventListener('click', this._onClick_browser.bind(core)); + + /** append html */ + context.element.relative.appendChild(browser_div); + + /** empty memory */ + browser_div = null, back = null, content = null; + }, + + set_browser: function (core) { + const lang = core.lang; + + return '
' + + '
' + + '' + + '' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
'; + }, + + /** + * @description Event to control the behavior of closing the browser + * @param {MouseEvent} e Event object + * @private + */ + _onMouseDown_browser: function (e) { + if (/se-file-browser-inner/.test(e.target.className)) { + this.context.fileBrowser._closeSignal = true; + } else { + this.context.fileBrowser._closeSignal = false; + } + }, + + /** + * @description Event to close the window when the outside area of the browser or close button is click + * @param {MouseEvent} e Event object + * @private + */ + _onClick_browser: function (e) { + e.stopPropagation(); + + if (/close/.test(e.target.getAttribute('data-command')) || this.context.fileBrowser._closeSignal) { + this.plugins.fileBrowser.close.call(this); + } + }, + + /** + * @description Open a file browser plugin + * @param {String} pluginName Plugin name using the file browser + * @param {Function|null} selectorHandler When the function comes as an argument value, it substitutes "context.selectorHandler". + */ + open: function (pluginName, selectorHandler) { + if (this.plugins.fileBrowser._bindClose) { + this._d.removeEventListener('keydown', this.plugins.fileBrowser._bindClose); + this.plugins.fileBrowser._bindClose = null; + } + + this.plugins.fileBrowser._bindClose = function (e) { + if (!/27/.test(e.keyCode)) return; + this.plugins.fileBrowser.close.call(this); + }.bind(this); + this._d.addEventListener('keydown', this.plugins.fileBrowser._bindClose); + + const fileBrowserContext = this.context.fileBrowser; + fileBrowserContext.contextPlugin = pluginName; + fileBrowserContext.selectorHandler = selectorHandler; + + const pluginContext = this.context[pluginName]; + const listClassName = pluginContext.listClass; + if (!this.util.hasClass(fileBrowserContext.list, listClassName)) { + fileBrowserContext.list.className = 'se-file-browser-list ' + listClassName; + } + + if (this.options.popupDisplay === 'full') { + fileBrowserContext.area.style.position = 'fixed'; + } else { + fileBrowserContext.area.style.position = 'absolute'; + } + + fileBrowserContext.titleArea.textContent = pluginContext.title; + fileBrowserContext.area.style.display = 'block'; + + this.plugins.fileBrowser._drawFileList.call(this, this.context[pluginName].url); + }, + + _bindClose: null, + + /** + * @description Close a fileBrowser plugin + * The plugin's "init" method is called. + */ + close: function () { + const fileBrowserPlugin = this.plugins.fileBrowser; + + if (fileBrowserPlugin._xmlHttp) { + fileBrowserPlugin._xmlHttp.abort(); + } + + if (fileBrowserPlugin._bindClose) { + this._d.removeEventListener('keydown', fileBrowserPlugin._bindClose); + fileBrowserPlugin._bindClose = null; + } + + const fileBrowserContext = this.context.fileBrowser; + fileBrowserContext.area.style.display = 'none'; + fileBrowserContext.selectorHandler = null; + fileBrowserContext.selectedTags = []; + fileBrowserContext.items = []; + fileBrowserContext.list.innerHTML = fileBrowserContext.tagArea.innerHTML = fileBrowserContext.titleArea.textContent = ''; + + if (typeof this.plugins[fileBrowserContext.contextPlugin].init === 'function') this.plugins[fileBrowserContext.contextPlugin].init.call(this); + fileBrowserContext.contextPlugin = ''; + }, + + /** + * @description Show file browser loading box + */ + showBrowserLoading: function () { + this._loading.style.display = 'block'; + }, + + /** + * @description Close file browser loading box + */ + closeBrowserLoading: function () { + this._loading.style.display = 'none'; + }, + + _drawFileList: function (url) { + const fileBrowserPlugin = this.plugins.fileBrowser; + + const xmlHttp = fileBrowserPlugin._xmlHttp = this.util.getXMLHttpRequest(); + xmlHttp.onreadystatechange = fileBrowserPlugin._callBackGet.bind(this, xmlHttp); + xmlHttp.open('get', url, true); + xmlHttp.send(null); + + this.plugins.fileBrowser.showBrowserLoading(); + }, + + _callBackGet: function (xmlHttp) { + if (xmlHttp.readyState === 4) { + this.plugins.fileBrowser._xmlHttp = null; + if (xmlHttp.status === 200) { + try { + this.plugins.fileBrowser._drawListItem.call(this, JSON.parse(xmlHttp.responseText).result, true); + } catch (e) { + throw Error('[SUNEDITOR.fileBrowser.drawList.fail] cause : "' + e.message + '"'); + } finally { + this.plugins.fileBrowser.closeBrowserLoading(); + this.context.fileBrowser.body.style.maxHeight = (this._w.innerHeight - this.context.fileBrowser.header.offsetHeight - 50) + 'px'; + } + } else { // exception + this.plugins.fileBrowser.closeBrowserLoading(); + if (xmlHttp.status !== 0) { + const res = !xmlHttp.responseText ? xmlHttp : JSON.parse(xmlHttp.responseText); + const err = '[SUNEDITOR.fileBrowser.get.serverException] status: ' + xmlHttp.status + ', response: ' + (res.errorMessage || xmlHttp.responseText); + throw Error(err); + } + } + } + }, + + _drawListItem: function (items, update) { + const fileBrowserContext = this.context.fileBrowser; + const pluginContext = this.context[fileBrowserContext.contextPlugin]; + + const _tags = []; + const len = items.length; + const columnSize = pluginContext.columnSize || fileBrowserContext.columnSize; + const splitSize = columnSize <= 1 ? 1 : (Math.round(len/columnSize) || 1); + const drawItemHandler = pluginContext.itemTemplateHandler; + + let tagsHTML = ''; + let listHTML = '
'; + let columns = 1; + for (let i = 0, item, tags; i < len; i++) { + item = items[i]; + tags = !item.tag ? [] : typeof item.tag === 'string' ? item.tag.split(',') : item.tag; + tags = item.tag = tags.map(function (v) { return v.trim(); }); + listHTML += drawItemHandler(item); + + if ((i + 1) % splitSize === 0 && columns < columnSize && (i + 1) < len) { + columns++; + listHTML += '
'; + } + + if (update && tags.length > 0) { + for (let t = 0, tLen = tags.length, tag; t < tLen; t++) { + tag = tags[t]; + if (tag && _tags.indexOf(tag) === -1) { + _tags.push(tag); + tagsHTML += '' + tag + ''; + } + } + } + } + listHTML += '
'; + + fileBrowserContext.list.innerHTML = listHTML; + + if (update) { + fileBrowserContext.items = items; + fileBrowserContext.tagArea.innerHTML = tagsHTML; + fileBrowserContext.tagElements = fileBrowserContext.tagArea.querySelectorAll('A'); + } + }, + + onClickTag: function (e) { + const target = e.target; + if (!this.util.isAnchor(target)) return; + + const tagName = target.textContent; + const fileBrowserPlugin = this.plugins.fileBrowser; + const fileBrowserContext = this.context.fileBrowser; + + const selectTag = fileBrowserContext.tagArea.querySelector('a[title="' + tagName + '"]'); + const selectedTags = fileBrowserContext.selectedTags; + const sTagIndex = selectedTags.indexOf(tagName); + + if (sTagIndex > -1){ + selectedTags.splice(sTagIndex, 1); + this.util.removeClass(selectTag, 'on'); + } else { + selectedTags.push(tagName); + this.util.addClass(selectTag, 'on'); + } + + fileBrowserPlugin._drawListItem.call(this, + selectedTags.length === 0 ? + fileBrowserContext.items : + fileBrowserContext.items.filter(function (item) { + return item.tag.some(function (tag) { + return selectedTags.indexOf(tag) > -1; + }); + }), false); + }, + + onClickFile: function (e) { + e.preventDefault(); + e.stopPropagation(); + + const fileBrowserContext = this.context.fileBrowser; + const listEl = fileBrowserContext.list; + let target = e.target; + let command = null; + + if (target === listEl) return; + + while (listEl !== target.parentNode) { + command = target.getAttribute('data-command'); + if (command) break; + target = target.parentNode; + } + + if (!command) return; + + const handler = (fileBrowserContext.selectorHandler || this.context[fileBrowserContext.contextPlugin].selectorHandler); + this.plugins.fileBrowser.close.call(this); + handler(target); + } + }; + + if (typeof noGlobal === typeof undefined) { + if (!window.SUNEDITOR_MODULES) { + Object.defineProperty(window, 'SUNEDITOR_MODULES', { + enumerable: true, + writable: false, + configurable: false, + value: {} + }); + } + + Object.defineProperty(window.SUNEDITOR_MODULES, 'fileBrowser', { + enumerable: true, + writable: false, + configurable: false, + value: fileBrowser + }); + } + + return fileBrowser; +})); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/fileManager.js": +/*!*******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/fileManager.js ***! + \*******************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +(function (global, factory) { + if ( true && typeof module.exports === 'object') { + module.exports = global.document ? + factory(global, true) : + function (w) { + if (!w.document) { + throw new Error('SUNEDITOR_MODULES a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } +}(typeof window !== 'undefined' ? window : this, function (window, noGlobal) { + const fileManager = { + name: 'fileManager', + _xmlHttp: null, + + _checkMediaComponent: function (tag) { + if (/IMG/i.test(tag)) { + return !/FIGURE/i.test(tag.parentElement.nodeName) || !/FIGURE/i.test(tag.parentElement.parentElement.nodeName); + } else if (/VIDEO/i.test(tag)) { + return !/FIGURE/i.test(tag.parentElement.nodeName); + } + return true; + }, + + /** + * @description Upload the file to the server. + * @param {String} uploadUrl Upload server url + * @param {Object|null} uploadHeader Request header + * @param {FormData} formData FormData in body + * @param {Function|null} callBack Success call back function + * @param {Function|null} errorCallBack Error call back function + * @example this.plugins.fileManager.upload.call(this, imageUploadUrl, this.options.imageUploadHeader, formData, this.plugins.image.callBack_imgUpload.bind(this, info), this.functions.onImageUploadError); + */ + upload: function (uploadUrl, uploadHeader, formData, callBack, errorCallBack) { + this.showLoading(); + const filePlugin = this.plugins.fileManager; + const xmlHttp = filePlugin._xmlHttp = this.util.getXMLHttpRequest(); + + xmlHttp.onreadystatechange = filePlugin._callBackUpload.bind(this, xmlHttp, callBack, errorCallBack); + xmlHttp.open('post', uploadUrl, true); + if(uploadHeader !== null && typeof uploadHeader === 'object' && this._w.Object.keys(uploadHeader).length > 0){ + for(let key in uploadHeader){ + xmlHttp.setRequestHeader(key, uploadHeader[key]); + } + } + xmlHttp.send(formData); + }, + + _callBackUpload: function (xmlHttp, callBack, errorCallBack) { + if (xmlHttp.readyState === 4) { + if (xmlHttp.status === 200) { + try { + callBack(xmlHttp); + } catch (e) { + throw Error('[SUNEDITOR.fileManager.upload.callBack.fail] cause : "' + e.message + '"'); + } finally { + this.closeLoading(); + } + } else { // exception + this.closeLoading(); + const res = !xmlHttp.responseText ? xmlHttp : JSON.parse(xmlHttp.responseText); + if (typeof errorCallBack !== 'function' || errorCallBack('', res, this)) { + const err = '[SUNEDITOR.fileManager.upload.serverException] status: ' + xmlHttp.status + ', response: ' + (res.errorMessage || xmlHttp.responseText); + this.functions.noticeOpen(err); + throw Error(err); + } + } + } + }, + + /** + * @description Checke the file's information and modify the tag that does not fit the format. + * @param {String} pluginName Plugin name + * @param {Array} tagNames Tag array to check + * @param {Function|null} uploadEventHandler Event handler to process updated file info after checking (used in "setInfo") + * @param {Function} modifyHandler A function to modify a tag that does not fit the format (Argument value: Tag element) + * @param {Boolean} resizing True if the plugin is using a resizing module + * @example + * const modifyHandler = function (tag) { + * imagePlugin.onModifyMode.call(this, tag, null); + * imagePlugin.openModify.call(this, true); + * imagePlugin.update_image.call(this, true, false, true); + * }.bind(this); + * this.plugins.fileManager.checkInfo.call(this, 'image', ['img'], this.functions.onImageUpload, modifyHandler, true); + */ + checkInfo: function (pluginName, tagNames, uploadEventHandler, modifyHandler, resizing) { + let tags = []; + for (let i = 0, len = tagNames.length; i < len; i++) { + tags = tags.concat([].slice.call(this.context.element.wysiwyg.getElementsByTagName(tagNames[i]))); + } + + const fileManagerPlugin = this.plugins.fileManager; + const context = this.context[pluginName]; + const infoList = context._infoList; + const setFileInfo = fileManagerPlugin.setInfo.bind(this); + + if (tags.length === infoList.length) { + // reset + if (this._componentsInfoReset) { + for (let i = 0, len = tags.length; i < len; i++) { + setFileInfo(pluginName, tags[i], uploadEventHandler, null, resizing); + } + return ; + } else { + let infoUpdate = false; + for (let i = 0, len = infoList.length, info; i < len; i++) { + info = infoList[i]; + if (tags.filter(function (t) { return info.src === t.src && info.index.toString() === t.getAttribute('data-index'); }).length === 0) { + infoUpdate = true; + break; + } + } + // pass + if (!infoUpdate) return; + } + } + + // check + const _resize_plugin = resizing ? this.context.resizing._resize_plugin : ''; + if (resizing) this.context.resizing._resize_plugin = pluginName; + const currentTags = []; + const infoIndex = []; + for (let i = 0, len = infoList.length; i < len; i++) { + infoIndex[i] = infoList[i].index; + } + + for (let i = 0, len = tags.length, tag; i < len; i++) { + tag = tags[i]; + if (!this.util.getParentElement(tag, this.util.isMediaComponent) || !fileManagerPlugin._checkMediaComponent(tag)) { + currentTags.push(context._infoIndex); + modifyHandler(tag); + } else if (!tag.getAttribute('data-index') || infoIndex.indexOf(tag.getAttribute('data-index') * 1) < 0) { + currentTags.push(context._infoIndex); + tag.removeAttribute('data-index'); + setFileInfo(pluginName, tag, uploadEventHandler, null, resizing); + } else { + currentTags.push(tag.getAttribute('data-index') * 1); + } + } + + for (let i = 0, dataIndex; i < infoList.length; i++) { + dataIndex = infoList[i].index; + if (currentTags.indexOf(dataIndex) > -1) continue; + + infoList.splice(i, 1); + if (typeof uploadEventHandler === 'function') uploadEventHandler(null, dataIndex, 'delete', null, 0, this); + i--; + } + + if (resizing) this.context.resizing._resize_plugin = _resize_plugin; + }, + + /** + * @description Create info object of file and add it to "_infoList" (this.context[pluginName]._infoList[]) + * @param {String} pluginName Plugin name + * @param {Element} element + * @param {Function|null} uploadEventHandler Event handler to process updated file info (created in setInfo) + * @param {Object|null} file + * @param {Boolean} resizing True if the plugin is using a resizing module + * @example + * uploadCallBack {.. file = { name: fileList[i].name, size: fileList[i].size }; + * this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true); + */ + setInfo: function (pluginName, element, uploadEventHandler, file, resizing) { + const _resize_plugin = resizing ? this.context.resizing._resize_plugin : ''; + if (resizing) this.context.resizing._resize_plugin = pluginName; + + const plguin = this.plugins[pluginName]; + const context = this.context[pluginName]; + const infoList = context._infoList; + let dataIndex = element.getAttribute('data-index'); + let info = null; + let state = ''; + + if (!file) { + file = { + 'name': element.getAttribute('data-file-name') || (typeof element.src === 'string' ? element.src.split('/').pop() : ''), + 'size': element.getAttribute('data-file-size') || 0 + }; + } + + // create + if (!dataIndex || this._componentsInfoInit) { + state = 'create'; + dataIndex = context._infoIndex++; + + element.setAttribute('data-index', dataIndex); + element.setAttribute('data-file-name', file.name); + element.setAttribute('data-file-size', file.size); + + info = { + src: element.src, + index: dataIndex * 1, + name: file.name, + size: file.size + }; + + infoList.push(info); + } else { // update + state = 'update'; + dataIndex *= 1; + + for (let i = 0, len = infoList.length; i < len; i++) { + if (dataIndex === infoList[i].index) { + info = infoList[i]; + break; + } + } + + if (!info) { + dataIndex = context._infoIndex++; + info = { index: dataIndex }; + infoList.push(info); + } + + info.src = element.src; + info.name = element.getAttribute("data-file-name"); + info.size = element.getAttribute("data-file-size") * 1; + } + + // method bind + info.element = element; + info.delete = plguin.destroy.bind(this, element); + info.select = function (element) { + element.scrollIntoView(true); + this._w.setTimeout(plguin.select.bind(this, element)); + }.bind(this, element); + + if (resizing) { + if (!element.getAttribute('origin-size') && element.naturalWidth) { + element.setAttribute('origin-size', element.naturalWidth + ',' + element.naturalHeight); + } + + if (!element.getAttribute('data-origin')) { + const container = this.util.getParentElement(element, this.util.isMediaComponent); + const cover = this.util.getParentElement(element, 'FIGURE'); + + const w = this.plugins.resizing._module_getSizeX.call(this, context, element, cover, container); + const h = this.plugins.resizing._module_getSizeY.call(this, context, element, cover, container); + element.setAttribute('data-origin', w + ',' + h); + element.setAttribute('data-size', w + ',' + h); + } + + if (!element.style.width) { + const size = (element.getAttribute('data-size') || element.getAttribute('data-origin') || '').split(','); + plguin.onModifyMode.call(this, element, null); + plguin.applySize.call(this, size[0], size[1]); + } + + this.context.resizing._resize_plugin = _resize_plugin; + } + + if (typeof uploadEventHandler === 'function') uploadEventHandler(element, dataIndex, state, info, --context._uploadFileLength < 0 ? 0 : context._uploadFileLength, this); + }, + + /** + * @description Delete info object at "_infoList" + * @param {String} pluginName Plugin name + * @param {Number} index index of info object (this.context[pluginName]._infoList[].index) + * @param {Function|null} uploadEventHandler Event handler to process updated file info (created in setInfo) + */ + deleteInfo: function (pluginName, index, uploadEventHandler) { + if (index >= 0) { + const infoList = this.context[pluginName]._infoList; + + for (let i = 0, len = infoList.length; i < len; i++) { + if (index === infoList[i].index) { + infoList.splice(i, 1); + if (typeof uploadEventHandler === 'function') uploadEventHandler(null, index, 'delete', null, 0, this); + return; + } + } + } + }, + + /** + * @description Reset info object and "_infoList = []", "_infoIndex = 0" + * @param {String} pluginName Plugin name + * @param {Function|null} uploadEventHandler Event handler to process updated file info (created in setInfo) + */ + resetInfo: function (pluginName, uploadEventHandler) { + const context = this.context[pluginName]; + + if (typeof uploadEventHandler === 'function') { + const infoList = context._infoList; + for (let i = 0, len = infoList.length; i < len; i++) { + uploadEventHandler(null, infoList[i].index, 'delete', null, 0, this); + } + } + + context._infoList = []; + context._infoIndex = 0; + } + }; + + if (typeof noGlobal === typeof undefined) { + if (!window.SUNEDITOR_MODULES) { + Object.defineProperty(window, 'SUNEDITOR_MODULES', { + enumerable: true, + writable: false, + configurable: false, + value: {} + }); + } + + Object.defineProperty(window.SUNEDITOR_MODULES, 'fileManager', { + enumerable: true, + writable: false, + configurable: false, + value: fileManager + }); + } + + return fileManager; +})); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/modules/resizing.js": +/*!****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/modules/resizing.js ***! + \****************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +(function (global, factory) { + if ( true && typeof module.exports === 'object') { + module.exports = global.document ? + factory(global, true) : + function (w) { + if (!w.document) { + throw new Error('SUNEDITOR_MODULES a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } +}(typeof window !== 'undefined' ? window : this, function (window, noGlobal) { + const resizing = { + name: 'resizing', + /** + * @description Constructor + * Require context properties when resizing module + inputX: Element, + inputY: Element, + _container: null, + _cover: null, + _element: null, + _element_w: 1, + _element_h: 1, + _element_l: 0, + _element_t: 0, + _defaultSizeX: 'auto', + _defaultSizeY: 'auto', + _origin_w: core.options.imageWidth === 'auto' ? '' : core.options.imageWidth, + _origin_h: core.options.imageHeight === 'auto' ? '' : core.options.imageHeight, + _proportionChecked: true, + // -- select function -- + _resizing: core.options.imageResizing, + _resizeDotHide: !core.options.imageHeightShow, + _rotation: core.options.imageRotation, + _onlyPercentage: core.options.imageSizeOnlyPercentage, + _ratio: false, + _ratioX: 1, + _ratioY: 1 + _captionShow: true, + // -- when used caption (_captionShow: true) -- + _caption: null, + _captionChecked: false, + captionCheckEl: null, + * @param {Object} core Core object + */ + add: function (core) { + const icons = core.icons; + const context = core.context; + context.resizing = { + _resizeClientX: 0, + _resizeClientY: 0, + _resize_plugin: '', + _resize_w: 0, + _resize_h: 0, + _origin_w: 0, + _origin_h: 0, + _rotateVertical: false, + _resize_direction: '', + _move_path: null, + _isChange: false, + alignIcons: { + basic: icons.align_justify, + left: icons.align_left, + right: icons.align_right, + center: icons.align_center + } + }; + + /** resize controller, button */ + let resize_div_container = this.setController_resize(core); + context.resizing.resizeContainer = resize_div_container; + + context.resizing.resizeDiv = resize_div_container.querySelector('.se-modal-resize'); + context.resizing.resizeDot = resize_div_container.querySelector('.se-resize-dot'); + context.resizing.resizeDisplay = resize_div_container.querySelector('.se-resize-display'); + + let resize_button = this.setController_button(core); + context.resizing.resizeButton = resize_button; + + let resize_handles = context.resizing.resizeHandles = context.resizing.resizeDot.querySelectorAll('span'); + context.resizing.resizeButtonGroup = resize_button.querySelector('._se_resizing_btn_group'); + context.resizing.rotationButtons = resize_button.querySelectorAll('._se_resizing_btn_group ._se_rotation'); + context.resizing.percentageButtons = resize_button.querySelectorAll('._se_resizing_btn_group ._se_percentage'); + + context.resizing.alignMenu = resize_button.querySelector('.se-resizing-align-list'); + context.resizing.alignMenuList = context.resizing.alignMenu.querySelectorAll('button'); + + context.resizing.alignButton = resize_button.querySelector('._se_resizing_align_button'); + context.resizing.autoSizeButton = resize_button.querySelector('._se_resizing_btn_group ._se_auto_size'); + context.resizing.captionButton = resize_button.querySelector('._se_resizing_caption_button'); + + /** add event listeners */ + resize_div_container.addEventListener('mousedown', function (e) { e.preventDefault(); }); + resize_handles[0].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[1].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[2].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[3].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[4].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[5].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[6].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_handles[7].addEventListener('mousedown', this.onMouseDown_resize_handle.bind(core)); + resize_button.addEventListener('click', this.onClick_resizeButton.bind(core)); + + /** append html */ + context.element.relative.appendChild(resize_div_container); + context.element.relative.appendChild(resize_button); + + /** empty memory */ + resize_div_container = null, resize_button = null, resize_handles = null; + }, + + /** resize controller, button (image, iframe, video) */ + setController_resize: function (core) { + const resize_container = core.util.createElement('DIV'); + + resize_container.className = 'se-controller se-resizing-container'; + resize_container.style.display = 'none'; + resize_container.innerHTML = '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
'; + + return resize_container; + }, + + setController_button: function (core) { + const lang = core.lang; + const icons = core.icons; + const resize_button = core.util.createElement("DIV"); + + resize_button.className = "se-controller se-controller-resizing"; + resize_button.innerHTML = '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
    ' + + '
  • ' + + '
  • ' + + '
  • ' + + '
  • ' + + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
'; + + return resize_button; + }, + + /** + * @description Gets the width size + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + * @param {Element} element Target element + * @param {Element} cover Cover element (FIGURE) + * @param {Element} container Container element (DIV.se-component) + * @returns {String} + */ + _module_getSizeX: function (contextPlugin, element, cover, container) { + if (!element) element = contextPlugin._element; + if (!cover) cover = contextPlugin._cover; + if (!container) container = contextPlugin._container; + + if (!element) return ''; + + return !/%$/.test(element.style.width) ? element.style.width : ((container && this.util.getNumber(container.style.width, 2)) || 100) + '%'; + }, + + /** + * @description Gets the height size + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + * @param {Element} element Target element + * @param {Element} cover Cover element (FIGURE) + * @param {Element} container Container element (DIV.se-component) + * @returns {String} + */ + _module_getSizeY: function (contextPlugin, element, cover, container) { + if (!element) element = contextPlugin._element; + if (!cover) cover = contextPlugin._cover; + if (!container) container = contextPlugin._container; + + if (!container || !cover) return (element && element.style.height) || ''; + + return this.util.getNumber(cover.style.paddingBottom, 0) > 0 && !this.context.resizing._rotateVertical ? cover.style.height : (!/%$/.test(element.style.height) || !/%$/.test(element.style.width) ? element.style.height : ((container && this.util.getNumber(container.style.height, 2)) || 100) + '%'); + }, + + /** + * @description Called at the "openModify" to put the size of the current target into the size input element. + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + * @param {Object} pluginObj Plugin object + */ + _module_setModifyInputSize: function (contextPlugin, pluginObj) { + const percentageRotation = contextPlugin._onlyPercentage && this.context.resizing._rotateVertical; + contextPlugin.proportion.checked = contextPlugin._proportionChecked = contextPlugin._element.getAttribute('data-proportion') !== 'false'; + + let x = percentageRotation ? '' : this.plugins.resizing._module_getSizeX.call(this, contextPlugin); + if (x === contextPlugin._defaultSizeX) x = ''; + if (contextPlugin._onlyPercentage) x = this.util.getNumber(x, 2); + contextPlugin.inputX.value = x; + pluginObj.setInputSize.call(this, 'x'); + + if (!contextPlugin._onlyPercentage) { + let y = percentageRotation ? '' : this.plugins.resizing._module_getSizeY.call(this, contextPlugin); + if (y === contextPlugin._defaultSizeY) y = ''; + if (contextPlugin._onlyPercentage) y = this.util.getNumber(y, 2); + contextPlugin.inputY.value = y; + } + + contextPlugin.inputX.disabled = percentageRotation ? true : false; + contextPlugin.inputY.disabled = percentageRotation ? true : false; + contextPlugin.proportion.disabled = percentageRotation ? true : false; + + pluginObj.setRatio.call(this); + }, + + /** + * @description It is called in "setInputSize" (input tag keyupEvent), + * checks the value entered in the input tag, + * calculates the ratio, and sets the calculated value in the input tag of the opposite size. + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + * @param {String} xy 'x': width, 'y': height + */ + _module_setInputSize: function (contextPlugin, xy) { + if (contextPlugin._onlyPercentage) { + if (xy === 'x' && contextPlugin.inputX.value > 100) contextPlugin.inputX.value = 100; + return; + } + + if (contextPlugin.proportion.checked && contextPlugin._ratio && /\d/.test(contextPlugin.inputX.value) && /\d/.test(contextPlugin.inputY.value)) { + const xUnit = contextPlugin.inputX.value.replace(/\d+|\./g, '') || contextPlugin.sizeUnit; + const yUnit = contextPlugin.inputY.value.replace(/\d+|\./g, '') || contextPlugin.sizeUnit; + + if (xUnit !== yUnit) return; + + const dec = xUnit === '%' ? 2 : 0; + + if (xy === 'x') { + contextPlugin.inputY.value = this.util.getNumber(contextPlugin._ratioY * this.util.getNumber(contextPlugin.inputX.value, dec), dec) + yUnit; + } else { + contextPlugin.inputX.value = this.util.getNumber(contextPlugin._ratioX * this.util.getNumber(contextPlugin.inputY.value, dec), dec) + xUnit; + } + } + }, + + /** + * @description It is called in "setRatio" (input and proportionCheck tags changeEvent), + * checks the value of the input tag, calculates the ratio, and resets it in the input tag. + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + */ + _module_setRatio: function (contextPlugin) { + const xValue = contextPlugin.inputX.value; + const yValue = contextPlugin.inputY.value; + + if (contextPlugin.proportion.checked && /\d+/.test(xValue) && /\d+/.test(yValue)) { + const xUnit = xValue.replace(/\d+|\./g, '') || contextPlugin.sizeUnit; + const yUnit = yValue.replace(/\d+|\./g, '') || contextPlugin.sizeUnit; + + if (xUnit !== yUnit) { + contextPlugin._ratio = false; + } else if (!contextPlugin._ratio) { + const x = this.util.getNumber(xValue, 0); + const y = this.util.getNumber(yValue, 0); + + contextPlugin._ratio = true; + contextPlugin._ratioX = x / y; + contextPlugin._ratioY = y / x; + } + } else { + contextPlugin._ratio = false; + } + }, + + /** + * @description Revert size of element to origin size (plugin._origin_w, plugin._origin_h) + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + */ + _module_sizeRevert: function (contextPlugin) { + if (contextPlugin._onlyPercentage) { + contextPlugin.inputX.value = contextPlugin._origin_w > 100 ? 100 : contextPlugin._origin_w; + } else { + contextPlugin.inputX.value = contextPlugin._origin_w; + contextPlugin.inputY.value = contextPlugin._origin_h; + } + }, + + /** + * @description Save the size data (element.setAttribute("data-size")) + * Used at the "setSize" method + * @param {Object} contextPlugin context object of plugin (core.context[plugin]) + */ + _module_saveCurrentSize: function (contextPlugin) { + const x = this.plugins.resizing._module_getSizeX.call(this, contextPlugin); + const y = this.plugins.resizing._module_getSizeY.call(this, contextPlugin); + contextPlugin._element.setAttribute('data-size', x + ',' + y); + if (!!contextPlugin._videoRatio) contextPlugin._videoRatio = y; + }, + + /** + * @description Call the resizing module + * @param {Element} targetElement Resizing target element + * @param {string} plugin Plugin name + * @returns {Object} Size of resizing div {w, h, t, l} + */ + call_controller_resize: function (targetElement, plugin) { + const contextResizing = this.context.resizing; + const contextPlugin = this.context[plugin]; + contextResizing._resize_plugin = plugin; + + const resizeContainer = contextResizing.resizeContainer; + const resizeDiv = contextResizing.resizeDiv; + const offset = this.util.getOffset(targetElement, this.context.element.wysiwygFrame); + + const isVertical = contextResizing._rotateVertical = /^(90|270)$/.test(Math.abs(targetElement.getAttribute('data-rotate')).toString()); + + const w = isVertical ? targetElement.offsetHeight : targetElement.offsetWidth; + const h = isVertical ? targetElement.offsetWidth : targetElement.offsetHeight; + const t = offset.top; + const l = offset.left - this.context.element.wysiwygFrame.scrollLeft; + + resizeContainer.style.top = t + 'px'; + resizeContainer.style.left = l + 'px'; + resizeContainer.style.width = w + 'px'; + resizeContainer.style.height = h + 'px'; + + resizeDiv.style.top = '0px'; + resizeDiv.style.left = '0px'; + resizeDiv.style.width = w + 'px'; + resizeDiv.style.height = h + 'px'; + + let align = targetElement.getAttribute('data-align') || 'basic'; + align = align === 'none' ? 'basic' : align; + + // text + const container = this.util.getParentElement(targetElement, this.util.isComponent); + const cover = this.util.getParentElement(targetElement, 'FIGURE'); + const displayX = this.plugins.resizing._module_getSizeX.call(this, contextPlugin, targetElement, cover, container) || 'auto'; + const displayY = contextPlugin._onlyPercentage && plugin === 'image' ? '' : ', ' + (this.plugins.resizing._module_getSizeY.call(this, contextPlugin, targetElement, cover, container) || 'auto'); + this.util.changeTxt(contextResizing.resizeDisplay, this.lang.dialogBox[align] + ' (' + displayX + displayY + ')'); + + // resizing display + contextResizing.resizeButtonGroup.style.display = contextPlugin._resizing ? '' : 'none'; + const resizeDotShow = contextPlugin._resizing && !contextPlugin._resizeDotHide && !contextPlugin._onlyPercentage ? 'flex' : 'none'; + const resizeHandles = contextResizing.resizeHandles; + for (let i = 0, len = resizeHandles.length; i < len; i++) { + resizeHandles[i].style.display = resizeDotShow; + } + + if (contextPlugin._resizing) { + const rotations = contextResizing.rotationButtons; + rotations[0].style.display = rotations[1].style.display = contextPlugin._rotation ? '' : 'none'; + } + + // align icon + const alignList = contextResizing.alignMenuList; + this.util.changeElement(contextResizing.alignButton.firstElementChild, contextResizing.alignIcons[align]); + for (let i = 0, len = alignList.length; i < len; i++) { + if (alignList[i].getAttribute('data-value') === align) this.util.addClass(alignList[i], 'on'); + else this.util.removeClass(alignList[i], 'on'); + } + + // percentage active + const pButtons = contextResizing.percentageButtons; + const value = /%$/.test(targetElement.style.width) && /%$/.test(container.style.width) ? (this.util.getNumber(container.style.width, 0) / 100) + '' : '' ; + for (let i = 0, len = pButtons.length; i < len; i++) { + if (pButtons[i].getAttribute('data-value') === value) { + this.util.addClass(pButtons[i], 'active'); + } else { + this.util.removeClass(pButtons[i], 'active'); + } + } + + // caption display, active + if (!contextPlugin._captionShow) { + contextResizing.captionButton.style.display = 'none'; + } else { + contextResizing.captionButton.style.display = ''; + if (this.util.getChildElement(targetElement.parentNode, 'figcaption')) { + this.util.addClass(contextResizing.captionButton, 'active'); + contextPlugin._captionChecked = true; + } else { + this.util.removeClass(contextResizing.captionButton, 'active'); + contextPlugin._captionChecked = false; + } + } + + resizeContainer.style.display = 'block'; + + const addOffset = {left: 0, top: 50}; + if (this.options.iframe) { + addOffset.left -= this.context.element.wysiwygFrame.parentElement.offsetLeft; + addOffset.top -= this.context.element.wysiwygFrame.parentElement.offsetTop; + } + + this.setControllerPosition(contextResizing.resizeButton, resizeContainer, 'bottom', addOffset); + this.controllersOn(resizeContainer, contextResizing.resizeButton, this.util.setDisabledButtons.bind(this, false, this.resizingDisabledButtons), targetElement, plugin); + this.util.setDisabledButtons(true, this.resizingDisabledButtons); + + contextResizing._resize_w = w; + contextResizing._resize_h = h; + + const originSize = (targetElement.getAttribute('origin-size') || '').split(','); + contextResizing._origin_w = originSize[0] || targetElement.naturalWidth; + contextResizing._origin_h = originSize[1] || targetElement.naturalHeight; + + return { + w: w, + h: h, + t: t, + l: l + }; + }, + + _closeAlignMenu: null, + + /** + * @description Open align submenu of module + */ + openAlignMenu: function () { + const alignButton = this.context.resizing.alignButton; + this.util.addClass(alignButton, 'on'); + this.context.resizing.alignMenu.style.top = (alignButton.offsetTop + alignButton.offsetHeight) + 'px'; + this.context.resizing.alignMenu.style.left = (alignButton.offsetLeft - alignButton.offsetWidth / 2) + 'px'; + this.context.resizing.alignMenu.style.display = 'block'; + + this.plugins.resizing._closeAlignMenu = function () { + this.util.removeClass(this.context.resizing.alignButton, 'on'); + this.context.resizing.alignMenu.style.display = 'none'; + this.removeDocEvent('click', this.plugins.resizing._closeAlignMenu); + this.plugins.resizing._closeAlignMenu = null; + }.bind(this); + + this.addDocEvent('click', this.plugins.resizing._closeAlignMenu); + }, + + /** + * @description Click event of resizing toolbar + * Performs the action of the clicked toolbar button. + * @param {MouseEvent} e Event object + */ + onClick_resizeButton: function (e) { + e.stopPropagation(); + + const target = e.target; + const command = target.getAttribute('data-command') || target.parentNode.getAttribute('data-command'); + + if (!command) return; + + const value = target.getAttribute('data-value') || target.parentNode.getAttribute('data-value'); + + const pluginName = this.context.resizing._resize_plugin; + const currentContext = this.context[pluginName]; + const contextEl = currentContext._element; + const currentModule = this.plugins[pluginName]; + + e.preventDefault(); + + if (typeof this.plugins.resizing._closeAlignMenu === 'function') { + this.plugins.resizing._closeAlignMenu(); + if (command === 'onalign') return; + } + + switch (command) { + case 'auto': + this.plugins.resizing.resetTransform.call(this, contextEl); + currentModule.setAutoSize.call(this); + this.selectComponent(contextEl, pluginName); + break; + case 'percent': + let percentY = this.plugins.resizing._module_getSizeY.call(this, currentContext); + if (this.context.resizing._rotateVertical) { + const percentage = contextEl.getAttribute('data-percentage'); + if (percentage) percentY = percentage.split(',')[1]; + } + + this.plugins.resizing.resetTransform.call(this, contextEl); + currentModule.setPercentSize.call(this, (value * 100), (this.util.getNumber(percentY, 0) === null || !/%$/.test(percentY)) ? '' : percentY); + this.selectComponent(contextEl, pluginName); + break; + case 'mirror': + const r = contextEl.getAttribute('data-rotate') || '0'; + let x = contextEl.getAttribute('data-rotateX') || ''; + let y = contextEl.getAttribute('data-rotateY') || ''; + + if ((value === 'h' && !this.context.resizing._rotateVertical) || (value === 'v' && this.context.resizing._rotateVertical)) { + y = y ? '' : '180'; + } else { + x = x ? '' : '180'; + } + + contextEl.setAttribute('data-rotateX', x); + contextEl.setAttribute('data-rotateY', y); + + this.plugins.resizing._setTransForm(contextEl, r, x, y); + break; + case 'rotate': + const contextResizing = this.context.resizing; + const slope = (contextEl.getAttribute('data-rotate') * 1) + (value * 1); + const deg = this._w.Math.abs(slope) >= 360 ? 0 : slope; + + contextEl.setAttribute('data-rotate', deg); + contextResizing._rotateVertical = /^(90|270)$/.test(this._w.Math.abs(deg).toString()); + this.plugins.resizing.setTransformSize.call(this, contextEl, null, null); + + this.selectComponent(contextEl, pluginName); + break; + case 'onalign': + this.plugins.resizing.openAlignMenu.call(this); + return; + case 'align': + const alignValue = value === 'basic' ? 'none' : value; + currentModule.setAlign.call(this, alignValue, null, null, null); + this.selectComponent(contextEl, pluginName); + break; + case 'caption': + const caption = !currentContext._captionChecked; + currentModule.openModify.call(this, true); + currentContext._captionChecked = currentContext.captionCheckEl.checked = caption; + + currentModule.update_image.call(this, false, false, false); + + if (caption) { + const captionText = this.util.getChildElement(currentContext._caption, function (current) { + return current.nodeType === 3; + }); + + if (!captionText) { + currentContext._caption.focus(); + } else { + this.setRange(captionText, 0, captionText, captionText.textContent.length); + } + + this.controllersOff(); + } else { + this.selectComponent(contextEl, pluginName); + currentModule.openModify.call(this, true); + } + + break; + case 'revert': + currentModule.setOriginSize.call(this); + this.selectComponent(contextEl, pluginName); + break; + case 'update': + currentModule.openModify.call(this); + this.controllersOff(); + break; + case 'delete': + currentModule.destroy.call(this); + break; + } + + // history stack + this.history.push(false); + }, + + /** + * @description Initialize the transform style (rotation) of the element. + * @param {Element} element Target element + */ + resetTransform: function (element) { + const size = (element.getAttribute('data-size') || element.getAttribute('data-origin') || '').split(','); + this.context.resizing._rotateVertical = false; + + element.style.maxWidth = ''; + element.style.transform = ''; + element.style.transformOrigin = ''; + element.setAttribute('data-rotate', ''); + element.setAttribute('data-rotateX', ''); + element.setAttribute('data-rotateY', ''); + + this.plugins[this.context.resizing._resize_plugin].setSize.call(this, size[0] ? size[0] : 'auto', size[1] ? size[1] : '', true); + }, + + /** + * @description Set the transform style (rotation) of the element. + * @param {Element} element Target element + * @param {Number|null} width Element's width size + * @param {Number|null} height Element's height size + */ + setTransformSize: function (element, width, height) { + let percentage = element.getAttribute('data-percentage'); + const isVertical = this.context.resizing._rotateVertical; + const deg = element.getAttribute('data-rotate') * 1; + let transOrigin = ''; + + if (percentage && !isVertical) { + percentage = percentage.split(','); + if (percentage[0] === 'auto' && percentage[1] === 'auto') { + this.plugins[this.context.resizing._resize_plugin].setAutoSize.call(this); + } else { + this.plugins[this.context.resizing._resize_plugin].setPercentSize.call(this, percentage[0], percentage[1]); + } + } else { + const cover = this.util.getParentElement(element, 'FIGURE'); + + const offsetW = width || element.offsetWidth; + const offsetH = height || element.offsetHeight; + const w = (isVertical ? offsetH : offsetW) + 'px'; + const h = (isVertical ? offsetW : offsetH) + 'px'; + + this.plugins[this.context.resizing._resize_plugin].cancelPercentAttr.call(this); + this.plugins[this.context.resizing._resize_plugin].setSize.call(this, offsetW + 'px', offsetH + 'px', true); + + cover.style.width = w; + cover.style.height = (!!this.context[this.context.resizing._resize_plugin]._caption ? '' : h); + + if (isVertical) { + let transW = (offsetW/2) + 'px ' + (offsetW/2) + 'px 0'; + let transH = (offsetH/2) + 'px ' + (offsetH/2) + 'px 0'; + transOrigin = deg === 90 || deg === -270 ? transH : transW; + } + } + + element.style.transformOrigin = transOrigin; + this.plugins.resizing._setTransForm(element, deg.toString(), element.getAttribute('data-rotateX') || '', element.getAttribute('data-rotateY') || ''); + + if (isVertical) element.style.maxWidth = 'none'; + else element.style.maxWidth = ''; + + this.plugins.resizing.setCaptionPosition.call(this, element); + }, + + _setTransForm: function (element, r, x, y) { + let width = (element.offsetWidth - element.offsetHeight) * (/-/.test(r) ? 1 : -1); + let translate = ''; + + if (/[1-9]/.test(r) && (x || y)) { + translate = x ? 'Y' : 'X'; + + switch (r) { + case '90': + translate = x && y ? 'X' : y ? translate : ''; + break; + case '270': + width *= -1; + translate = x && y ? 'Y' : x ? translate : ''; + break; + case '-90': + translate = x && y ? 'Y' : x ? translate : ''; + break; + case '-270': + width *= -1; + translate = x && y ? 'X' : y ? translate : ''; + break; + default: + translate = ''; + } + } + + if (r % 180 === 0) { + element.style.maxWidth = ''; + } + + element.style.transform = 'rotate(' + r + 'deg)' + (x ? ' rotateX(' + x + 'deg)' : '') + (y ? ' rotateY(' + y + 'deg)' : '') + (translate ? ' translate' + translate + '(' + width + 'px)' : ''); + }, + + /** + * @description The position of the caption is set automatically. + * @param {Element} element Target element (not caption element) + */ + setCaptionPosition: function (element) { + const figcaption = this.util.getChildElement(this.util.getParentElement(element, 'FIGURE'), 'FIGCAPTION'); + if (figcaption) { + figcaption.style.marginTop = (this.context.resizing._rotateVertical ? element.offsetWidth - element.offsetHeight : 0) + 'px'; + } + }, + + /** + * @description Mouse down event of resize handles + * @param {MouseEvent} e Event object + */ + onMouseDown_resize_handle: function (e) { + e.stopPropagation(); + e.preventDefault(); + + const contextResizing = this.context.resizing; + const direction = contextResizing._resize_direction = e.target.classList[0]; + + contextResizing._resizeClientX = e.clientX; + contextResizing._resizeClientY = e.clientY; + this.context.element.resizeBackground.style.display = 'block'; + contextResizing.resizeButton.style.display = 'none'; + contextResizing.resizeDiv.style.float = /l/.test(direction) ? 'right' : /r/.test(direction) ? 'left' : 'none'; + + const closureFunc_bind = function closureFunc(e) { + if (e.type === 'keydown' && e.keyCode !== 27) return; + + const change = contextResizing._isChange; + contextResizing._isChange = false; + + this.removeDocEvent('mousemove', resizing_element_bind); + this.removeDocEvent('mouseup', closureFunc_bind); + this.removeDocEvent('keydown', closureFunc_bind); + + if (e.type === 'keydown') { + this.controllersOff(); + this.context.element.resizeBackground.style.display = 'none'; + this.plugins[this.context.resizing._resize_plugin].init.call(this); + } else { + // element resize + this.plugins.resizing.cancel_controller_resize.call(this, direction); + // history stack + if (change) this.history.push(false); + } + }.bind(this); + + const resizing_element_bind = this.plugins.resizing.resizing_element.bind(this, contextResizing, direction, this.context[contextResizing._resize_plugin]); + this.addDocEvent('mousemove', resizing_element_bind); + this.addDocEvent('mouseup', closureFunc_bind); + this.addDocEvent('keydown', closureFunc_bind); + }, + + /** + * @description Mouse move event after call "onMouseDown_resize_handle" of resize handles + * The size of the module's "div" is adjusted according to the mouse move event. + * @param {Object} contextResizing "core.context.resizing" object (binding argument) + * @param {String} direction Direction ("tl", "tr", "bl", "br", "lw", "th", "rw", "bh") (binding argument) + * @param {Object} plugin "core.context[currentPlugin]" object (binding argument) + * @param {MouseEvent} e Event object + */ + resizing_element: function (contextResizing, direction, plugin, e) { + const clientX = e.clientX; + const clientY = e.clientY; + + let resultW = plugin._element_w; + let resultH = plugin._element_h; + + const w = plugin._element_w + (/r/.test(direction) ? clientX - contextResizing._resizeClientX : contextResizing._resizeClientX - clientX); + const h = plugin._element_h + (/b/.test(direction) ? clientY - contextResizing._resizeClientY : contextResizing._resizeClientY - clientY); + const wh = ((plugin._element_h / plugin._element_w) * w); + + if (/t/.test(direction)) contextResizing.resizeDiv.style.top = (plugin._element_h - (/h/.test(direction) ? h : wh)) + 'px'; + if (/l/.test(direction)) contextResizing.resizeDiv.style.left = (plugin._element_w - w) + 'px'; + + if (/r|l/.test(direction)) { + contextResizing.resizeDiv.style.width = w + 'px'; + resultW = w; + } + + if (/^(t|b)[^h]$/.test(direction)) { + contextResizing.resizeDiv.style.height = wh + 'px'; + resultH = wh; + } + else if (/^(t|b)h$/.test(direction)) { + contextResizing.resizeDiv.style.height = h + 'px'; + resultH = h; + } + + contextResizing._resize_w = resultW; + contextResizing._resize_h = resultH; + this.util.changeTxt(contextResizing.resizeDisplay, this._w.Math.round(resultW) + ' x ' + this._w.Math.round(resultH)); + contextResizing._isChange = true; + }, + + /** + * @description Resize the element to the size of the "div" adjusted in the "resizing_element" method. + * Called at the mouse-up event registered in "onMouseDown_resize_handle". + * @param {String} direction Direction ("tl", "tr", "bl", "br", "lw", "th", "rw", "bh") + */ + cancel_controller_resize: function (direction) { + const isVertical = this.context.resizing._rotateVertical; + this.controllersOff(); + this.context.element.resizeBackground.style.display = 'none'; + + let w = this._w.Math.round(isVertical ? this.context.resizing._resize_h : this.context.resizing._resize_w); + let h = this._w.Math.round(isVertical ? this.context.resizing._resize_w : this.context.resizing._resize_h); + + if (!isVertical && !/%$/.test(w)) { + const padding = 16; + const limit = this.context.element.wysiwygFrame.clientWidth - (padding * 2) - 2; + + if (this.util.getNumber(w, 0) > limit) { + h = this._w.Math.round((h / w) * limit); + w = limit; + } + } + + const pluginName = this.context.resizing._resize_plugin; + this.plugins[pluginName].setSize.call(this, w, h, false, direction); + if (isVertical) this.plugins.resizing.setTransformSize.call(this, this.context[this.context.resizing._resize_plugin]._element, w, h); + + this.selectComponent(this.context[pluginName]._element, pluginName); + } + }; + + if (typeof noGlobal === typeof undefined) { + if (!window.SUNEDITOR_MODULES) { + Object.defineProperty(window, 'SUNEDITOR_MODULES', { + enumerable: true, + writable: false, + configurable: false, + value: {} + }); + } + + Object.defineProperty(window.SUNEDITOR_MODULES, 'resizing', { + enumerable: true, + writable: false, + configurable: false, + value: resizing + }); + } + + return resizing; +})); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/align.js": +/*!*************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/align.js ***! + \*************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'align', + display: 'submenu', + add: function (core, targetElement) { + const icons = core.icons; + const context = core.context; + context.align = { + targetButton: targetElement, + _alignList: null, + currentAlign: '', + defaultDir: core.options.rtl ? 'right' : 'left', + icons: { + justify: icons.align_justify, + left: icons.align_left, + right: icons.align_right, + center: icons.align_center + } + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let listUl = listDiv.querySelector('ul'); + + /** add event listeners */ + listUl.addEventListener('click', this.pickup.bind(core)); + context.align._alignList = listUl.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null, listUl = null; + }, + + setSubmenu: function (core) { + const lang = core.lang; + const icons = core.icons; + const listDiv = core.util.createElement('DIV'); + const leftDir = core.context.align.defaultDir === 'left'; + + const leftMenu = '
  • ' + + '' + + '
  • '; + + const rightMenu = '
  • ' + + '' + + '
  • '; + + listDiv.className = 'se-submenu se-list-layer se-list-align'; + listDiv.innerHTML = '' + + '
    ' + + '
      ' + + (leftDir ? leftMenu : rightMenu) + + '
    • ' + + '' + + '
    • ' + + (leftDir? rightMenu : leftMenu) + + '
    • ' + + '' + + '
    • ' + + '
    ' + + '
    '; + + return listDiv; + }, + + /** + * @Override core + */ + active: function (element) { + const alignContext = this.context.align; + const targetButton = alignContext.targetButton; + const target = targetButton.firstElementChild; + + if (!element) { + this.util.changeElement(target, alignContext.icons[alignContext.defaultDir]); + targetButton.removeAttribute('data-focus'); + } else if (this.util.isFormatElement(element)) { + const textAlign = element.style.textAlign; + if (textAlign) { + this.util.changeElement(target, alignContext.icons[textAlign] || alignContext.icons[alignContext.defaultDir]); + targetButton.setAttribute('data-focus', textAlign); + return true; + } + } + + return false; + }, + + /** + * @Override submenu + */ + on: function () { + const alignContext = this.context.align; + const alignList = alignContext._alignList; + const currentAlign = alignContext.targetButton.getAttribute('data-focus') || alignContext.defaultDir; + + if (currentAlign !== alignContext.currentAlign) { + for (let i = 0, len = alignList.length; i < len; i++) { + if (currentAlign === alignList[i].getAttribute('data-value')) { + this.util.addClass(alignList[i], 'active'); + } else { + this.util.removeClass(alignList[i], 'active'); + } + } + + alignContext.currentAlign = currentAlign; + } + }, + + pickup: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let value = null; + + while (!value && !/UL/i.test(target.tagName)) { + value = target.getAttribute('data-value'); + target = target.parentNode; + } + + if (!value) return; + + const defaultDir = this.context.align.defaultDir; + const selectedFormsts = this.getSelectedElements(); + for (let i = 0, len = selectedFormsts.length; i < len; i++) { + this.util.setStyle(selectedFormsts[i], 'textAlign', (value === defaultDir ? '' : value)); + } + + this.effectNode = null; + this.submenuOff(); + this.focus(); + + // history stack + this.history.push(false); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/font.js": +/*!************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/font.js ***! + \************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'font', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.font = { + targetText: targetElement.querySelector('.txt'), + targetTooltip: targetElement.parentNode.querySelector('.se-tooltip-text'), + _fontList: null, + currentFont: '' + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + + /** add event listeners */ + listDiv.querySelector('.se-list-inner').addEventListener('click', this.pickup.bind(core)); + + context.font._fontList = listDiv.querySelectorAll('ul li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const lang = core.lang; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer se-list-font-family'; + + let font, text, i, len; + let fontList = !option.font ? + [ + 'Arial', + 'Comic Sans MS', + 'Courier New', + 'Impact', + 'Georgia', + 'tahoma', + 'Trebuchet MS', + 'Verdana' + ] : option.font; + + let list = '
    ' + + '
      ' + + '
    • '; + for (i = 0, len = fontList.length; i < len; i++) { + font = fontList[i]; + text = font.split(',')[0]; + list += '
    • '; + } + list += '
    '; + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override core + */ + active: function (element) { + const target = this.context.font.targetText; + const tooltip = this.context.font.targetTooltip; + + if (!element) { + const font = this.lang.toolbar.font; + this.util.changeTxt(target, font); + this.util.changeTxt(tooltip, font); + } else if (element.style && element.style.fontFamily.length > 0) { + const selectFont = element.style.fontFamily.replace(/["']/g,''); + this.util.changeTxt(target, selectFont); + this.util.changeTxt(tooltip, selectFont); + return true; + } + + return false; + }, + + /** + * @Override submenu + */ + on: function () { + const fontContext = this.context.font; + const fontList = fontContext._fontList; + const currentFont = fontContext.targetText.textContent; + + if (currentFont !== fontContext.currentFont) { + for (let i = 0, len = fontList.length; i < len; i++) { + if (currentFont === fontList[i].getAttribute('data-value')) { + this.util.addClass(fontList[i], 'active'); + } else { + this.util.removeClass(fontList[i], 'active'); + } + } + + fontContext.currentFont = currentFont; + } + }, + + pickup: function (e) { + if (!/^BUTTON$/i.test(e.target.tagName)) return false; + + e.preventDefault(); + e.stopPropagation(); + + const value = e.target.getAttribute('data-value'); + + if (value) { + const newNode = this.util.createElement('SPAN'); + newNode.style.fontFamily = value; + this.nodeChange(newNode, ['font-family'], null, null); + } else { + this.nodeChange(null, ['font-family'], ['span'], true); + } + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/fontColor.js": +/*!*****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/fontColor.js ***! + \*****************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_colorPicker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/_colorPicker */ "./node_modules/suneditor/src/plugins/modules/_colorPicker.js"); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'fontColor', + display: 'submenu', + add: function (core, targetElement) { + core.addModule([_modules_colorPicker__WEBPACK_IMPORTED_MODULE_0__["default"]]); + + const context = core.context; + context.fontColor = { + previewEl: null, + colorInput: null, + colorList: null + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + context.fontColor.colorInput = listDiv.querySelector('._se_color_picker_input'); + + /** add event listeners */ + context.fontColor.colorInput.addEventListener('keyup', this.onChangeInput.bind(core)); + listDiv.querySelector('._se_color_picker_submit').addEventListener('click', this.submit.bind(core)); + listDiv.querySelector('._se_color_picker_remove').addEventListener('click', this.remove.bind(core)); + listDiv.addEventListener('click', this.pickup.bind(core)); + context.fontColor.colorList = listDiv.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const colorArea = core.context.colorPicker.colorListHTML; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer'; + listDiv.innerHTML = colorArea; + + return listDiv; + }, + + /** + * @Override submenu + */ + on: function () { + const contextPicker = this.context.colorPicker; + const contextFontColor = this.context.fontColor; + + contextPicker._colorInput = contextFontColor.colorInput; + contextPicker._defaultColor = '#333333'; + contextPicker._styleProperty = 'color'; + contextPicker._colorList = contextFontColor.colorList; + + this.plugins.colorPicker.init.call(this, this.getSelectionNode(), null); + }, + + /** + * @Override _colorPicker + */ + onChangeInput: function (e) { + this.plugins.colorPicker.setCurrentColor.call(this, e.target.value); + }, + + submit: function () { + this.plugins.fontColor.applyColor.call(this, this.context.colorPicker._currentColor); + }, + + pickup: function (e) { + e.preventDefault(); + e.stopPropagation(); + + this.plugins.fontColor.applyColor.call(this, e.target.getAttribute('data-value')); + }, + + remove: function () { + this.nodeChange(null, ['color'], ['span'], true); + this.submenuOff(); + }, + + applyColor: function (color) { + if (!color) return; + + const newNode = this.util.createElement('SPAN'); + newNode.style.color = color; + this.nodeChange(newNode, ['color'], null, null); + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/fontSize.js": +/*!****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/fontSize.js ***! + \****************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'fontSize', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.fontSize = { + targetText: targetElement.querySelector('.txt'), + _sizeList: null, + currentSize: '' + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let listUl = listDiv.querySelector('ul'); + + /** add event listeners */ + listUl.addEventListener('click', this.pickup.bind(core)); + context.fontSize._sizeList = listUl.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null, listUl = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const lang = core.lang; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer se-list-font-size'; + + const sizeList = !option.fontSize ? [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72] : option.fontSize; + + let list = '
    ' + + '
      ' + + '
    • '; + for (let i = 0, unit = option.fontSizeUnit, len = sizeList.length, size; i < len; i++) { + size = sizeList[i]; + list += '
    • '; + } + list += '
    '; + + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override core + */ + active: function (element) { + if (!element) { + this.util.changeTxt(this.context.fontSize.targetText, this.lang.toolbar.fontSize); + } else if (element.style && element.style.fontSize.length > 0) { + this.util.changeTxt(this.context.fontSize.targetText, element.style.fontSize); + return true; + } + + return false; + }, + + /** + * @Override submenu + */ + on: function () { + const fontSizeContext = this.context.fontSize; + const sizeList = fontSizeContext._sizeList; + const currentSize = fontSizeContext.targetText.textContent; + + if (currentSize !== fontSizeContext.currentSize) { + for (let i = 0, len = sizeList.length; i < len; i++) { + if (currentSize === sizeList[i].getAttribute('data-value')) { + this.util.addClass(sizeList[i], 'active'); + } else { + this.util.removeClass(sizeList[i], 'active'); + } + } + + fontSizeContext.currentSize = currentSize; + } + }, + + pickup: function (e) { + if (!/^BUTTON$/i.test(e.target.tagName)) return false; + + e.preventDefault(); + e.stopPropagation(); + + const value = e.target.getAttribute('data-value'); + + if (value) { + const newNode = this.util.createElement('SPAN'); + newNode.style.fontSize = value; + this.nodeChange(newNode, ['font-size'], null, null); + } else { + this.nodeChange(null, ['font-size'], ['span'], true); + } + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/formatBlock.js": +/*!*******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/formatBlock.js ***! + \*******************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'formatBlock', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.formatBlock = { + targetText: targetElement.querySelector('.txt'), + targetTooltip: targetElement.parentNode.querySelector('.se-tooltip-text'), + _formatList: null, + currentFormat: '' + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + + /** add event listeners */ + listDiv.querySelector('ul').addEventListener('click', this.pickUp.bind(core)); + context.formatBlock._formatList = listDiv.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const lang_toolbar = core.lang.toolbar; + const listDiv = core.util.createElement('DIV'); + listDiv.className = 'se-submenu se-list-layer se-list-format'; + + const defaultFormats = ['p', 'div', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']; + const formatList = !option.formats || option.formats.length === 0 ? defaultFormats : option.formats; + + let list = '
      '; + for (let i = 0, len = formatList.length, format, tagName, command, name, h, attrs, className; i < len; i++) { + format = formatList[i]; + + if (typeof format === 'string' && defaultFormats.indexOf(format) > -1) { + tagName = format.toLowerCase(); + command = tagName === 'blockquote' ? 'range' : tagName === 'pre' ? 'free' : 'replace'; + h = /^h/.test(tagName) ? tagName.match(/\d+/)[0] : ''; + name = lang_toolbar['tag_' + (h ? 'h' : tagName)] + h; + className = ''; + attrs = ''; + } else { + tagName = format.tag.toLowerCase(); + command = format.command; + name = format.name || tagName; + className = format.class; + attrs = className ? ' class="' + className + '"' : ''; + } + + list += '
    • ' + + '
    • '; + } + list += '
    '; + + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override core + */ + active: function (element) { + let formatTitle = this.lang.toolbar.formats; + const target = this.context.formatBlock.targetText; + const tooltip = this.context.formatBlock.targetTooltip; + + if (!element) { + this.util.changeTxt(target, formatTitle); + this.util.changeTxt(tooltip, formatTitle); + } else if (this.util.isFormatElement(element)) { + const formatContext = this.context.formatBlock; + const formatList = formatContext._formatList; + const nodeName = element.nodeName.toLowerCase(); + const className = (element.className.match(/(\s|^)__se__format__[^\s]+/) || [''])[0].trim(); + + for (let i = 0, len = formatList.length, f; i < len; i++) { + f = formatList[i]; + if (nodeName === f.getAttribute('data-value') && className === f.getAttribute('data-class')) { + formatTitle = f.title; + break; + } + } + + this.util.changeTxt(target, formatTitle); + this.util.changeTxt(tooltip, formatTitle); + target.setAttribute('data-value', nodeName); + target.setAttribute('data-class', className); + + return true; + } + + return false; + }, + + /** + * @Override submenu + */ + on: function () { + const formatContext = this.context.formatBlock; + const formatList = formatContext._formatList; + const target = formatContext.targetText; + const currentFormat = (target.getAttribute('data-value') || '') + (target.getAttribute('data-class') || ''); + + if (currentFormat !== formatContext.currentFormat) { + for (let i = 0, len = formatList.length, f; i < len; i++) { + f = formatList[i]; + if (currentFormat === f.getAttribute('data-value') + f.getAttribute('data-class')) { + this.util.addClass(f, 'active'); + } else { + this.util.removeClass(f, 'active'); + } + } + + formatContext.currentFormat = currentFormat; + } + }, + + pickUp: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let command = null, value = null, tag = null, className = ''; + + while (!command && !/UL/i.test(target.tagName)) { + command = target.getAttribute('data-command'); + value = target.getAttribute('data-value'); + className = target.getAttribute('data-class'); + if (command) { + tag = target.firstChild; + break; + } + target = target.parentNode; + } + + if (!command) return; + + // blockquote + if (command === 'range') { + const rangeElement = tag.cloneNode(false); + this.applyRangeFormatElement(rangeElement); + } + // free, replace + else { + let range = this.getRange(); + let selectedFormsts = this.getSelectedElementsAndComponents(false); + + if (selectedFormsts.length === 0) { + range = this.getRange_addLine(range, null); + selectedFormsts = this.getSelectedElementsAndComponents(false); + if (selectedFormsts.length === 0) return; + } + + const startOffset = range.startOffset; + const endOffset = range.endOffset; + + const util = this.util; + let first = selectedFormsts[0]; + let last = selectedFormsts[selectedFormsts.length - 1]; + const firstPath = util.getNodePath(range.startContainer, first, null, null); + const lastPath = util.getNodePath(range.endContainer, last, null, null); + + // remove selected list + const rlist = this.detachList(selectedFormsts, false); + if (rlist.sc) first = rlist.sc; + if (rlist.ec) last = rlist.ec; + + // change format tag + this.setRange(util.getNodeFromPath(firstPath, first), startOffset, util.getNodeFromPath(lastPath, last), endOffset); + const modifiedFormsts = this.getSelectedElementsAndComponents(false); + + // free format + if (command === 'free') { + const len = modifiedFormsts.length - 1; + let parentNode = modifiedFormsts[len].parentNode; + let freeElement = tag.cloneNode(false); + const focusElement = freeElement; + + for (let i = len, f, html, before, next, inner, isComp, first = true; i >= 0; i--) { + f = modifiedFormsts[i]; + if (f === (!modifiedFormsts[i + 1] ? null : modifiedFormsts[i + 1].parentNode)) continue; + + isComp = util.isComponent(f); + html = isComp ? '' : f.innerHTML.replace(/(?!>)\s+(?=<)|\n/g, ' '); + before = util.getParentElement(f, function (current) { + return current.parentNode === parentNode; + }); + + if (parentNode !== f.parentNode || isComp) { + if (util.isFormatElement(parentNode)) { + parentNode.parentNode.insertBefore(freeElement, parentNode.nextSibling); + parentNode = parentNode.parentNode; + } else { + parentNode.insertBefore(freeElement, before ? before.nextSibling : null); + parentNode = f.parentNode; + } + + next = freeElement.nextSibling; + if (next && freeElement.nodeName === next.nodeName && util.isSameAttributes(freeElement, next)) { + freeElement.innerHTML += '
    ' + next.innerHTML; + util.removeItem(next); + } + + freeElement = tag.cloneNode(false); + first = true; + } + + inner = freeElement.innerHTML; + freeElement.innerHTML = ((first || !html || !inner || /
    $/i.test(html)) ? html : html + '
    ') + inner; + + if (i === 0) { + parentNode.insertBefore(freeElement, f); + next = f.nextSibling; + if (next && freeElement.nodeName === next.nodeName && util.isSameAttributes(freeElement, next)) { + freeElement.innerHTML += '
    ' + next.innerHTML; + util.removeItem(next); + } + + const prev = freeElement.previousSibling; + if (prev && freeElement.nodeName === prev.nodeName && util.isSameAttributes(freeElement, prev)) { + prev.innerHTML += '
    ' + freeElement.innerHTML; + util.removeItem(freeElement); + } + } + + if (!isComp) util.removeItem(f); + if (!!html) first = false; + } + + this.setRange(focusElement, 0, focusElement, 0); + } + // replace format + else { + for (let i = 0, len = modifiedFormsts.length, node, newFormat; i < len; i++) { + node = modifiedFormsts[i]; + + if ((node.nodeName.toLowerCase() !== value.toLowerCase() || (node.className.match(/(\s|^)__se__format__[^\s]+/) || [''])[0].trim() !== className) && !util.isComponent(node)) { + newFormat = tag.cloneNode(false); + util.copyFormatAttributes(newFormat, node); + newFormat.innerHTML = node.innerHTML; + + node.parentNode.replaceChild(newFormat, node); + } + + if (i === 0) first = newFormat || node; + if (i === len - 1) last = newFormat || node; + newFormat = null; + } + + this.setRange(util.getNodeFromPath(firstPath, first), startOffset, util.getNodeFromPath(lastPath, last), endOffset); + } + + // history stack + this.history.push(false); + } + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/hiliteColor.js": +/*!*******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/hiliteColor.js ***! + \*******************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _modules_colorPicker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/_colorPicker */ "./node_modules/suneditor/src/plugins/modules/_colorPicker.js"); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'hiliteColor', + display: 'submenu', + add: function (core, targetElement) { + core.addModule([_modules_colorPicker__WEBPACK_IMPORTED_MODULE_0__["default"]]); + + const context = core.context; + context.hiliteColor = { + previewEl: null, + colorInput: null, + colorList: null + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + context.hiliteColor.colorInput = listDiv.querySelector('._se_color_picker_input'); + + /** add event listeners */ + context.hiliteColor.colorInput.addEventListener('keyup', this.onChangeInput.bind(core)); + listDiv.querySelector('._se_color_picker_submit').addEventListener('click', this.submit.bind(core)); + listDiv.querySelector('._se_color_picker_remove').addEventListener('click', this.remove.bind(core)); + listDiv.addEventListener('click', this.pickup.bind(core)); + + context.hiliteColor.colorList = listDiv.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const colorArea = core.context.colorPicker.colorListHTML; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer'; + listDiv.innerHTML = colorArea; + + return listDiv; + }, + + /** + * @Override submenu + */ + on: function () { + const contextPicker = this.context.colorPicker; + const contextHiliteColor = this.context.hiliteColor; + + contextPicker._colorInput = contextHiliteColor.colorInput; + contextPicker._defaultColor = '#FFFFFF'; + contextPicker._styleProperty = 'backgroundColor'; + contextPicker._colorList = contextHiliteColor.colorList; + + this.plugins.colorPicker.init.call(this, this.getSelectionNode(), null); + }, + + /** + * @Override _colorPicker + */ + onChangeInput: function (e) { + this.plugins.colorPicker.setCurrentColor.call(this, e.target.value); + }, + + submit: function () { + this.plugins.hiliteColor.applyColor.call(this, this.context.colorPicker._currentColor); + }, + + pickup: function (e) { + e.preventDefault(); + e.stopPropagation(); + + this.plugins.hiliteColor.applyColor.call(this, e.target.getAttribute('data-value')); + }, + + remove: function () { + this.nodeChange(null, ['background-color'], ['span'], true); + this.submenuOff(); + }, + + applyColor: function (color) { + if (!color) return; + + const newNode = this.util.createElement('SPAN'); + newNode.style.backgroundColor = color; + this.nodeChange(newNode, ['background-color'], null, null); + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/horizontalRule.js": +/*!**********************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/horizontalRule.js ***! + \**********************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'horizontalRule', + display: 'submenu', + add: function (core, targetElement) { + /** set submenu */ + let listDiv = this.setSubmenu(core); + + /** add event listeners */ + listDiv.querySelector('ul').addEventListener('click', this.horizontalRulePick.bind(core)); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const lang = core.lang; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer se-list-line'; + listDiv.innerHTML = '' + + '
    ' + + '
      ' + + '
    • ' + + '' + + '
    • ' + + '
    • ' + + '' + + '
    • ' + + '
    • ' + + '' + + '
    • ' + + '
    ' + + '
    '; + + return listDiv; + }, + + appendHr: function (className) { + const oHr = this.util.createElement('HR'); + oHr.className = className; + this.focus(); + return this.insertComponent(oHr, false, true, false); + }, + + horizontalRulePick: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let value = null; + + while (!value && !/UL/i.test(target.tagName)) { + value = target.getAttribute('data-value'); + target = target.parentNode; + } + + if (!value) return; + + const oNode = this.plugins.horizontalRule.appendHr.call(this, '__se__' + value); + if (oNode) { + this.setRange(oNode, 0, oNode, 0); + this.submenuOff(); + } + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/lineHeight.js": +/*!******************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/lineHeight.js ***! + \******************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 20197 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'lineHeight', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.lineHeight = { + _sizeList: null, + currentSize: -1 + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let listUl = listDiv.querySelector('ul'); + + /** add event listeners */ + listUl.addEventListener('click', this.pickup.bind(core)); + + context.lineHeight._sizeList = listUl.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null, listUl = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const lang = core.lang; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer'; + + const sizeList = !option.lineHeights ? [ + {text: '1', value: 1}, + {text: '1.15', value: 1.15}, + {text: '1.5', value: 1.5}, + {text: '2', value: 2} + ] : option.lineHeights; + + let list = '
    ' + + '
      ' + + '
    • '; + for (let i = 0, len = sizeList.length, text, size; i < len; i++) { + size = sizeList[i]; + list += '
    • '; + } + list += '
    '; + + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override submenu + */ + on: function () { + const lineHeightContext = this.context.lineHeight; + const sizeList = lineHeightContext._sizeList; + const format = this.util.getFormatElement(this.getSelectionNode()); + const currentSize = !format ? '' : format.style.lineHeight + ''; + + if (currentSize !== lineHeightContext.currentSize) { + for (let i = 0, len = sizeList.length; i < len; i++) { + if (currentSize === sizeList[i].getAttribute('data-value')) { + this.util.addClass(sizeList[i], 'active'); + } else { + this.util.removeClass(sizeList[i], 'active'); + } + } + + lineHeightContext.currentSize = currentSize; + } + }, + + pickup: function (e) { + if (!/^BUTTON$/i.test(e.target.tagName)) return false; + + e.preventDefault(); + e.stopPropagation(); + + const value = e.target.getAttribute('data-value') || ''; + const formats = this.getSelectedElements(); + + for (let i = 0, len = formats.length; i < len; i++) { + formats[i].style.lineHeight = value; + } + + this.submenuOff(); + + // history stack + this.history.push(false); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/list.js": +/*!************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/list.js ***! + \************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'list', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.list = { + targetButton: targetElement, + _list: null, + currentList: '', + icons: { + bullets: core.icons.list_bullets, + number: core.icons.list_number + } + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let listUl = listDiv.querySelector('ul'); + + /** add event listeners */ + listUl.addEventListener('click', this.pickup.bind(core)); + context.list._list = listUl.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null, listUl = null; + }, + + setSubmenu: function (core) { + const lang = core.lang; + const listDiv = core.util.createElement('DIV'); + + listDiv.className = 'se-submenu se-list-layer'; + listDiv.innerHTML = '' + + '
    ' + + '
      ' + + '
    • ' + + '
    • ' + + '
    ' + + '
    '; + + return listDiv; + }, + + /** + * @Override core + */ + active: function (element) { + const button = this.context.list.targetButton; + const icon = button.firstElementChild; + const util = this.util; + + if (!element) { + button.removeAttribute('data-focus'); + util.changeElement(icon, this.context.list.icons.number); + util.removeClass(button, 'active'); + } else if (util.isList(element)) { + const nodeName = element.nodeName; + button.setAttribute('data-focus', nodeName); + util.addClass(button, 'active'); + if (/UL/i.test(nodeName)) { + util.changeElement(icon, this.context.list.icons.bullets); + } else { + util.changeElement(icon, this.context.list.icons.number); + } + + return true; + } + + return false; + }, + + /** + * @Override submenu + */ + on: function () { + const listContext = this.context.list; + const list = listContext._list; + const currentList = listContext.targetButton.getAttribute('data-focus') || ''; + + if (currentList !== listContext.currentList) { + for (let i = 0, len = list.length; i < len; i++) { + if (currentList === list[i].getAttribute('data-command')) { + this.util.addClass(list[i], 'active'); + } else { + this.util.removeClass(list[i], 'active'); + } + } + + listContext.currentList = currentList; + } + }, + + editList: function (command, selectedCells, detach) { + let range = this.getRange(); + let selectedFormats = !selectedCells ? this.getSelectedElementsAndComponents(false) : selectedCells; + + if (selectedFormats.length === 0) { + if (selectedCells) return; + range = this.getRange_addLine(range, null); + selectedFormats = this.getSelectedElementsAndComponents(false); + if (selectedFormats.length === 0) return; + } + + const util = this.util; + util.sortByDepth(selectedFormats, true); + + // merge + let firstSel = selectedFormats[0]; + let lastSel = selectedFormats[selectedFormats.length - 1]; + let topEl = (util.isListCell(firstSel) || util.isComponent(firstSel)) && !firstSel.previousElementSibling ? firstSel.parentNode.previousElementSibling : firstSel.previousElementSibling; + let bottomEl = (util.isListCell(lastSel) || util.isComponent(lastSel)) && !lastSel.nextElementSibling ? lastSel.parentNode.nextElementSibling : lastSel.nextElementSibling; + + const originRange = { + sc: range.startContainer, + so: range.startOffset, + ec: range.endContainer, + eo: range.endOffset + }; + + let isRemove = true; + + for (let i = 0, len = selectedFormats.length; i < len; i++) { + if (!util.isList(util.getRangeFormatElement(selectedFormats[i], function (current) { + return this.getRangeFormatElement(current) && current !== selectedFormats[i]; + }.bind(util)))) { + isRemove = false; + break; + } + } + + if (isRemove && (!topEl || (firstSel.tagName !== topEl.tagName || command !== topEl.tagName.toUpperCase())) && (!bottomEl || (lastSel.tagName !== bottomEl.tagName || command !== bottomEl.tagName.toUpperCase()))) { + if (detach) { + for (let i = 0, len = selectedFormats.length; i < len; i++) { + for (let j = i - 1; j >= 0; j--) { + if (selectedFormats[j].contains(selectedFormats[i])) { + selectedFormats.splice(i, 1); + i--; len--; + break; + } + } + } + } + + const currentFormat = util.getRangeFormatElement(firstSel); + const cancel = currentFormat && currentFormat.tagName === command; + let rangeArr, tempList; + const passComponent = function (current) { + return !this.isComponent(current); + }.bind(util); + + if (!cancel) tempList = util.createElement(command); + + for (let i = 0, len = selectedFormats.length, r, o; i < len; i++) { + o = util.getRangeFormatElement(selectedFormats[i], passComponent); + if (!o || !util.isList(o)) continue; + + if (!r) { + r = o; + rangeArr = {r: r, f: [util.getParentElement(selectedFormats[i], 'LI')]}; + } else { + if (r !== o) { + if (detach && util.isListCell(o.parentNode)) { + this.plugins.list._detachNested.call(this, rangeArr.f); + } else { + this.detachRangeFormatElement(rangeArr.f[0].parentNode, rangeArr.f, tempList, false, true); + } + + o = selectedFormats[i].parentNode; + if (!cancel) tempList = util.createElement(command); + + r = o; + rangeArr = {r: r, f: [util.getParentElement(selectedFormats[i], 'LI')]}; + } else { + rangeArr.f.push(util.getParentElement(selectedFormats[i], 'LI')); + } + } + + if (i === len - 1) { + if (detach && util.isListCell(o.parentNode)) { + this.plugins.list._detachNested.call(this, rangeArr.f); + } else { + this.detachRangeFormatElement(rangeArr.f[0].parentNode, rangeArr.f, tempList, false, true); + } + } + } + } else { + const topElParent = topEl ? topEl.parentNode : topEl; + const bottomElParent = bottomEl ? bottomEl.parentNode : bottomEl; + topEl = topElParent && !util.isWysiwygDiv(topElParent) && topElParent.nodeName === command ? topElParent : topEl; + bottomEl = bottomElParent && !util.isWysiwygDiv(bottomElParent) && bottomElParent.nodeName === command ? bottomElParent : bottomEl; + + const mergeTop = topEl && topEl.tagName === command; + const mergeBottom = bottomEl && bottomEl.tagName === command; + + let list = mergeTop ? topEl : util.createElement(command); + let firstList = null; + let lastList = null; + let topNumber = null; + let bottomNumber = null; + + const passComponent = function (current) { + return !this.isComponent(current) && !this.isList(current); + }.bind(util); + + for (let i = 0, len = selectedFormats.length, newCell, fTag, isCell, next, originParent, nextParent, parentTag, siblingTag, rangeTag; i < len; i++) { + fTag = selectedFormats[i]; + if (fTag.childNodes.length === 0 && !util._isIgnoreNodeChange(fTag)) { + util.removeItem(fTag); + continue; + } + next = selectedFormats[i + 1]; + originParent = fTag.parentNode; + nextParent = next ? next.parentNode : null; + isCell = util.isListCell(fTag); + rangeTag = util.isRangeFormatElement(originParent) ? originParent : null; + parentTag = isCell && !util.isWysiwygDiv(originParent) ? originParent.parentNode : originParent; + siblingTag = isCell && !util.isWysiwygDiv(originParent) ? (!next || util.isListCell(parentTag)) ? originParent : originParent.nextSibling : fTag.nextSibling; + + newCell = util.createElement('LI'); + util.copyFormatAttributes(newCell, fTag); + if (util.isComponent(fTag)) { + const isHR = /^HR$/i.test(fTag.nodeName); + if (!isHR) newCell.innerHTML = '
    '; + newCell.innerHTML += fTag.outerHTML; + if (isHR) newCell.innerHTML += '
    '; + } else { + const fChildren = fTag.childNodes; + while (fChildren[0]) { + newCell.appendChild(fChildren[0]); + } + } + list.appendChild(newCell); + + if (!next) lastList = list; + if (!next || parentTag !== nextParent || util.isRangeFormatElement(siblingTag)) { + if (!firstList) firstList = list; + if ((!mergeTop || !next || parentTag !== nextParent) && !(next && util.isList(nextParent) && nextParent === originParent)) { + if (list.parentNode !== parentTag) parentTag.insertBefore(list, siblingTag); + } + } + + util.removeItem(fTag); + if (mergeTop && topNumber === null) topNumber = list.children.length - 1; + if (next && (util.getRangeFormatElement(nextParent, passComponent) !== util.getRangeFormatElement(originParent, passComponent) || (util.isList(nextParent) && util.isList(originParent) && util.getElementDepth(nextParent) !== util.getElementDepth(originParent)))) { + list = util.createElement(command); + } + + if (rangeTag && rangeTag.children.length === 0) util.removeItem(rangeTag); + } + + if (topNumber) { + firstList = firstList.children[topNumber]; + } + + if (mergeBottom) { + bottomNumber = list.children.length - 1; + list.innerHTML += bottomEl.innerHTML; + lastList = list.children[bottomNumber]; + util.removeItem(bottomEl); + } + } + + this.effectNode = null; + return originRange; + }, + + _detachNested: function (cells) { + const first = cells[0]; + const last = cells[cells.length - 1]; + const next = last.nextElementSibling; + const originList = first.parentNode; + const sibling = originList.parentNode.nextElementSibling; + const parentNode = originList.parentNode.parentNode; + + for (let c = 0, cLen = cells.length; c < cLen; c++) { + parentNode.insertBefore(cells[c], sibling); + } + + if (next && originList.children.length > 0) { + const newList = originList.cloneNode(false); + const children = originList.childNodes; + const index = this.util.getPositionIndex(next); + while (children[index]) { + newList.appendChild(children[index]); + } + last.appendChild(newList); + } + + if (originList.children.length === 0) this.util.removeItem(originList); + this.util.mergeSameTags(parentNode); + + const edge = this.util.getEdgeChildNodes(first, last); + + return { + cc: first.parentNode, + sc: edge.sc, + ec: edge.ec + }; + }, + + editInsideList: function (remove, selectedCells) { + selectedCells = !selectedCells ? this.getSelectedElements().filter(function (el) { return this.isListCell(el); }.bind(this.util)) : selectedCells; + const cellsLen = selectedCells.length; + if (cellsLen === 0 || (!remove && (!this.util.isListCell(selectedCells[0].previousElementSibling) && !this.util.isListCell(selectedCells[cellsLen - 1].nextElementSibling)))) { + return { + sc: selectedCells[0], + so: 0, + ec: selectedCells[cellsLen - 1], + eo: 1 + }; + } + + let originList = selectedCells[0].parentNode; + let lastCell = selectedCells[cellsLen - 1]; + let range = null; + + if (remove) { + if (originList !== lastCell.parentNode && this.util.isList(lastCell.parentNode.parentNode) && lastCell.nextElementSibling) { + lastCell = lastCell.nextElementSibling; + while (lastCell) { + selectedCells.push(lastCell); + lastCell = lastCell.nextElementSibling; + } + } + range = this.plugins.list.editList.call(this, originList.nodeName.toUpperCase(), selectedCells, true); + } else { + let innerList = this.util.createElement(originList.nodeName); + let prev = selectedCells[0].previousElementSibling; + let next = lastCell.nextElementSibling; + const nodePath = { s: null, e: null, sl: originList, el: originList }; + + for (let i = 0, len = cellsLen, c; i < len; i++) { + c = selectedCells[i]; + if (c.parentNode !== originList) { + this.plugins.list._insiedList.call(this, originList, innerList, prev, next, nodePath); + originList = c.parentNode; + innerList = this.util.createElement(originList.nodeName); + } + + prev = c.previousElementSibling; + next = c.nextElementSibling; + innerList.appendChild(c); + } + + this.plugins.list._insiedList.call(this, originList, innerList, prev, next, nodePath); + + const sc = this.util.getNodeFromPath(nodePath.s, nodePath.sl); + const ec = this.util.getNodeFromPath(nodePath.e, nodePath.el); + range = { + sc: sc, + so: 0, + ec: ec, + eo: ec.textContent.length + }; + } + + return range; + }, + + _insiedList: function (originList, innerList, prev, next, nodePath) { + let insertPrev = false; + + if (prev && innerList.tagName === prev.tagName) { + const children = innerList.children; + while (children[0]) { + prev.appendChild(children[0]); + } + + innerList = prev; + insertPrev = true; + } + + if (next && innerList.tagName === next.tagName) { + const children = next.children; + while (children[0]) { + innerList.appendChild(children[0]); + } + + const temp = next.nextElementSibling; + next.parentNode.removeChild(next); + next = temp; + } + + if (!insertPrev) { + if (this.util.isListCell(prev)) { + originList = prev; + next = null; + } + + originList.insertBefore(innerList, next); + + if (!nodePath.s) { + nodePath.s = this.util.getNodePath(innerList.firstElementChild.firstChild, originList, null); + nodePath.sl = originList; + } + + const slPath = originList.contains(nodePath.sl) ? this.util.getNodePath(nodePath.sl, originList) : null; + nodePath.e = this.util.getNodePath(innerList.lastElementChild.firstChild, originList, null); + nodePath.el = originList; + + this.util.mergeSameTags(originList, [nodePath.s, nodePath.e, slPath], false); + this.util.mergeNestedTags(originList); + if (slPath) nodePath.sl = this.util.getNodeFromPath(slPath, originList); + } + + return innerList; + }, + + pickup: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let command = ''; + + while (!command && !/^UL$/i.test(target.tagName)) { + command = target.getAttribute('data-command'); + target = target.parentNode; + } + + if (!command) return; + + const range = this.plugins.list.editList.call(this, command, null, false); + if (range) this.setRange(range.sc, range.so, range.ec, range.eo); + + this.submenuOff(); + + // history stack + this.history.push(false); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/paragraphStyle.js": +/*!**********************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/paragraphStyle.js ***! + \**********************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'paragraphStyle', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.paragraphStyle = { + _classList: null + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + + /** add event listeners */ + listDiv.querySelector('ul').addEventListener('click', this.pickUp.bind(core)); + + context.paragraphStyle._classList = listDiv.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const listDiv = core.util.createElement('DIV'); + listDiv.className = 'se-submenu se-list-layer se-list-format'; + + const menuLang = core.lang.menu; + const defaultList = { + spaced: { + name: menuLang.spaced, + class: '__se__p-spaced', + _class: '' + }, + bordered: { + name: menuLang.bordered, + class: '__se__p-bordered', + _class: '' + }, + neon: { + name: menuLang.neon, + class: '__se__p-neon', + _class: '' + } + }; + const paragraphStyles = !option.paragraphStyles || option.paragraphStyles.length === 0 ? ['spaced', 'bordered', 'neon'] : option.paragraphStyles; + + let list = '
      '; + for (let i = 0, len = paragraphStyles.length, p, name, attrs, _class; i < len; i++) { + p = paragraphStyles[i]; + + if (typeof p === 'string') { + const defaultStyle = defaultList[p.toLowerCase()]; + if (!defaultStyle) continue; + p = defaultStyle; + } + + name = p.name; + attrs = p.class ? ' class="' + p.class + '"' : ''; + _class = p._class; + + list += '
    • ' + + '
    ' + + ''; + } + list += ''; + + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override submenu + */ + on: function () { + const paragraphContext = this.context.paragraphStyle; + const paragraphList = paragraphContext._classList; + const currentFormat = this.util.getFormatElement(this.getSelectionNode()); + + for (let i = 0, len = paragraphList.length; i < len; i++) { + if (this.util.hasClass(currentFormat, paragraphList[i].getAttribute('data-value'))) { + this.util.addClass(paragraphList[i], 'active'); + } else { + this.util.removeClass(paragraphList[i], 'active'); + } + } + }, + + pickUp: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let value = null; + + while (!/^UL$/i.test(target.tagName)) { + value = target.getAttribute('data-value'); + if (value) break; + target = target.parentNode; + } + + if (!value) return; + + let selectedFormsts = this.getSelectedElements(); + if (selectedFormsts.length === 0) { + this.getRange_addLine(this.getRange(), null); + selectedFormsts = this.getSelectedElements(); + if (selectedFormsts.length === 0) return; + } + + // change format class + const toggleClass = this.util.hasClass(target, 'active') ? this.util.removeClass.bind(this.util) : this.util.addClass.bind(this.util); + for (let i = 0, len = selectedFormsts.length; i < len; i++) { + toggleClass(selectedFormsts[i], value); + } + + this.submenuOff(); + + // history stack + this.history.push(false); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/table.js": +/*!*************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/table.js ***! + \*************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'table', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + let contextTable = context.table = { + _element: null, + _tdElement: null, + _trElement: null, + _trElements: null, + _tableXY: [], + _maxWidth: true, + _fixedColumn: false, + _rtl: core.options.rtl, + cellControllerTop: core.options.tableCellControllerPosition === 'top', + resizeText: null, + headerButton: null, + mergeButton: null, + splitButton: null, + splitMenu: null, + maxText: core.lang.controller.maxSize, + minText: core.lang.controller.minSize, + _physical_cellCnt: 0, + _logical_cellCnt: 0, + _rowCnt: 0, + _rowIndex: 0, + _physical_cellIndex: 0, + _logical_cellIndex: 0, + _current_colSpan: 0, + _current_rowSpan: 0, + icons: { + expansion: core.icons.expansion, + reduction: core.icons.reduction + } + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let tablePicker = listDiv.querySelector('.se-controller-table-picker'); + + contextTable.tableHighlight = listDiv.querySelector('.se-table-size-highlighted'); + contextTable.tableUnHighlight = listDiv.querySelector('.se-table-size-unhighlighted'); + contextTable.tableDisplay = listDiv.querySelector('.se-table-size-display'); + if (core.options.rtl) contextTable.tableHighlight.style.left = (10 * 18 - 13) + 'px'; + + /** set table controller */ + let tableController = this.setController_table(core); + contextTable.tableController = tableController; + contextTable.resizeButton = tableController.querySelector('._se_table_resize'); + contextTable.resizeText = tableController.querySelector('._se_table_resize > span > span'); + contextTable.columnFixedButton = tableController.querySelector('._se_table_fixed_column'); + contextTable.headerButton = tableController.querySelector('._se_table_header'); + + /** set resizing */ + let resizeDiv = this.setController_tableEditor(core, contextTable.cellControllerTop); + contextTable.resizeDiv = resizeDiv; + contextTable.splitMenu = resizeDiv.querySelector('.se-btn-group-sub'); + contextTable.mergeButton = resizeDiv.querySelector('._se_table_merge_button'); + contextTable.splitButton = resizeDiv.querySelector('._se_table_split_button'); + contextTable.insertRowAboveButton = resizeDiv.querySelector('._se_table_insert_row_a'); + contextTable.insertRowBelowButton = resizeDiv.querySelector('._se_table_insert_row_b'); + + /** add event listeners */ + tablePicker.addEventListener('mousemove', this.onMouseMove_tablePicker.bind(core, contextTable)); + tablePicker.addEventListener('click', this.appendTable.bind(core)); + resizeDiv.addEventListener('click', this.onClick_tableController.bind(core)); + tableController.addEventListener('click', this.onClick_tableController.bind(core)); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** append controller */ + context.element.relative.appendChild(resizeDiv); + context.element.relative.appendChild(tableController); + + /** empty memory */ + listDiv = null, tablePicker = null, resizeDiv = null, tableController = null, contextTable = null; + }, + + setSubmenu: function (core) { + const listDiv = core.util.createElement('DIV'); + listDiv.className = 'se-submenu se-selector-table'; + listDiv.innerHTML = '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    1 x 1
    '; + + return listDiv; + }, + + setController_table: function (core) { + const lang = core.lang; + const icons = core.icons; + const tableResize = core.util.createElement('DIV'); + + tableResize.className = 'se-controller se-controller-table'; + tableResize.innerHTML = '' + + '
    ' + + '
    ' + + '' + + '' + + '' + + '' + + '
    ' + + '
    '; + + return tableResize; + }, + + setController_tableEditor: function (core, cellControllerTop) { + const lang = core.lang; + const icons = core.icons; + const tableResize = core.util.createElement('DIV'); + + tableResize.className = 'se-controller se-controller-table-cell'; + tableResize.innerHTML = (cellControllerTop ? '' : '
    ') + + '
    ' + + '' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '
      ' + + '
    • ' + + lang.controller.VerticalSplit + '
    • ' + + '
    • ' + + lang.controller.HorizontalSplit + '
    • ' + + '
    ' + + '
    ' + + '
    ' + + '
    '; + + return tableResize; + }, + + appendTable: function () { + const oTable = this.util.createElement('TABLE'); + const createCells = this.plugins.table.createCells; + + const x = this.context.table._tableXY[0]; + let y = this.context.table._tableXY[1]; + let tableHTML = ''; + while (y > 0) { + tableHTML += '' + createCells.call(this, 'td', x) + ''; + --y; + } + tableHTML += ''; + oTable.innerHTML = tableHTML; + + const changed = this.insertComponent(oTable, false, true, false); + + if (changed) { + const firstTd = oTable.querySelector('td div'); + this.setRange(firstTd, 0, firstTd, 0); + this.plugins.table.reset_table_picker.call(this); + } + }, + + createCells: function (nodeName, cnt, returnElement) { + nodeName = nodeName.toLowerCase(); + + if (!returnElement) { + let cellsHTML = ''; + while (cnt > 0) { + cellsHTML += '<' +nodeName + '>

    '; + cnt--; + } + return cellsHTML; + } else { + const cell = this.util.createElement(nodeName); + cell.innerHTML = '

    '; + return cell; + } + }, + + onMouseMove_tablePicker: function (contextTable, e) { + e.stopPropagation(); + + let x = this._w.Math.ceil(e.offsetX / 18); + let y = this._w.Math.ceil(e.offsetY / 18); + x = x < 1 ? 1 : x; + y = y < 1 ? 1 : y; + + if (contextTable._rtl) { + contextTable.tableHighlight.style.left = (x * 18 - 13) + 'px'; + x = 11 - x; + } + + contextTable.tableHighlight.style.width = x + 'em'; + contextTable.tableHighlight.style.height = y + 'em'; + + // let x_u = x < 5 ? 5 : (x > 9 ? 10 : x + 1); + // let y_u = y < 5 ? 5 : (y > 9 ? 10 : y + 1); + // contextTable.tableUnHighlight.style.width = x_u + 'em'; + // contextTable.tableUnHighlight.style.height = y_u + 'em'; + + this.util.changeTxt(contextTable.tableDisplay, x + ' x ' + y); + contextTable._tableXY = [x, y]; + }, + + reset_table_picker: function () { + if (!this.context.table.tableHighlight) return; + + const highlight = this.context.table.tableHighlight.style; + const unHighlight = this.context.table.tableUnHighlight.style; + + highlight.width = '1em'; + highlight.height = '1em'; + unHighlight.width = '10em'; + unHighlight.height = '10em'; + + this.util.changeTxt(this.context.table.tableDisplay, '1 x 1'); + this.submenuOff(); + }, + + init: function () { + const contextTable = this.context.table; + const tablePlugin = this.plugins.table; + + tablePlugin._removeEvents.call(this); + + if (tablePlugin._selectedTable) { + const selectedCells = tablePlugin._selectedTable.querySelectorAll('.se-table-selected-cell'); + for (let i = 0, len = selectedCells.length; i < len; i++) { + this.util.removeClass(selectedCells[i], 'se-table-selected-cell'); + } + } + + tablePlugin._toggleEditor.call(this, true); + + contextTable._element = null; + contextTable._tdElement = null; + contextTable._trElement = null; + contextTable._trElements = null; + contextTable._tableXY = []; + contextTable._maxWidth = true; + contextTable._fixedColumn = false; + contextTable._physical_cellCnt = 0; + contextTable._logical_cellCnt = 0; + contextTable._rowCnt = 0; + contextTable._rowIndex = 0; + contextTable._physical_cellIndex = 0; + contextTable._logical_cellIndex = 0; + contextTable._current_colSpan = 0; + contextTable._current_rowSpan = 0; + + tablePlugin._shift = false; + tablePlugin._selectedCells = null; + tablePlugin._selectedTable = null; + tablePlugin._ref = null; + + tablePlugin._fixedCell = null; + tablePlugin._selectedCell = null; + tablePlugin._fixedCellName = null; + }, + + /** table edit controller */ + call_controller_tableEdit: function (tdElement) { + const tablePlugin = this.plugins.table; + const contextTable = this.context.table; + + if (!this.getSelection().isCollapsed && !tablePlugin._selectedCell) { + this.controllersOff(); + this.util.removeClass(tdElement, 'se-table-selected-cell'); + return; + } + + const tableElement = contextTable._element || this.plugins.table._selectedTable || this.util.getParentElement(tdElement, 'TABLE'); + contextTable._maxWidth = this.util.hasClass(tableElement, 'se-table-size-100') || tableElement.style.width === '100%' || (!tableElement.style.width && !this.util.hasClass(tableElement, 'se-table-size-auto')); + contextTable._fixedColumn = this.util.hasClass(tableElement, 'se-table-layout-fixed') || tableElement.style.tableLayout === 'fixed'; + tablePlugin.setTableStyle.call(this, contextTable._maxWidth ? 'width|column' : 'width'); + + tablePlugin.setPositionControllerTop.call(this, tableElement); + tablePlugin.setPositionControllerDiv.call(this, tdElement, tablePlugin._shift); + + if (!tablePlugin._shift) this.controllersOn(contextTable.resizeDiv, contextTable.tableController, tablePlugin.init.bind(this), tdElement, 'table'); + }, + + setPositionControllerTop: function (tableElement) { + this.setControllerPosition(this.context.table.tableController, tableElement, 'top', {left: 0, top: 0}); + }, + + setPositionControllerDiv: function (tdElement, reset) { + const contextTable = this.context.table; + const resizeDiv = contextTable.resizeDiv; + + this.plugins.table.setCellInfo.call(this, tdElement, reset); + + if (contextTable.cellControllerTop) { + this.setControllerPosition(resizeDiv, contextTable._element, 'top', {left: contextTable.tableController.offsetWidth, top: 0}); + } else { + this.setControllerPosition(resizeDiv, tdElement, 'bottom', {left: 0, top: 0}); + } + }, + + setCellInfo: function (tdElement, reset) { + const contextTable = this.context.table; + const table = contextTable._element = this.plugins.table._selectedTable || this.util.getParentElement(tdElement, 'TABLE'); + + if (/THEAD/i.test(table.firstElementChild.nodeName)) { + this.util.addClass(contextTable.headerButton, 'active'); + } else { + this.util.removeClass(contextTable.headerButton, 'active'); + } + + if (reset || contextTable._physical_cellCnt === 0) { + if (contextTable._tdElement !== tdElement) { + contextTable._tdElement = tdElement; + contextTable._trElement = tdElement.parentNode; + } + + const rows = contextTable._trElements = table.rows; + const cellIndex = tdElement.cellIndex; + + let cellCnt = 0; + for (let i = 0, cells = rows[0].cells, len = rows[0].cells.length; i < len; i++) { + cellCnt += cells[i].colSpan; + } + + // row cnt, row index + const rowIndex = contextTable._rowIndex = contextTable._trElement.rowIndex; + contextTable._rowCnt = rows.length; + + // cell cnt, physical cell index + contextTable._physical_cellCnt = contextTable._trElement.cells.length; + contextTable._logical_cellCnt = cellCnt; + contextTable._physical_cellIndex = cellIndex; + + // span + contextTable._current_colSpan = contextTable._tdElement.colSpan - 1; + contextTable._current_rowSpan - contextTable._trElement.cells[cellIndex].rowSpan - 1; + + // find logcal cell index + let rowSpanArr = []; + let spanIndex = []; + for (let i = 0, cells, colSpan; i <= rowIndex; i++) { + cells = rows[i].cells; + colSpan = 0; + for (let c = 0, cLen = cells.length, cell, cs, rs, logcalIndex; c < cLen; c++) { + cell = cells[c]; + cs = cell.colSpan - 1; + rs = cell.rowSpan - 1; + logcalIndex = c + colSpan; + + if (spanIndex.length > 0) { + for (let r = 0, arr; r < spanIndex.length; r++) { + arr = spanIndex[r]; + if (arr.row > i) continue; + if (logcalIndex >= arr.index) { + colSpan += arr.cs; + logcalIndex += arr.cs; + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } else if (c === cLen - 1) { + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } + } + } + + // logcal cell index + if (i === rowIndex && c === cellIndex) { + contextTable._logical_cellIndex = logcalIndex; + break; + } + + if (rs > 0) { + rowSpanArr.push({ + index: logcalIndex, + cs: cs + 1, + rs: rs, + row: -1 + }); + } + + colSpan += cs; + } + + spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {return a.index - b.index;}); + rowSpanArr = []; + } + + rowSpanArr = null; + spanIndex = null; + } + }, + + editTable: function (type, option) { + const tablePlugin = this.plugins.table; + const contextTable = this.context.table; + const table = contextTable._element; + const isRow = type === 'row'; + + if (isRow) { + const tableAttr = contextTable._trElement.parentNode; + if (/^THEAD$/i.test(tableAttr.nodeName)) { + if (option === 'up') { + return; + } else if (!tableAttr.nextElementSibling || !/^TBODY$/i.test(tableAttr.nextElementSibling.nodeName)) { + table.innerHTML += '' + tablePlugin.createCells.call(this, 'td', contextTable._logical_cellCnt, false) + ''; + return; + } + } + } + + // multi + if (tablePlugin._ref) { + const positionCell = contextTable._tdElement; + const selectedCells = tablePlugin._selectedCells; + // multi - row + if (isRow) { + // remove row + if (!option) { + let row = selectedCells[0].parentNode; + const removeCells = [selectedCells[0]]; + + for (let i = 1, len = selectedCells.length, cell; i < len; i++) { + cell = selectedCells[i]; + if (row !== cell.parentNode) { + removeCells.push(cell); + row = cell.parentNode; + } + } + + for (let i = 0, len = removeCells.length; i < len; i++) { + tablePlugin.setCellInfo.call(this, removeCells[i], true); + tablePlugin.editRow.call(this, option); + } + } else { // edit row + tablePlugin.setCellInfo.call(this, option === 'up' ? selectedCells[0] : selectedCells[selectedCells.length - 1], true); + tablePlugin.editRow.call(this, option, positionCell); + } + } else { // multi - cell + const firstRow = selectedCells[0].parentNode; + // remove cell + if (!option) { + const removeCells = [selectedCells[0]]; + + for (let i = 1, len = selectedCells.length, cell; i < len; i++) { + cell = selectedCells[i]; + if (firstRow === cell.parentNode) { + removeCells.push(cell); + } else { + break; + } + } + + for (let i = 0, len = removeCells.length; i < len; i++) { + tablePlugin.setCellInfo.call(this, removeCells[i], true); + tablePlugin.editCell.call(this, option); + } + } else { // edit cell + let rightCell = null; + + for (let i = 0, len = selectedCells.length - 1; i < len; i++) { + if (firstRow !== selectedCells[i + 1].parentNode) { + rightCell = selectedCells[i]; + break; + } + } + + tablePlugin.setCellInfo.call(this, option === 'left' ? selectedCells[0] : rightCell || selectedCells[0], true); + tablePlugin.editCell.call(this, option, positionCell); + } + } + + if (!option) tablePlugin.init.call(this); + } // one + else { + tablePlugin[isRow ? 'editRow' : 'editCell'].call(this, option); + } + + // after remove + if (!option) { + const children = table.children; + for (let i = 0; i < children.length; i++) { + if (children[i].children.length === 0) { + this.util.removeItem(children[i]); + i--; + } + } + + if (table.children.length === 0) this.util.removeItem(table); + } + }, + + editRow: function (option, positionResetElement) { + const contextTable = this.context.table; + const remove = !option; + + const up = option === 'up'; + const originRowIndex = contextTable._rowIndex; + const rowIndex = remove || up ? originRowIndex : originRowIndex + contextTable._current_rowSpan + 1; + const sign = remove ? -1 : 1; + + const rows = contextTable._trElements; + let cellCnt = contextTable._logical_cellCnt; + + for (let i = 0, len = originRowIndex + (remove ? -1 : 0), cell; i <= len; i++) { + cell = rows[i].cells; + if (cell.length === 0) return; + + for (let c = 0, cLen = cell.length, rs, cs; c < cLen; c++) { + rs = cell[c].rowSpan; + cs = cell[c].colSpan; + if (rs < 2 && cs < 2) continue; + + if (rs + i > rowIndex && rowIndex > i) { + cell[c].rowSpan = rs + sign; + cellCnt -= cs; + } + } + } + + if (remove) { + const next = rows[originRowIndex + 1]; + if (next) { + const spanCells = []; + let cells = rows[originRowIndex].cells; + let colSpan = 0; + + for (let i = 0, len = cells.length, cell, logcalIndex; i < len; i++) { + cell = cells[i]; + logcalIndex = i + colSpan; + colSpan += cell.colSpan - 1; + + if (cell.rowSpan > 1) { + cell.rowSpan -= 1; + spanCells.push({cell: cell.cloneNode(false), index: logcalIndex}); + } + } + + if (spanCells.length > 0) { + let spanCell = spanCells.shift(); + cells = next.cells; + colSpan = 0; + + for (let i = 0, len = cells.length, cell, logcalIndex; i < len; i++) { + cell = cells[i]; + logcalIndex = i + colSpan; + colSpan += cell.colSpan - 1; + + if (logcalIndex >= spanCell.index) { + i--, colSpan--; + colSpan += spanCell.cell.colSpan - 1; + next.insertBefore(spanCell.cell, cell); + spanCell = spanCells.shift(); + if (!spanCell) break; + } + } + + if (spanCell) { + next.appendChild(spanCell.cell); + for (let i = 0, len = spanCells.length; i < len; i++) { + next.appendChild(spanCells[i].cell); + } + } + } + } + + contextTable._element.deleteRow(rowIndex); + } else { + const newRow = contextTable._element.insertRow(rowIndex); + newRow.innerHTML = this.plugins.table.createCells.call(this, 'td', cellCnt, false); + } + + if (!remove) { + this.plugins.table.setPositionControllerDiv.call(this, positionResetElement || contextTable._tdElement, true); + } else { + this.controllersOff(); + } + }, + + editCell: function (option, positionResetElement) { + const contextTable = this.context.table; + const util = this.util; + const remove = !option; + + const left = option === 'left'; + const colSpan = contextTable._current_colSpan; + const cellIndex = remove || left ? contextTable._logical_cellIndex : contextTable._logical_cellIndex + colSpan + 1; + + const rows = contextTable._trElements; + let rowSpanArr = []; + let spanIndex = []; + let passCell = 0; + const removeCell = []; + const removeSpanArr = []; + + for (let i = 0, len = contextTable._rowCnt, row, insertIndex, cells, newCell, applySpan, cellColSpan; i < len; i++) { + row = rows[i]; + insertIndex = cellIndex; + applySpan = false; + cells = row.cells; + cellColSpan = 0; + + for (let c = 0, cell, cLen = cells.length, rs, cs, removeIndex; c < cLen; c++) { + cell = cells[c]; + if (!cell) break; + + rs = cell.rowSpan - 1; + cs = cell.colSpan - 1; + + if (!remove) { + if (c >= insertIndex) break; + if (cs > 0) { + if (passCell < 1 && cs + c >= insertIndex) { + cell.colSpan += 1; + insertIndex = null; + passCell = rs + 1; + break; + } + + insertIndex -= cs; + } + + if (!applySpan) { + for (let r = 0, arr; r < spanIndex.length; r++) { + arr = spanIndex[r]; + insertIndex -= arr.cs; + arr.rs -= 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } + applySpan = true; + } + } else { + removeIndex = c + cellColSpan; + + if (spanIndex.length > 0) { + const lastCell = !cells[c + 1]; + for (let r = 0, arr; r < spanIndex.length; r++) { + arr = spanIndex[r]; + if (arr.row > i) continue; + + if (removeIndex >= arr.index) { + cellColSpan += arr.cs; + removeIndex = c + cellColSpan; + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } else if (lastCell) { + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } + } + } + + if (rs > 0) { + rowSpanArr.push({ + rs: rs, + cs: cs + 1, + index: removeIndex, + row: -1 + }); + } + + if (removeIndex >= insertIndex && removeIndex + cs <= insertIndex + colSpan) { + removeCell.push(cell); + } else if (removeIndex <= insertIndex + colSpan && removeIndex + cs >= insertIndex) { + cell.colSpan -= util.getOverlapRangeAtIndex(cellIndex, cellIndex + colSpan, removeIndex, removeIndex + cs); + } else if (rs > 0 && (removeIndex < insertIndex || removeIndex + cs > insertIndex + colSpan)) { + removeSpanArr.push({ + cell: cell, + i: i, + rs: i + rs + }); + } + + cellColSpan += cs; + } + } + + spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {return a.index - b.index;}); + rowSpanArr = []; + + if (!remove) { + if (passCell > 0) { + passCell -= 1; + continue; + } + + if (insertIndex !== null && cells.length > 0) { + newCell = this.plugins.table.createCells.call(this, cells[0].nodeName, 0, true); + newCell = row.insertBefore(newCell, cells[insertIndex]); + } + } + } + + if (remove) { + let removeFirst, removeEnd; + for (let r = 0, rLen = removeCell.length, row; r < rLen; r++) { + row = removeCell[r].parentNode; + util.removeItem(removeCell[r]); + if (row.cells.length === 0) { + if (!removeFirst) removeFirst = util.getArrayIndex(rows, row); + removeEnd = util.getArrayIndex(rows, row); + util.removeItem(row); + } + } + + for (let c = 0, cLen = removeSpanArr.length, rowSpanCell; c < cLen; c++) { + rowSpanCell = removeSpanArr[c]; + rowSpanCell.cell.rowSpan = util.getOverlapRangeAtIndex(removeFirst, removeEnd, rowSpanCell.i, rowSpanCell.rs); + } + + this.controllersOff(); + } else { + this.plugins.table.setPositionControllerDiv.call(this, positionResetElement || contextTable._tdElement, true); + } + }, + + _closeSplitMenu: null, + openSplitMenu: function () { + this.util.addClass(this.context.table.splitButton, 'on'); + this.context.table.splitMenu.style.display = 'inline-table'; + + this.plugins.table._closeSplitMenu = function () { + this.util.removeClass(this.context.table.splitButton, 'on'); + this.context.table.splitMenu.style.display = 'none'; + this.removeDocEvent('click', this.plugins.table._closeSplitMenu); + this.plugins.table._closeSplitMenu = null; + }.bind(this); + + this.addDocEvent('click', this.plugins.table._closeSplitMenu); + }, + + splitCells: function (direction) { + const util = this.util; + const vertical = direction === 'vertical'; + const contextTable = this.context.table; + const currentCell = contextTable._tdElement; + const rows = contextTable._trElements; + const currentRow = contextTable._trElement; + const index = contextTable._logical_cellIndex; + const rowIndex = contextTable._rowIndex; + const newCell = this.plugins.table.createCells.call(this, currentCell.nodeName, 0, true); + + // vertical + if (vertical) { + const currentColSpan = currentCell.colSpan; + newCell.rowSpan = currentCell.rowSpan; + + // colspan > 1 + if (currentColSpan > 1) { + newCell.colSpan = this._w.Math.floor(currentColSpan/2); + currentCell.colSpan = currentColSpan - newCell.colSpan; + currentRow.insertBefore(newCell, currentCell.nextElementSibling); + } else { // colspan - 1 + let rowSpanArr = []; + let spanIndex = []; + + for (let i = 0, len = contextTable._rowCnt, cells, colSpan; i < len; i++) { + cells = rows[i].cells; + colSpan = 0; + for (let c = 0, cLen = cells.length, cell, cs, rs, logcalIndex; c < cLen; c++) { + cell = cells[c]; + cs = cell.colSpan - 1; + rs = cell.rowSpan - 1; + logcalIndex = c + colSpan; + + if (spanIndex.length > 0) { + for (let r = 0, arr; r < spanIndex.length; r++) { + arr = spanIndex[r]; + if (arr.row > i) continue; + if (logcalIndex >= arr.index) { + colSpan += arr.cs; + logcalIndex += arr.cs; + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } else if (c === cLen - 1) { + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } + } + } + + if (logcalIndex <= index && rs > 0) { + rowSpanArr.push({ + index: logcalIndex, + cs: cs + 1, + rs: rs, + row: -1 + }); + } + + if (cell !== currentCell && logcalIndex <= index && logcalIndex + cs >= index + currentColSpan - 1) { + cell.colSpan += 1; + break; + } + + if (logcalIndex > index) break; + + colSpan += cs; + } + + spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {return a.index - b.index;}); + rowSpanArr = []; + } + + currentRow.insertBefore(newCell, currentCell.nextElementSibling); + } + } else { // horizontal + const currentRowSpan = currentCell.rowSpan; + newCell.colSpan = currentCell.colSpan; + + // rowspan > 1 + if (currentRowSpan > 1) { + newCell.rowSpan = this._w.Math.floor(currentRowSpan/2); + const newRowSpan = currentRowSpan - newCell.rowSpan; + + const rowSpanArr = []; + const nextRowIndex = util.getArrayIndex(rows, currentRow) + newRowSpan; + + for (let i = 0, cells, colSpan; i < nextRowIndex; i++) { + cells = rows[i].cells; + colSpan = 0; + for (let c = 0, cLen = cells.length, cell, cs, logcalIndex; c < cLen; c++) { + logcalIndex = c + colSpan; + if (logcalIndex >= index) break; + + cell = cells[c]; + cs = cell.rowSpan - 1; + if (cs > 0 && cs + i >= nextRowIndex && logcalIndex < index) { + rowSpanArr.push({ + index: logcalIndex, + cs: cell.colSpan + }); + } + colSpan += cell.colSpan - 1; + } + } + + const nextRow = rows[nextRowIndex]; + const nextCells = nextRow.cells; + let rs = rowSpanArr.shift(); + + for (let c = 0, cLen = nextCells.length, colSpan = 0, cell, cs, logcalIndex, insertIndex; c < cLen; c++) { + logcalIndex = c + colSpan; + cell = nextCells[c]; + cs = cell.colSpan - 1; + insertIndex = logcalIndex + cs + 1; + + if (rs && insertIndex >= rs.index) { + colSpan += rs.cs; + insertIndex += rs.cs; + rs = rowSpanArr.shift(); + } + + if (insertIndex >= index || c === cLen - 1) { + nextRow.insertBefore(newCell, cell.nextElementSibling); + break; + } + + colSpan += cs; + } + + currentCell.rowSpan = newRowSpan; + } else { // rowspan - 1 + newCell.rowSpan = currentCell.rowSpan; + const newRow = util.createElement('TR'); + newRow.appendChild(newCell); + + for (let i = 0, cells; i < rowIndex; i++) { + cells = rows[i].cells; + if (cells.length === 0) return; + + for (let c = 0, cLen = cells.length; c < cLen; c++) { + if (i + cells[c].rowSpan - 1 >= rowIndex) { + cells[c].rowSpan += 1; + } + } + } + + const physicalIndex = contextTable._physical_cellIndex; + const cells = currentRow.cells; + + for (let c = 0, cLen = cells.length; c < cLen; c++) { + if (c === physicalIndex) continue; + cells[c].rowSpan += 1; + } + + currentRow.parentNode.insertBefore(newRow, currentRow.nextElementSibling); + } + } + + this.focusEdge(currentCell); + this.plugins.table.setPositionControllerDiv.call(this, currentCell, true); + }, + + mergeCells: function () { + const tablePlugin = this.plugins.table; + const contextTable = this.context.table; + const util = this.util; + + const ref = tablePlugin._ref; + const selectedCells = tablePlugin._selectedCells; + const mergeCell = selectedCells[0]; + + let emptyRowFirst = null; + let emptyRowLast = null; + let cs = (ref.ce - ref.cs) + 1; + let rs = (ref.re - ref.rs) + 1; + let mergeHTML = ''; + let row = null; + + for (let i = 1, len = selectedCells.length, cell, ch; i < len; i++) { + cell = selectedCells[i]; + if (row !== cell.parentNode) row = cell.parentNode; + + ch = cell.children; + for (let c = 0, cLen = ch.length; c < cLen; c++) { + if (util.isFormatElement(ch[c]) && util.onlyZeroWidthSpace(ch[c].textContent)) { + util.removeItem(ch[c]); + } + } + + mergeHTML += cell.innerHTML; + util.removeItem(cell); + + if (row.cells.length === 0) { + if (!emptyRowFirst) emptyRowFirst = row; + else emptyRowLast = row; + rs -= 1; + } + } + + if (emptyRowFirst) { + const rows = contextTable._trElements; + const rowIndexFirst = util.getArrayIndex(rows, emptyRowFirst); + const rowIndexLast = util.getArrayIndex(rows, emptyRowLast || emptyRowFirst); + const removeRows = []; + + for (let i = 0, cells; i <= rowIndexLast; i++) { + cells = rows[i].cells; + if (cells.length === 0) { + removeRows.push(rows[i]); + continue; + } + + for (let c = 0, cLen = cells.length, cell, rs; c < cLen; c++) { + cell = cells[c]; + rs = cell.rowSpan - 1; + if (rs > 0 && i + rs >= rowIndexFirst) { + cell.rowSpan -= util.getOverlapRangeAtIndex(rowIndexFirst, rowIndexLast, i, i + rs); + } + } + } + + for (let i = 0, len = removeRows.length; i < len; i++) { + util.removeItem(removeRows[i]); + } + } + + mergeCell.innerHTML += mergeHTML; + mergeCell.colSpan = cs; + mergeCell.rowSpan = rs; + + this.controllersOff(); + tablePlugin.setActiveButton.call(this, true, false); + tablePlugin.call_controller_tableEdit.call(this, mergeCell); + + util.addClass(mergeCell, 'se-table-selected-cell'); + this.focusEdge(mergeCell); + }, + + toggleHeader: function () { + const util = this.util; + const headerButton = this.context.table.headerButton; + const active = util.hasClass(headerButton, 'active'); + const table = this.context.table._element; + + if (!active) { + const header = util.createElement('THEAD'); + header.innerHTML = '' + this.plugins.table.createCells.call(this, 'th', this.context.table._logical_cellCnt, false) + ''; + table.insertBefore(header, table.firstElementChild); + } else { + util.removeItem(table.querySelector('thead')); + } + + util.toggleClass(headerButton, 'active'); + + if (/TH/i.test(this.context.table._tdElement.nodeName)) { + this.controllersOff(); + } else { + this.plugins.table.setPositionControllerDiv.call(this, this.context.table._tdElement, false); + } + }, + + setTableStyle: function (styles) { + const contextTable = this.context.table; + const tableElement = contextTable._element; + let icon, span, sizeIcon, text; + + if (styles.indexOf('width') > -1) { + icon = contextTable.resizeButton.firstElementChild; + span = contextTable.resizeText; + + if (!contextTable._maxWidth) { + sizeIcon = contextTable.icons.expansion; + text = contextTable.maxText; + contextTable.columnFixedButton.style.display = 'none'; + this.util.removeClass(tableElement, 'se-table-size-100'); + this.util.addClass(tableElement, 'se-table-size-auto'); + } else { + sizeIcon = contextTable.icons.reduction; + text = contextTable.minText; + contextTable.columnFixedButton.style.display = 'block'; + this.util.removeClass(tableElement, 'se-table-size-auto'); + this.util.addClass(tableElement, 'se-table-size-100'); + } + + this.util.changeElement(icon, sizeIcon); + this.util.changeTxt(span, text); + } + + if (styles.indexOf('column') > -1) { + if (!contextTable._fixedColumn) { + this.util.removeClass(tableElement, 'se-table-layout-fixed'); + this.util.addClass(tableElement, 'se-table-layout-auto'); + this.util.removeClass(contextTable.columnFixedButton, 'active'); + } else { + this.util.removeClass(tableElement, 'se-table-layout-auto'); + this.util.addClass(tableElement, 'se-table-layout-fixed'); + this.util.addClass(contextTable.columnFixedButton, 'active'); + } + + } + }, + + setActiveButton: function (fixedCell, selectedCell) { + const contextTable = this.context.table; + + if (/^TH$/i.test(fixedCell.nodeName)) { + contextTable.insertRowAboveButton.setAttribute('disabled', true); + contextTable.insertRowBelowButton.setAttribute('disabled', true); + } else { + contextTable.insertRowAboveButton.removeAttribute('disabled'); + contextTable.insertRowBelowButton.removeAttribute('disabled'); + } + + if (!selectedCell || fixedCell === selectedCell) { + contextTable.splitButton.removeAttribute('disabled'); + contextTable.mergeButton.setAttribute('disabled', true); + } else { + contextTable.splitButton.setAttribute('disabled', true); + contextTable.mergeButton.removeAttribute('disabled'); + } + }, + + // multi selecte + _bindOnSelect: null, + _bindOffSelect: null, + _bindOffShift: null, + _selectedCells: null, + _shift: false, + _fixedCell: null, + _fixedCellName: null, + _selectedCell: null, + _selectedTable: null, + _ref: null, + _toggleEditor: function (enabled) { + this.context.element.wysiwyg.setAttribute('contenteditable', enabled); + if (enabled) this.util.removeClass(this.context.element.wysiwyg, 'se-disabled'); + else this.util.addClass(this.context.element.wysiwyg, 'se-disabled'); + }, + + _offCellMultiSelect: function (e) { + e.stopPropagation(); + const tablePlugin = this.plugins.table; + + if (!tablePlugin._shift) { + tablePlugin._removeEvents.call(this); + tablePlugin._toggleEditor.call(this, true); + } else if (tablePlugin._initBind) { + this._wd.removeEventListener('touchmove', tablePlugin._initBind); + tablePlugin._initBind = null; + } + + if (!tablePlugin._fixedCell || !tablePlugin._selectedTable) return; + + tablePlugin.setActiveButton.call(this, tablePlugin._fixedCell, tablePlugin._selectedCell); + tablePlugin.call_controller_tableEdit.call(this, tablePlugin._selectedCell || tablePlugin._fixedCell); + + tablePlugin._selectedCells = tablePlugin._selectedTable.querySelectorAll('.se-table-selected-cell'); + if (tablePlugin._selectedCell && tablePlugin._fixedCell) this.focusEdge(tablePlugin._selectedCell); + + if (!tablePlugin._shift) { + tablePlugin._fixedCell = null; + tablePlugin._selectedCell = null; + tablePlugin._fixedCellName = null; + } + }, + + _onCellMultiSelect: function (e) { + this._antiBlur = true; + const tablePlugin = this.plugins.table; + const target = this.util.getParentElement(e.target, this.util.isCell); + + if (tablePlugin._shift) { + if (target === tablePlugin._fixedCell) tablePlugin._toggleEditor.call(this, true); + else tablePlugin._toggleEditor.call(this, false); + } else if (!tablePlugin._ref) { + if (target === tablePlugin._fixedCell) return; + else tablePlugin._toggleEditor.call(this, false); + } + + if (!target || target === tablePlugin._selectedCell || tablePlugin._fixedCellName !== target.nodeName || + tablePlugin._selectedTable !== this.util.getParentElement(target, 'TABLE')) { + return; + } + + tablePlugin._selectedCell = target; + tablePlugin._setMultiCells.call(this, tablePlugin._fixedCell, target); + }, + + _setMultiCells: function (startCell, endCell) { + const tablePlugin = this.plugins.table; + const rows = tablePlugin._selectedTable.rows; + const util = this.util; + + const selectedCells = tablePlugin._selectedTable.querySelectorAll('.se-table-selected-cell'); + for (let i = 0, len = selectedCells.length; i < len; i++) { + util.removeClass(selectedCells[i], 'se-table-selected-cell'); + } + + if (startCell === endCell) { + util.addClass(startCell, 'se-table-selected-cell'); + if (!tablePlugin._shift) return; + } + + let findSelectedCell = true; + let spanIndex = []; + let rowSpanArr = []; + const ref = tablePlugin._ref = {_i: 0, cs: null, ce: null, rs: null, re: null}; + + for (let i = 0, len = rows.length, cells, colSpan; i < len; i++) { + cells = rows[i].cells; + colSpan = 0; + + for (let c = 0, cLen = cells.length, cell, logcalIndex, cs, rs; c < cLen; c++) { + cell = cells[c]; + cs = cell.colSpan - 1; + rs = cell.rowSpan - 1; + logcalIndex = c + colSpan; + + if (spanIndex.length > 0) { + for (let r = 0, arr; r < spanIndex.length; r++) { + arr = spanIndex[r]; + if (arr.row > i) continue; + if (logcalIndex >= arr.index) { + colSpan += arr.cs; + logcalIndex += arr.cs; + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } else if (c === cLen - 1) { + arr.rs -= 1; + arr.row = i + 1; + if (arr.rs < 1) { + spanIndex.splice(r, 1); + r--; + } + } + } + } + + if (findSelectedCell) { + if (cell === startCell || cell === endCell) { + ref.cs = ref.cs !== null && ref.cs < logcalIndex ? ref.cs : logcalIndex; + ref.ce = ref.ce !== null && ref.ce > logcalIndex + cs ? ref.ce : logcalIndex + cs; + ref.rs = ref.rs !== null && ref.rs < i ? ref.rs : i; + ref.re = ref.re !== null && ref.re > i + rs ? ref.re : i + rs; + ref._i += 1; + } + + if (ref._i === 2) { + findSelectedCell = false; + spanIndex = []; + rowSpanArr = []; + i = -1; + break; + } + } else if (util.getOverlapRangeAtIndex(ref.cs, ref.ce, logcalIndex, logcalIndex + cs) && util.getOverlapRangeAtIndex(ref.rs, ref.re, i, i + rs)) { + const newCs = ref.cs < logcalIndex ? ref.cs : logcalIndex; + const newCe = ref.ce > logcalIndex + cs ? ref.ce : logcalIndex + cs; + const newRs = ref.rs < i ? ref.rs : i; + const newRe = ref.re > i + rs ? ref.re : i + rs; + + if (ref.cs !== newCs || ref.ce !== newCe || ref.rs !== newRs || ref.re !== newRe) { + ref.cs = newCs; + ref.ce = newCe; + ref.rs = newRs; + ref.re = newRe; + i = -1; + + spanIndex = []; + rowSpanArr = []; + break; + } + + util.addClass(cell, 'se-table-selected-cell'); + } + + if (rs > 0) { + rowSpanArr.push({ + index: logcalIndex, + cs: cs + 1, + rs: rs, + row: -1 + }); + } + + colSpan += cell.colSpan - 1; + } + + spanIndex = spanIndex.concat(rowSpanArr).sort(function (a, b) {return a.index - b.index;}); + rowSpanArr = []; + } + }, + + _removeEvents: function () { + const tablePlugin = this.plugins.table; + + if (tablePlugin._initBind) { + this._wd.removeEventListener('touchmove', tablePlugin._initBind); + tablePlugin._initBind = null; + } + + if (tablePlugin._bindOnSelect) { + this._wd.removeEventListener('mousedown', tablePlugin._bindOnSelect); + this._wd.removeEventListener('mousemove', tablePlugin._bindOnSelect); + tablePlugin._bindOnSelect = null; + } + + if (tablePlugin._bindOffSelect) { + this._wd.removeEventListener('mouseup', tablePlugin._bindOffSelect); + tablePlugin._bindOffSelect = null; + } + + if (tablePlugin._bindOffShift) { + this._wd.removeEventListener('keyup', tablePlugin._bindOffShift); + tablePlugin._bindOffShift = null; + } + }, + + _initBind: null, + onTableCellMultiSelect: function (tdElement, shift) { + const tablePlugin = this.plugins.table; + + tablePlugin._removeEvents.call(this); + this.controllersOff(); + + tablePlugin._shift = shift; + tablePlugin._fixedCell = tdElement; + tablePlugin._fixedCellName = tdElement.nodeName; + tablePlugin._selectedTable = this.util.getParentElement(tdElement, 'TABLE'); + + const selectedCells = tablePlugin._selectedTable.querySelectorAll('.se-table-selected-cell'); + for (let i = 0, len = selectedCells.length; i < len; i++) { + this.util.removeClass(selectedCells[i], 'se-table-selected-cell'); + } + + this.util.addClass(tdElement, 'se-table-selected-cell'); + + tablePlugin._bindOnSelect = tablePlugin._onCellMultiSelect.bind(this); + tablePlugin._bindOffSelect = tablePlugin._offCellMultiSelect.bind(this); + + if (!shift) { + this._wd.addEventListener('mousemove', tablePlugin._bindOnSelect, false); + } else { + tablePlugin._bindOffShift = function () { + this.controllersOn(this.context.table.resizeDiv, this.context.table.tableController, this.plugins.table.init.bind(this), tdElement, 'table'); + if (!tablePlugin._ref) this.controllersOff(); + }.bind(this); + + this._wd.addEventListener('keyup', tablePlugin._bindOffShift, false); + this._wd.addEventListener('mousedown', tablePlugin._bindOnSelect, false); + } + + this._wd.addEventListener('mouseup', tablePlugin._bindOffSelect, false); + tablePlugin._initBind = tablePlugin.init.bind(this); + this._wd.addEventListener('touchmove', tablePlugin._initBind, false); + }, + + onClick_tableController: function (e) { + e.stopPropagation(); + const target = e.target.getAttribute('data-command') ? e.target : e.target.parentNode; + + if (target.getAttribute('disabled')) return; + + const command = target.getAttribute('data-command'); + const value = target.getAttribute('data-value'); + const option = target.getAttribute('data-option'); + const tablePlugin = this.plugins.table; + + if (typeof tablePlugin._closeSplitMenu === 'function') { + tablePlugin._closeSplitMenu(); + if (command === 'onsplit') return; + } + + if (!command) return; + + e.preventDefault(); + const contextTable = this.context.table; + + switch (command) { + case 'insert': + case 'delete': + tablePlugin.editTable.call(this, value, option); + break; + case 'header': + tablePlugin.toggleHeader.call(this); + break; + case 'onsplit': + tablePlugin.openSplitMenu.call(this); + break; + case 'split': + tablePlugin.splitCells.call(this, value); + break; + case 'merge': + tablePlugin.mergeCells.call(this); + break; + case 'resize': + contextTable._maxWidth = !contextTable._maxWidth; + tablePlugin.setTableStyle.call(this, 'width'); + tablePlugin.setPositionControllerTop.call(this, contextTable._element); + tablePlugin.setPositionControllerDiv.call(this, contextTable._tdElement, tablePlugin._shift); + break; + case 'layout': + contextTable._fixedColumn = !contextTable._fixedColumn; + tablePlugin.setTableStyle.call(this, 'column'); + tablePlugin.setPositionControllerTop.call(this, contextTable._element); + tablePlugin.setPositionControllerDiv.call(this, contextTable._tdElement, tablePlugin._shift); + break; + case 'remove': + const emptyDiv = contextTable._element.parentNode; + this.util.removeItem(contextTable._element); + this.controllersOff(); + + if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null); + this.focus(); + } + + // history stack + this.history.push(false); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/template.js": +/*!****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/template.js ***! + \****************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'template', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.template = {}; + + /** set submenu */ + let templateDiv = this.setSubmenu(core); + + /** add event listeners */ + templateDiv.querySelector('ul').addEventListener('click', this.pickup.bind(core)); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, templateDiv); + + /** empty memory */ + templateDiv = null; + }, + + setSubmenu: function (core) { + const templateList = core.options.templates; + if (!templateList || templateList.length === 0) { + throw Error('[SUNEDITOR.plugins.template.fail] To use the "template" plugin, please define the "templates" option.'); + } + + const listDiv = core.util.createElement('DIV'); + listDiv.className = 'se-list-layer'; + + let list = '
    ' + + '
      '; + for (let i = 0, len = templateList.length, t; i < len; i++) { + t = templateList[i]; + list += '
    • '; + } + list += '
    '; + + listDiv.innerHTML = list; + + return listDiv; + }, + + pickup: function (e) { + if (!/^BUTTON$/i.test(e.target.tagName)) return false; + + e.preventDefault(); + e.stopPropagation(); + + const temp = this.options.templates[e.target.getAttribute('data-value')]; + + if (temp.html) { + this.setContents(temp.html); + } else { + this.submenuOff(); + throw Error('[SUNEDITOR.template.fail] cause : "templates[i].html not found"'); + } + + this.submenuOff(); + } +}); + +/***/ }), + +/***/ "./node_modules/suneditor/src/plugins/submenu/textStyle.js": +/*!*****************************************************************!*\ + !*** ./node_modules/suneditor/src/plugins/submenu/textStyle.js ***! + \*****************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + +/* harmony default export */ __webpack_exports__["default"] = ({ + name: 'textStyle', + display: 'submenu', + add: function (core, targetElement) { + const context = core.context; + context.textStyle = { + _styleList: null + }; + + /** set submenu */ + let listDiv = this.setSubmenu(core); + let listUl = listDiv.querySelector('ul'); + + /** add event listeners */ + listUl.addEventListener('click', this.pickup.bind(core)); + + context.textStyle._styleList = listDiv.querySelectorAll('li button'); + + /** append target button menu */ + core.initMenuTarget(this.name, targetElement, listDiv); + + /** empty memory */ + listDiv = null, listUl = null; + }, + + setSubmenu: function (core) { + const option = core.options; + const listDiv = core.util.createElement('DIV'); + listDiv.className = 'se-submenu se-list-layer se-list-format'; + + const defaultList = { + code: { + name: core.lang.menu.code, + class: '__se__t-code', + tag: 'code', + }, + translucent: { + name: core.lang.menu.translucent, + style: 'opacity: 0.5;', + tag: 'span', + }, + shadow: { + name: core.lang.menu.shadow, + class: '__se__t-shadow', + tag: 'span', + } + }; + const styleList = !option.textStyles ? core._w.Object.keys(defaultList) : option.textStyles; + + let list = '
      '; + for (let i = 0, len = styleList.length, t, tag, name, attrs, command, value, _class; i < len; i++) { + t = styleList[i]; + attrs = '', value = '', command = []; + + if (typeof t === 'string') { + const defaultStyle = defaultList[t.toLowerCase()]; + if (!defaultStyle) continue; + t = defaultStyle; + } + + name = t.name; + tag = t.tag || 'span'; + _class = t._class; + + if (t.style) { + attrs += ' style="' + t.style + '"'; + value += t.style.replace(/:[^;]+(;|$)\s*/g, ','); + command.push('style'); + } + if (t.class) { + attrs += ' class="' + t.class + '"'; + value += '.' + t.class.trim().replace(/\s+/g, ',.'); + command.push('class'); + } + + value = value.replace(/,$/, ''); + + list += '
    • ' + + '
    • '; + } + list += '
    '; + + listDiv.innerHTML = list; + + return listDiv; + }, + + /** + * @Override submenu + */ + on: function () { + const util = this.util; + const textStyleContext = this.context.textStyle; + const styleButtonList = textStyleContext._styleList; + const selectionNode = this.getSelectionNode(); + + for (let i = 0, len = styleButtonList.length, btn, data, active; i < len; i++) { + btn = styleButtonList[i]; + data = btn.getAttribute('data-value').split(','); + + for (let v = 0, node, value; v < data.length; v++) { + node = selectionNode; + active = false; + + while (node && !util.isFormatElement(node) && !util.isComponent(node)) { + if (node.nodeName.toLowerCase() === btn.getAttribute('data-command').toLowerCase()) { + value = data[v]; + if (/^\./.test(value) ? util.hasClass(node, value.replace(/^\./, '')) : !!node.style[value]) { + active = true; + break; + } + } + node = node.parentNode; + } + + if (!active) break; + } + + active ? util.addClass(btn, 'active') : util.removeClass(btn, 'active'); + } + + }, + + pickup: function (e) { + e.preventDefault(); + e.stopPropagation(); + + let target = e.target; + let command = null, tag = null; + + while (!command && !/UL/i.test(target.tagName)) { + command = target.getAttribute('data-command'); + if (command) { + tag = target.firstChild; + break; + } + target = target.parentNode; + } + + if (!command) return; + + const checkStyles = tag.style.cssText.replace(/:.+(;|$)/g, ',').split(','); + checkStyles.pop(); + + const classes = tag.classList; + for (let i = 0, len = classes.length; i < len; i++) { + checkStyles.push('.' + classes[i]); + } + + const newNode = this.util.hasClass(target, 'active') ? null : tag.cloneNode(false); + const removeNodes = newNode ? null : [tag.nodeName]; + this.nodeChange(newNode, checkStyles, removeNodes, true); + + this.submenuOff(); + } +}); + + +/***/ }), + +/***/ "./node_modules/suneditor/src/suneditor.js": +/*!*************************************************!*\ + !*** ./node_modules/suneditor/src/suneditor.js ***! + \*************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _lib_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/core */ "./node_modules/suneditor/src/lib/core.js"); +/* harmony import */ var _lib_util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/util */ "./node_modules/suneditor/src/lib/util.js"); +/* harmony import */ var _lib_constructor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/constructor */ "./node_modules/suneditor/src/lib/constructor.js"); +/* harmony import */ var _lib_context__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lib/context */ "./node_modules/suneditor/src/lib/context.js"); +/* + * wysiwyg web editor + * + * suneditor.js + * Copyright 2017 JiHong Lee. + * MIT license. + */ + + + + + + + +/* harmony default export */ __webpack_exports__["default"] = ({ + /** + * @description Returns the create function with preset options. + * If the options overlap, the options of the 'create' function take precedence. + * @param {Json} options Initialization options + * @returns {Object} + */ + init: function (init_options) { + return { + create: function (idOrElement, options) { + return this.create(idOrElement, options, init_options); + }.bind(this) + }; + }, + + /** + * @description Create the suneditor + * @param {String|Element} idOrElement textarea Id or textarea element + * @param {JSON|Object} options user options + * @returns {Object} + */ + create: function (idOrElement, options, _init_options) { + _lib_util__WEBPACK_IMPORTED_MODULE_1__["default"]._propertiesInit(); + + if (typeof options !== 'object') options = {}; + if (_init_options) { + options = [_init_options, options].reduce(function (init, option) { + for (let key in option) { + if (!_lib_util__WEBPACK_IMPORTED_MODULE_1__["default"].hasOwn(option, key)) continue; + if (key === 'plugins' && option[key] && init[key]) { + let i = init[key], o = option[key]; + i = i.length ? i : Object.keys(i).map(function(name) { return i[name]; }); + o = o.length ? o : Object.keys(o).map(function(name) { return o[name]; }); + init[key] = (o.filter(function(val) { return i.indexOf(val) === -1; })).concat(i); + } else { + init[key] = option[key]; + } + } + return init; + }, {}); + } + + const element = typeof idOrElement === 'string' ? document.getElementById(idOrElement) : idOrElement; + + if (!element) { + if (typeof idOrElement === 'string') { + throw Error('[SUNEDITOR.create.fail] The element for that id was not found (ID:"' + idOrElement + '")'); + } + + throw Error('[SUNEDITOR.create.fail] suneditor requires textarea\'s element or id value'); + } + + const cons = _lib_constructor__WEBPACK_IMPORTED_MODULE_2__["default"].init(element, options); + + if (cons.constructed._top.id && document.getElementById(cons.constructed._top.id)) { + throw Error('[SUNEDITOR.create.fail] The ID of the suneditor you are trying to create already exists (ID:"' + cons.constructed._top.id + '")'); + } + + return Object(_lib_core__WEBPACK_IMPORTED_MODULE_0__["default"])(Object(_lib_context__WEBPACK_IMPORTED_MODULE_3__["default"])(element, cons.constructed, cons.options), cons.pluginCallButtons, cons.plugins, cons.options.lang, options, cons._responsiveButtons); + } +}); + + /***/ }), /***/ "./node_modules/webpack/buildin/global.js": @@ -37948,6 +59427,8 @@ module.exports = function(module) { */ __webpack_require__(/*! ./bootstrap */ "./resources/js/bootstrap.js"); +__webpack_require__(/*! ./suneditor */ "./resources/js/suneditor.js"); + /***/ }), /***/ "./resources/js/bootstrap.js": @@ -37997,6 +59478,36 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; /***/ }), +/***/ "./resources/js/suneditor.js": +/*!***********************************!*\ + !*** ./resources/js/suneditor.js ***! + \***********************************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var suneditor_dist_css_suneditor_min_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! suneditor/dist/css/suneditor.min.css */ "./node_modules/suneditor/dist/css/suneditor.min.css"); +/* harmony import */ var suneditor_dist_css_suneditor_min_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(suneditor_dist_css_suneditor_min_css__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var suneditor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! suneditor */ "./node_modules/suneditor/src/suneditor.js"); +/* harmony import */ var suneditor_src_plugins__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! suneditor/src/plugins */ "./node_modules/suneditor/src/plugins/index.js"); + + + +suneditor__WEBPACK_IMPORTED_MODULE_1__["default"].create('sample', { + plugins: suneditor_src_plugins__WEBPACK_IMPORTED_MODULE_2__["default"], + buttonList: [['undo', 'redo'], ['font', 'fontSize', 'formatBlock'], ['paragraphStyle', 'blockquote'], ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'], ['fontColor', 'hiliteColor', 'textStyle'], ['removeFormat'], '/', // Line break + ['outdent', 'indent'], ['align', 'horizontalRule', 'list', 'lineHeight'], ['table', 'link', 'image', 'video', 'audio' + /** ,'math' */ + ], // You must add the 'katex' library at options to use the 'math' plugin. + + /** ['imageGallery'] */ + // You must add the "imageGalleryUrl". + ['fullScreen', 'showBlocks', 'codeView'], ['preview', 'print'], ['save', 'template']] +}); + +/***/ }), + /***/ "./resources/sass/app.scss": /*!*********************************!*\ !*** ./resources/sass/app.scss ***! diff --git a/motorradig/resources/js/app.js b/motorradig/resources/js/app.js index 9c481b4..f82e334 100644 --- a/motorradig/resources/js/app.js +++ b/motorradig/resources/js/app.js @@ -5,3 +5,4 @@ */ require('./bootstrap'); +require('./suneditor') diff --git a/motorradig/resources/js/suneditor.js b/motorradig/resources/js/suneditor.js new file mode 100644 index 0000000..7d3b595 --- /dev/null +++ b/motorradig/resources/js/suneditor.js @@ -0,0 +1,27 @@ + + +import 'suneditor/dist/css/suneditor.min.css' +import suneditor from 'suneditor' +import plugins from 'suneditor/src/plugins' + +suneditor.create('sample', { + plugins: plugins, + buttonList: [ + ['undo', 'redo'], + ['font', 'fontSize', 'formatBlock'], + ['paragraphStyle', 'blockquote'], + ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'], + ['fontColor', 'hiliteColor', 'textStyle'], + ['removeFormat'], + '/', // Line break + ['outdent', 'indent'], + ['align', 'horizontalRule', 'list', 'lineHeight'], + ['table', 'link', 'image', 'video', 'audio' /** ,'math' */], // You must add the 'katex' library at options to use the 'math' plugin. + /** ['imageGallery'] */ // You must add the "imageGalleryUrl". + ['fullScreen', 'showBlocks', 'codeView'], + ['preview', 'print'], + ['save', 'template'] + ] +}) + + diff --git a/motorradig/resources/views/home.blade.php b/motorradig/resources/views/home.blade.php index ee355b7..0d17164 100644 --- a/motorradig/resources/views/home.blade.php +++ b/motorradig/resources/views/home.blade.php @@ -18,10 +18,15 @@ @endif - + + + @@ -30,4 +35,6 @@ + + @endsection diff --git a/motorradig/resources/views/users/show.blade.php b/motorradig/resources/views/users/show.blade.php index 124a0c0..024e842 100644 --- a/motorradig/resources/views/users/show.blade.php +++ b/motorradig/resources/views/users/show.blade.php @@ -27,8 +27,9 @@ @if(file_exists (storage_path().'/img_storage/user/'.$user->id.'.jpg')) - - + + + @else diff --git a/motorradig/storage/img_storage/user/1.jpg b/motorradig/storage/img_storage/user/1.jpg index 1866ed6..22c8abf 100644 Binary files a/motorradig/storage/img_storage/user/1.jpg and b/motorradig/storage/img_storage/user/1.jpg differ diff --git a/motorradig/storage/img_storage/user/1_gross.jpg b/motorradig/storage/img_storage/user/1_gross.jpg index 8c5f2be..419a642 100644 Binary files a/motorradig/storage/img_storage/user/1_gross.jpg and b/motorradig/storage/img_storage/user/1_gross.jpg differ