mirror of
https://github.com/webislife/wc-wysiwyg.git
synced 2025-07-20 06:16:09 +00:00
initial commut
This commit is contained in:
34
.github/workflows/release-package.yml
vendored
Normal file
34
.github/workflows/release-package.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: wc-wysiwyg package
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- run: npm install
|
||||
- run: npm run tsc
|
||||
- run: npm run babel-minify
|
||||
- run: npm run sass
|
||||
|
||||
publish-gpr:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://npm.pkg.github.com/
|
||||
- run: npm publish --public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
package-lock.json
|
1
.npmignore
Normal file
1
.npmignore
Normal file
@ -0,0 +1 @@
|
||||
/.github
|
51
README.md
Normal file
51
README.md
Normal file
@ -0,0 +1,51 @@
|
||||
# wc-time
|
||||
WYWSIWYG HTML5 Editor written in TypeScript and designed by web-componennt, support all JS frameworks and browsers.
|
||||
See full demo - [wc-wysiwyg demo](https://webislife.ru/demo/wc-wysiwyg/) list and demo of all editor features
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm i wc-wysiwyg
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
Available package commands
|
||||
|
||||
```
|
||||
`npm run sass' - build scss styles
|
||||
`npm run tsc' - run typescript
|
||||
`npm run babel-minify' - minify code after typescript
|
||||
`npm run build' - build all stpes 1.sass 2.tsc 3.babel-minify
|
||||
```
|
||||
|
||||
## Custom element demo
|
||||
<!--
|
||||
```
|
||||
<custom-element-demo>
|
||||
<template>
|
||||
<link rel="import" href="index.html">
|
||||
<next-code-block></next-code-block>
|
||||
</template>
|
||||
</custom-element-demo>
|
||||
```
|
||||
-->
|
||||
```html
|
||||
<wc-wysiwyg id="wc-demo-comment"
|
||||
data-allow-tags="strong,u,i,b,q,blockquote,a,img,pre"
|
||||
data-storage="demo-comment"
|
||||
data-hide-bottom-actions="1"
|
||||
is="wc-wysiwyg"
|
||||
required
|
||||
minlength="5"
|
||||
maxlength="500">
|
||||
<textarea>your comment</textarea>
|
||||
</wc-wysiwyg>
|
||||
```
|
||||
|
||||
See full demo - [wc-wysiwyg demo](https://webislife.ru/demo/wc-wysiwyg/) list and demo of all editor features
|
||||
|
||||
Dont forgot star on git! Thank you! Enojoy!
|
||||
|
||||
Dev by strokoff.ru - make web, not war)
|
1
dist/core/el.js
vendored
Normal file
1
dist/core/el.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export const el=(tagName,{classList,styles,props,attrs,options,append}={})=>{if(!tagName)throw new Error(`Undefined tag ${tagName}`);const element=document.createElement(tagName,options);if(classList)for(let i=0;i<classList.length;i++){const styleClass=classList[i];element.classList.add(styleClass)}if(styles){const stylesKeys=Object.keys(styles);for(let i=0;i<stylesKeys.length;i++){const key=stylesKeys[i];element.style[key]=styles[key]}}if(props){const propKeys=Object.keys(props);for(let i=0;i<propKeys.length;i++){const key=propKeys[i];element[key]=props[key]}}if(attrs){const attrsKeys=Object.keys(attrs);for(let i=0;i<attrsKeys.length;i++){const key=attrsKeys[i];attrs[key]&&element.setAttribute(key,attrs[key])}}if(append)for(let i=0;i<append.length;i++){const appendEl=append[i];element.append(appendEl)}return element};
|
1
dist/core/translates.js
vendored
Normal file
1
dist/core/translates.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export const t={en:{h1:"Header 1 level",h2:"Header 2 level",h3:"Header 3 level",h4:"Header 4 level",h5:"Header 5 level",h6:"Header 6 level",span:"String",mark:"Marked text",small:"Small text",dfn:"Definition",a:"Link",q:"Inline quote",b:"Bold",i:"Italic",u:"Underlined",s:"Small",sup:"Superscript",sub:"Subscript",kbd:"Button",abbr:"Abbrevature",strong:"Important text",code:"Inline code",samp:"PC program output",del:"Deleted text from document",ins:"Insert text into document",var:"Variable designation",ul:"The bulleted list",ol:"Numbered list",pre:"Formatted text",time:"Date and time",img:"Image",audio:"Audio element",video:"Video element",blockquote:"Blockquote",clearFormat:"Clear text format",toggleViewMode:"Toggle view Text/HTML5",addNewParahraph:"Add new parahraph",fullScreen:"fullScreen",required:"Field required",minlength:"Min length is:",maxlength:"Max length is:",filtertags:"Found filter tag:"},ru:{h1:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 1 \u0443\u0440\u043E\u0432\u043D\u044F",h2:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 2 \u0443\u0440\u043E\u0432\u043D\u044F",h3:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 3 \u0443\u0440\u043E\u0432\u043D\u044F",h4:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 4 \u0443\u0440\u043E\u0432\u043D\u044F",h5:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 5 \u0443\u0440\u043E\u0432\u043D\u044F",h6:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 6 \u0443\u0440\u043E\u0432\u043D\u044F",span:"\u0421\u0442\u0440\u043E\u043A\u0430",mark:"\u041F\u043E\u043C\u0435\u0447\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442",small:"\u041C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442",dfn:"\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435",a:"\u0421\u0441\u044B\u043B\u043A\u0430",q:"\u0412\u043D\u0443\u0442\u0440\u0438\u0442\u0435\u043A\u0441\u0442\u043E\u0432\u0430\u044F \u0446\u0438\u0442\u0430\u0442\u0430",b:"\u0416\u0438\u0440\u043D\u044B\u0439",i:"\u041A\u0443\u0440\u0441\u0438\u0432",u:"\u041F\u043E\u0434\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044B\u0439",s:"\u041C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0439",sup:"\u041D\u0430\u0434\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0439",sub:"\u041F\u043E\u0434\u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0439",kbd:"\u041A\u043D\u043E\u043F\u043A\u0430",abbr:"\u0410\u0431\u0431\u0440\u0438\u0432\u0435\u0430\u0442\u0443\u0440\u0430",strong:"\u0412\u0430\u0436\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442",code:"\u0412\u043D\u0443\u0442\u0440\u0438\u0442\u0435\u043A\u0441\u0442\u043E\u0432\u044B\u0439 \u043A\u043E\u0434",samp:"\u0412\u044B\u0432\u043E\u0434 \u041F\u041A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B",del:"\u0423\u0434\u0430\u043B\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442 \u0438\u0437 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430",ins:"\u0412\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442 \u0432 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442",var:"\u041E\u0431\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439",ul:"\u041C\u0430\u0440\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A",ol:"\u041D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A",pre:"\u0424\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442",time:"\u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F",img:"\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435",audio:"\u0410\u0443\u0434\u0438\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442",video:"\u0412\u0438\u0434\u0435\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442",blockquote:"\u0411\u043B\u043E\u043A \u0446\u0438\u0442\u0430\u0442\u044B",clearFormat:"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0444\u043E\u0440\u043C\u0430\u0442",toggleViewMode:"\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0432\u0438\u0434 \u0442\u0435\u043A\u0441\u0442/html5",addNewParahraph:"\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u0430\u0440\u0430\u0433\u0440\u0430\u0444",fullScreen:"\u041F\u043E\u043B\u043D\u043E\u044D\u043A\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0435\u0436\u0438\u043C",required:"\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E \u0434\u043B\u044F \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F",minlength:"\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u043D\u0430:",maxlength:"\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u043D\u0430:",filtertags:"\u041D\u0430\u0439\u0434\u0435\u043D \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u0433:"}};
|
462
dist/sass/content.css
vendored
Normal file
462
dist/sass/content.css
vendored
Normal file
@ -0,0 +1,462 @@
|
||||
@charset "UTF-8";
|
||||
:root {
|
||||
--color-orange-50: #FFF8E1;
|
||||
--color-orange-100: #FFF8E1;
|
||||
--color-orange-500: #FF9800;
|
||||
--color-orange-700: #F57C00;
|
||||
--color-green-50: #E8F5E9;
|
||||
--color-green-100: #C8E6C9;
|
||||
--color-green-300: #AED581;
|
||||
--color-green-500: #4CAF50;
|
||||
--color-green-900: #1B5E20;
|
||||
--color-red-50: #FFEBEE;
|
||||
--color-red-100: #FFCDD2;
|
||||
--color-red-200: #FF8A65;
|
||||
--color-red-500: #F44336;
|
||||
--color-red-900: #B71C1C;
|
||||
--color-amber-50: #FFF8E1;
|
||||
--color-amber-100: #FFE0B2;
|
||||
--color-amber-900: #FF6F00;
|
||||
--color-indigo-100: #C5CAE9;
|
||||
--color-deep-orange-50: #FBE9E7;
|
||||
--color-deep-orange-900: #BF360C;
|
||||
--color-lime-50: #F9FBE7;
|
||||
--color-grey-50: #FAFAFA;
|
||||
--color-grey-100: #F5F5F5;
|
||||
--color-grey-200: #EEEEEE;
|
||||
--color-grey-300: #E0E0E0;
|
||||
--color-grey-400: #BDBDBD;
|
||||
--color-grey-500: #9E9E9E;
|
||||
--color-grey-600: #757575;
|
||||
--color-grey-700: #757575;
|
||||
--color-grey-800: #424242;
|
||||
--color-grey-900: #212121;
|
||||
--color-blue-50: #E3F2FD;
|
||||
--color-blue-100: #BBDEFB;
|
||||
--color-blue-200: #90CAF9;
|
||||
--color-blue-500: #2196F3;
|
||||
--color-blue-800: #1565C0;
|
||||
--color-blue-900: #0D47A1;
|
||||
--color-blue-gray-50: #ECEFF1;
|
||||
--color-blue-gray-100: #CFD8DC;
|
||||
--color-blue-gray-200: #B0BEC5;
|
||||
--color-blue-gray-300: #90A4AE;
|
||||
--color-blue-gray-400: #78909C;
|
||||
--color-blue-gray-700: #455A64;
|
||||
--color-blue-gray-800: #37474F;
|
||||
--color-blue-gray-900: #263238;
|
||||
--color-blue-light-50: #E1F5FE;
|
||||
--color-blue-light-100: #B3E5FC; }
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif; }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1.5em; }
|
||||
|
||||
h1 {
|
||||
font-size: 2em; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.8em; }
|
||||
|
||||
h3 {
|
||||
font-size: 1.6em; }
|
||||
|
||||
h4 {
|
||||
font-size: 1.4em; }
|
||||
|
||||
h5 {
|
||||
font-size: 1.2em; }
|
||||
|
||||
h6 {
|
||||
font-size: 1em; }
|
||||
|
||||
/* h1[id]::before,
|
||||
h2[id]::before,
|
||||
h3[id]::before,
|
||||
h4[id]::before,
|
||||
h5[id]::before,
|
||||
h6[id]::before {
|
||||
content: '§';
|
||||
color: var(--color-blue-gray-300);
|
||||
margin-right: 0.5em;
|
||||
} */
|
||||
/* del\ins */
|
||||
del {
|
||||
color: var(--color-red-900);
|
||||
background-color: var(--color-red-50);
|
||||
text-decoration: none; }
|
||||
|
||||
video {
|
||||
max-width: 100%; }
|
||||
|
||||
var {
|
||||
font-weight: bold;
|
||||
font-style: italic; }
|
||||
|
||||
del:before {
|
||||
content: '- ';
|
||||
font-weight: 400; }
|
||||
|
||||
ins {
|
||||
color: var(--color-green-900);
|
||||
background-color: var(--color-green-50);
|
||||
text-decoration: none; }
|
||||
|
||||
ins:before {
|
||||
content: '+ ';
|
||||
font-weight: 400; }
|
||||
|
||||
table > caption {
|
||||
background-color: var(--color-blue-gray-200); }
|
||||
|
||||
th {
|
||||
background-color: var(--color-blue-gray-100); }
|
||||
|
||||
td, th {
|
||||
padding: 3px;
|
||||
border: 1px solid var(--color-blue-gray-400); }
|
||||
|
||||
/* definiton */
|
||||
dfn {
|
||||
color: var(--color-blue-900);
|
||||
position: relative; }
|
||||
|
||||
dfn:after {
|
||||
content: "*";
|
||||
color: var(--color-blue-900); }
|
||||
|
||||
dfn:after {
|
||||
content: "*";
|
||||
color: var(--color-blue-900); }
|
||||
|
||||
dfn::before {
|
||||
transition: all 0.2s ease;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 90vw;
|
||||
min-width: 50px;
|
||||
padding: 3px 6px;
|
||||
background-color: var(--color-blue-50);
|
||||
top: 0;
|
||||
font-size: 0.9em;
|
||||
line-height: 0.9em;
|
||||
left: 50%;
|
||||
transform: translate(0, 0); }
|
||||
|
||||
dfn:hover::before {
|
||||
content: attr(title);
|
||||
transform: translate(-50%, -110%); }
|
||||
|
||||
small {
|
||||
font-size: 0.8em; }
|
||||
|
||||
samp {
|
||||
padding: 0 3px;
|
||||
background-color: var(--color-blue-gray-50);
|
||||
border-radius: 3px;
|
||||
font-family: inherit;
|
||||
border-bottom: 1px solid var(--color-blue-gray-300); }
|
||||
|
||||
samp::before {
|
||||
content: '> ';
|
||||
color: var(--color-blue-gray-300);
|
||||
font-family: sans-serif; }
|
||||
|
||||
a,
|
||||
a.wc-a {
|
||||
color: var(--color-blue-800); }
|
||||
|
||||
a:hover,
|
||||
a.wc-a:hover {
|
||||
color: var(--color-blue-900);
|
||||
border-color: var(--color-blue-900); }
|
||||
|
||||
a.wc-a[target=_blank]::after {
|
||||
user-select: none;
|
||||
content: '↗';
|
||||
display: inline-flex;
|
||||
margin-left: 5px;
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1em;
|
||||
line-height: 16px;
|
||||
font-size: 0.7em;
|
||||
height: 1em;
|
||||
border: 1px solid var(--color-blue-gray-200);
|
||||
transition: all 0.2s ease; }
|
||||
|
||||
a.wc-a[target=_blank]:hover::after {
|
||||
border: 1px solid var(--color-blue-500);
|
||||
background-color: var(--color-blue-500);
|
||||
color: #fff; }
|
||||
|
||||
blockquote {
|
||||
margin: 10px 0 10px 0;
|
||||
background-color: var(--color-amber-50);
|
||||
color: #412207;
|
||||
padding: 10px 10px 10px 20px;
|
||||
border-left: 2px solid #F57F17;
|
||||
border-radius: 3px;
|
||||
position: relative; }
|
||||
|
||||
blockquote::before {
|
||||
content: '❝';
|
||||
font-size: 1em;
|
||||
color: #F57F17;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 10px;
|
||||
user-select: none; }
|
||||
|
||||
p {
|
||||
margin-bottom: 1em; }
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
q {
|
||||
background-color: #FFF8E1;
|
||||
display: inline;
|
||||
font-style: italic;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px; }
|
||||
|
||||
q:before {
|
||||
content: open-quote; }
|
||||
|
||||
q:after {
|
||||
content: close-quote; }
|
||||
|
||||
mark {
|
||||
background-color: var(--color-lime-50);
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.2em;
|
||||
display: inline-block; }
|
||||
|
||||
strong {
|
||||
background-color: var(--color-deep-orange-50);
|
||||
color: var(--color-deep-orange-900);
|
||||
font-weight: 400;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.2em;
|
||||
display: inline-block; }
|
||||
|
||||
span.inline-code {
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-800);
|
||||
padding: 15px 10px 10px 10px;
|
||||
border-radius: 6px; }
|
||||
|
||||
kbd {
|
||||
background-color: #eee;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #b4b4b4;
|
||||
border-bottom: 3px solid #b4b4b4;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-family: inherit;
|
||||
font-size: 0.85em;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
padding: 2px 4px;
|
||||
white-space: nowrap; }
|
||||
|
||||
/* spoiler section */
|
||||
details {
|
||||
border: 1px dashed var(--color-blue-gray-200);
|
||||
border-radius: 5px;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
details > summary {
|
||||
text-decoration: dotted;
|
||||
color: var(--color-blue-grey-900);
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer; }
|
||||
|
||||
details > p {
|
||||
padding: 0 10px 10px 10px; }
|
||||
|
||||
/* abbr section */
|
||||
abbr {
|
||||
color: #1A237E;
|
||||
position: relative;
|
||||
cursor: help;
|
||||
transition: all 0.2s ease; }
|
||||
|
||||
abbr:hover {
|
||||
background-color: #E3F2FD; }
|
||||
|
||||
abbr::after {
|
||||
transition: all 0.2s ease;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 33vw;
|
||||
min-width: 50px;
|
||||
padding: 3px 6px;
|
||||
background-color: #BBDEFB;
|
||||
top: 0;
|
||||
font-size: 0.9em;
|
||||
line-height: 0.9em;
|
||||
left: 50%;
|
||||
transform: translate(0, 0); }
|
||||
|
||||
abbr:hover::after {
|
||||
content: attr(title);
|
||||
transform: translate(-50%, -110%); }
|
||||
|
||||
/* code block style */
|
||||
pre, .hljs {
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-900);
|
||||
padding: 15px 10px 10px 10px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 5px;
|
||||
position: relative; }
|
||||
|
||||
pre[data-lang]:before {
|
||||
content: attr(data-lang);
|
||||
display: inline-block;
|
||||
background-color: var(--color-blue-gray-100);
|
||||
color: var(--color-blue-grey-900);
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0 5px;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.7em;
|
||||
line-height: 16px; }
|
||||
|
||||
/* inlinde-code */
|
||||
code {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2em;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-900);
|
||||
border-radius: 3px; }
|
||||
|
||||
/* ul\li section */
|
||||
ul, ol {
|
||||
margin-left: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-inline-start: 0; }
|
||||
|
||||
ol li {
|
||||
list-style: decimal;
|
||||
margin-left: 1em; }
|
||||
|
||||
ul li {
|
||||
list-style-type: square;
|
||||
margin-left: 1em; }
|
||||
|
||||
li[data-listStyle] {
|
||||
list-style: none;
|
||||
list-style-type: none;
|
||||
position: relative; }
|
||||
|
||||
li[data-listStyle]:before {
|
||||
content: attr(data-liststyle);
|
||||
position: absolute;
|
||||
margin-left: -20px; }
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
border-radius: 3px; }
|
||||
|
||||
figure {
|
||||
border-radius: 4px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border: 1px solid var(--color-blue-gray-200); }
|
||||
|
||||
figure > figcaption {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em; }
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
outline: none;
|
||||
border: 1px dashed var(--color-blue-gray-200);
|
||||
margin: 1em 0; }
|
||||
|
||||
button, .btn {
|
||||
background: var(--color-blue-gray-50);
|
||||
outline: none;
|
||||
padding: 3px 6px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-grey-200);
|
||||
border-bottom: 3px solid var(--color-blue-grey-200);
|
||||
color: #333;
|
||||
min-width: 0px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85em;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
cursor: pointer; }
|
||||
button:hover, .btn:hover {
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-300); }
|
||||
button:focus, .btn:focus {
|
||||
border-color: var(--color-blue-500); }
|
||||
button:active, .btn:active {
|
||||
padding-top: 2px;
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-700);
|
||||
border-bottom: 1px solid; }
|
||||
button:disabled, .btn:disabled {
|
||||
pointer-events: none;
|
||||
color: var(--color-blue-gray-400);
|
||||
border: 1px solid var(--color-blue-gray-300);
|
||||
background-color: var(--color-blue-gray-200); }
|
||||
button > a, .btn > a {
|
||||
text-decoration: none; }
|
||||
button.-green, .btn.-green {
|
||||
border-color: var(--color-green-500); }
|
||||
button.-blue, .btn.-blue {
|
||||
background-color: var(--color-blue-500);
|
||||
color: #fff;
|
||||
border-color: var(--color-blue-800); }
|
||||
button.-blue:active, .btn.-blue:active {
|
||||
background-color: var(--color-blue-600);
|
||||
border-color: var(--color-blue-900); }
|
||||
|
||||
.-text-center {
|
||||
text-align: center; }
|
||||
|
||||
.-text-right {
|
||||
text-align: right; }
|
||||
|
||||
.-text-left {
|
||||
text-align: left; }
|
203
dist/sass/wc-wysiwyg.css
vendored
Normal file
203
dist/sass/wc-wysiwyg.css
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
.wc-wysiwyg {
|
||||
background-color: #eee;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
position: relative;
|
||||
border: 1px solid var(--color-blue-gray-400);
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
/* custom elements */
|
||||
/* preview */
|
||||
/* inline dialog */
|
||||
/* props form */
|
||||
/* hints */ }
|
||||
.wc-wysiwyg_bt {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
background-color: var(--color-blue-gray-100); }
|
||||
.wc-wysiwyg_bt .-errors {
|
||||
background-color: var(--color-red-500);
|
||||
color: var(--color-red-50);
|
||||
padding: 3px;
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
border-radius: 3px; }
|
||||
.wc-wysiwyg_ce {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 7px;
|
||||
border: 1px solid var(--color-blue-500);
|
||||
border-radius: 3px;
|
||||
background-color: var(--color-blue-50); }
|
||||
.wc-wysiwyg_ce:before {
|
||||
content: 'HTML5 custom-elements';
|
||||
color: #fff;
|
||||
background-color: var(--color-blue-500);
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
line-height: 0.6em;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
transform: translate(0, -50%);
|
||||
top: 0;
|
||||
left: 0; }
|
||||
.wc-wysiwyg_ce > button {
|
||||
border-color: var(--color-blue-500);
|
||||
background-color: var(--color-blue-100); }
|
||||
.wc-wysiwyg_ce > button:hover {
|
||||
border-color: var(--color-blue-900);
|
||||
background-color: var(--color-blue-200); }
|
||||
.wc-wysiwyg_pr {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
min-height: 200px; }
|
||||
.wc-wysiwyg_content {
|
||||
padding: 5px 5px 2em 5px;
|
||||
border: 1px solid #ccc;
|
||||
background: #fff;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
max-width: 960px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
resize: vertical; }
|
||||
.wc-wysiwyg_content .-selected {
|
||||
background-color: var(--color-blue-100); }
|
||||
.wc-wysiwyg_content:focus, .wc-wysiwyg_content:active {
|
||||
outline: 5px solid var(--color-green-300);
|
||||
border: none; }
|
||||
.wc-wysiwyg_content.-invalid:focus {
|
||||
outline: 5px solid var(--color-red-500); }
|
||||
.wc-wysiwyg_ec {
|
||||
background: var(--color-blue-gray-100);
|
||||
padding: 0.5em 0.25em 0.25em 0.25em;
|
||||
border-radius: 3px;
|
||||
border: 1px solid;
|
||||
border-color: var(--color-blue-gray-100); }
|
||||
.wc-wysiwyg_ec:focus-within {
|
||||
border-color: var(--color-blue-500); }
|
||||
.wc-wysiwyg_btn {
|
||||
background: var(--color-blue-gray-50);
|
||||
outline: none;
|
||||
padding: 3px 6px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-gray-200);
|
||||
border-bottom: 3px solid var(--color-blue-gray-200);
|
||||
color: #333;
|
||||
min-width: 0px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85em;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
cursor: pointer; }
|
||||
.wc-wysiwyg_btn:hover {
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-300); }
|
||||
.wc-wysiwyg_btn:focus {
|
||||
border-color: var(--color-blue-500); }
|
||||
.wc-wysiwyg_btn:active {
|
||||
padding-top: 2px;
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-700);
|
||||
border-bottom: 1px solid; }
|
||||
.wc-wysiwyg_btn.-clear {
|
||||
text-decoration: line-through;
|
||||
font-weight: bold; }
|
||||
.wc-wysiwyg_ia {
|
||||
display: flex;
|
||||
flex-wrap: wrap; }
|
||||
.wc-wysiwyg_ia > input {
|
||||
box-sizing: border-box;
|
||||
min-width: 100%;
|
||||
position: relative; }
|
||||
.wc-wysiwyg_di {
|
||||
z-index: 99901;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: var(--color-blue-gray-50);
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-gray-300);
|
||||
box-sizing: border-box; }
|
||||
.wc-wysiwyg_di > form:nth-child(1n+2) {
|
||||
margin-top: 10px; }
|
||||
.wc-wysiwyg_pf {
|
||||
display: flex;
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
background-color: var(--color-blue-100);
|
||||
flex-wrap: nowrap;
|
||||
font-size: 0.9em;
|
||||
align-items: center; }
|
||||
.wc-wysiwyg_pf:before {
|
||||
padding: 0 0 0 5px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
content: "<" attr(data-tag) " ";
|
||||
text-transform: lowercase;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
font-weight: bold;
|
||||
margin-right: 5px; }
|
||||
.wc-wysiwyg_pf > label {
|
||||
background-color: var(--color-blue-200);
|
||||
color: var(--color-blue-gray-800);
|
||||
padding: 3px 3px 3px 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
margin-right: 5px;
|
||||
height: 25px;
|
||||
line-height: 25px; }
|
||||
.wc-wysiwyg_pf input.wc_ed_inp {
|
||||
background: #fff;
|
||||
padding: 0 5px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
border: none; }
|
||||
.wc-wysiwyg_pf input.wc_ed_inp:focus {
|
||||
border: none;
|
||||
outline: 2px solid var(--color-green-500); }
|
||||
.wc-wysiwyg_pf > button {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
border-radius: 6px; }
|
||||
.wc-wysiwyg *[data-hint] {
|
||||
position: relative; }
|
||||
.wc-wysiwyg *[data-hint]:hover:after {
|
||||
visibility: visible;
|
||||
z-index: 9900;
|
||||
transform: translate(-50%, -100%); }
|
||||
.wc-wysiwyg *[data-hint]:after {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
transition: transform .2s ease;
|
||||
left: 50%;
|
||||
top: -3px;
|
||||
transform: translate(-50%, 0%);
|
||||
background-color: var(--color-blue-gray-700);
|
||||
color: #fff;
|
||||
content: attr(data-hint);
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
font-size: 10px;
|
||||
line-height: 10px; }
|
||||
.wc-wysiwyg .-display-none {
|
||||
display: none; }
|
1
dist/wc-wysiwyg.js
vendored
Normal file
1
dist/wc-wysiwyg.js
vendored
Normal file
File diff suppressed because one or more lines are too long
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "wc-wysiwyg",
|
||||
"version": "0.9.0",
|
||||
"description": "WYWSIWYG HTML5 Editor written in ts and designed by web-componennt, support all JS frameworks and browsers",
|
||||
"main": "src/wc-wysiwyg.ts",
|
||||
"scripts": {
|
||||
"sass": "./node_modules/node-sass/bin/node-sass ./src -o ./dist",
|
||||
"tsc": "./node_modules/.bin/tsc",
|
||||
"babel-minify": " ./node_modules/.bin/minify ./dist --mangle=false --out-dir ./dist --sourceType=module",
|
||||
"build": "npm run sass && npm run tsc && npm run babel-minify"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/webislife/wc-wysiwyg.git"
|
||||
},
|
||||
"keywords": [
|
||||
"web-component",
|
||||
"custom-element",
|
||||
"time",
|
||||
"html5",
|
||||
"esnext",
|
||||
"typescript"
|
||||
],
|
||||
"author": "srokoff",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/webislife/wc-wysiwyg/issues"
|
||||
},
|
||||
"homepage": "https://github.com/webislife/wc-wysiwyg#readme",
|
||||
"devDependencies": {
|
||||
"babel-minify": "^0.5.2",
|
||||
"node-sass": "^8.0.0",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"@webislife:registry": "https://npm.pkg.github.com"
|
||||
}
|
||||
}
|
||||
|
61
src/core/el.ts
Normal file
61
src/core/el.ts
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Short
|
||||
* @param tagName element tag name
|
||||
* @param params list of object params for document.createElements
|
||||
* @returns
|
||||
*/
|
||||
export const el = (tagName:keyof HTMLElementTagNameMap|string, {classList, styles, props, attrs, options, append}:{
|
||||
classList?: string[],
|
||||
styles?: object,
|
||||
props?: object,
|
||||
attrs?: object,
|
||||
options?: {
|
||||
is?:string
|
||||
},
|
||||
append?: Element[]
|
||||
} = {}):any => {
|
||||
if(!tagName) {
|
||||
throw new Error(`Undefined tag ${tagName}`);
|
||||
}
|
||||
const element = document.createElement(tagName, options);
|
||||
// element.classList
|
||||
if(classList) {
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
const styleClass = classList[i];
|
||||
element.classList.add(styleClass)
|
||||
}
|
||||
}
|
||||
// element.style[prop]
|
||||
if(styles) {
|
||||
const stylesKeys = Object.keys(styles);
|
||||
for (let i = 0; i < stylesKeys.length; i++) {
|
||||
const key = stylesKeys[i];
|
||||
element.style[key] = styles[key];
|
||||
}
|
||||
}
|
||||
// element[prop]
|
||||
if(props) {
|
||||
const propKeys = Object.keys(props);
|
||||
for (let i = 0; i < propKeys.length; i++) {
|
||||
const key = propKeys[i];
|
||||
element[key] = props[key];
|
||||
}
|
||||
}
|
||||
// element.setAttribute(key,val)
|
||||
if(attrs) {
|
||||
const attrsKeys = Object.keys(attrs);
|
||||
for (let i = 0; i < attrsKeys.length; i++) {
|
||||
const key = attrsKeys[i];
|
||||
if(attrs[key]) {
|
||||
element.setAttribute(key, attrs[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(append) {
|
||||
for (let i = 0; i < append.length; i++) {
|
||||
const appendEl = append[i];
|
||||
element.append(appendEl);
|
||||
}
|
||||
}
|
||||
return element;
|
||||
};
|
91
src/core/translates.ts
Normal file
91
src/core/translates.ts
Normal file
@ -0,0 +1,91 @@
|
||||
//Translates
|
||||
export const t = {
|
||||
en: {
|
||||
h1:'Header 1 level',
|
||||
h2:'Header 2 level',
|
||||
h3:'Header 3 level',
|
||||
h4:'Header 4 level',
|
||||
h5:'Header 5 level',
|
||||
h6:'Header 6 level',
|
||||
span:'String',
|
||||
mark:'Marked text',
|
||||
small:'Small text',
|
||||
dfn:'Definition',
|
||||
a:'Link',
|
||||
q:'Inline quote',
|
||||
b:'Bold',
|
||||
i:'Italic',
|
||||
u:'Underlined',
|
||||
s:'Small',
|
||||
sup:'Superscript',
|
||||
sub:'Subscript',
|
||||
kbd:'Button',
|
||||
abbr:'Abbrevature',
|
||||
strong:'Important text',
|
||||
code:'Inline code',
|
||||
samp:'PC program output',
|
||||
del:'Deleted text from document',
|
||||
ins:'Insert text into document',
|
||||
var:'Variable designation',
|
||||
ul:'The bulleted list',
|
||||
ol:'Numbered list',
|
||||
pre:'Formatted text',
|
||||
time:'Date and time',
|
||||
img:'Image',
|
||||
audio:'Audio element',
|
||||
video:'Video element',
|
||||
blockquote:'Blockquote',
|
||||
clearFormat: 'Clear text format',
|
||||
toggleViewMode: 'Toggle view Text/HTML5',
|
||||
addNewParahraph: 'Add new parahraph',
|
||||
fullScreen: 'fullScreen',
|
||||
required: 'Field required',
|
||||
minlength: 'Min length is:',
|
||||
maxlength: 'Max length is:',
|
||||
filtertags: 'Found filter tag:',
|
||||
},
|
||||
ru: {
|
||||
h1:'Заголовок 1 уровня',
|
||||
h2:'Заголовок 2 уровня',
|
||||
h3:'Заголовок 3 уровня',
|
||||
h4:'Заголовок 4 уровня',
|
||||
h5:'Заголовок 5 уровня',
|
||||
h6:'Заголовок 6 уровня',
|
||||
span:'Строка',
|
||||
mark:'Помеченный текст',
|
||||
small:'Маленький текст',
|
||||
dfn:'Определение',
|
||||
a:'Ссылка',
|
||||
q:'Внутритекстовая цитата',
|
||||
b:'Жирный',
|
||||
i:'Курсив',
|
||||
u:'Подчеркнутый',
|
||||
s:'Маленький',
|
||||
sup:'Надстрочный',
|
||||
sub:'Подстрочный',
|
||||
kbd:'Кнопка',
|
||||
abbr:'Аббривеатура',
|
||||
strong:'Важный текст',
|
||||
code:'Внутритекстовый код',
|
||||
samp:'Вывод ПК программы',
|
||||
del:'Удаленный текст из документа',
|
||||
ins:'Вставленный текст в документ',
|
||||
var:'Обозначение переменной',
|
||||
ul:'Маркированный список',
|
||||
ol:'Нумерованный список',
|
||||
pre:'Форматированный текст',
|
||||
time:'Дата и время',
|
||||
img:'Изображение',
|
||||
audio:'Аудио элемент',
|
||||
video:'Видео элемент',
|
||||
blockquote:'Блок цитаты',
|
||||
clearFormat: 'Очистить формат',
|
||||
toggleViewMode: 'Переключить вид текст/html5',
|
||||
addNewParahraph: 'Добавить параграф',
|
||||
fullScreen: 'Полноэкранный режим',
|
||||
required: 'Обязательно для заполнения',
|
||||
minlength: 'Минимальная длинна:',
|
||||
maxlength: 'Максимальная длинна:',
|
||||
filtertags: 'Найден запрещенный тег:',
|
||||
}
|
||||
};
|
490
src/sass/content.scss
Normal file
490
src/sass/content.scss
Normal file
@ -0,0 +1,490 @@
|
||||
:root {
|
||||
// orange
|
||||
--color-orange-50: #FFF8E1;
|
||||
--color-orange-100: #FFF8E1;
|
||||
--color-orange-500: #FF9800;
|
||||
--color-orange-700: #F57C00;
|
||||
|
||||
--color-green-50: #E8F5E9;
|
||||
--color-green-100: #C8E6C9;
|
||||
--color-green-300: #AED581;
|
||||
--color-green-500: #4CAF50;
|
||||
--color-green-900: #1B5E20;
|
||||
|
||||
--color-red-50: #FFEBEE;
|
||||
--color-red-100: #FFCDD2;
|
||||
--color-red-200: #FF8A65;
|
||||
--color-red-500: #F44336;
|
||||
--color-red-900: #B71C1C;
|
||||
|
||||
--color-amber-50: #FFF8E1;
|
||||
--color-amber-100: #FFE0B2;
|
||||
--color-amber-900: #FF6F00;
|
||||
|
||||
--color-indigo-100: #C5CAE9;
|
||||
|
||||
// orange
|
||||
--color-deep-orange-50: #FBE9E7;
|
||||
--color-deep-orange-900: #BF360C;
|
||||
|
||||
// lime
|
||||
--color-lime-50: #F9FBE7;
|
||||
|
||||
// grey
|
||||
--color-grey-50: #FAFAFA;
|
||||
--color-grey-100: #F5F5F5;
|
||||
--color-grey-200: #EEEEEE;
|
||||
--color-grey-300: #E0E0E0;
|
||||
--color-grey-400: #BDBDBD;
|
||||
--color-grey-500: #9E9E9E;
|
||||
--color-grey-600: #757575;
|
||||
--color-grey-700: #757575;
|
||||
--color-grey-800: #424242;
|
||||
--color-grey-900: #212121;
|
||||
|
||||
// blue
|
||||
--color-blue-50: #E3F2FD;
|
||||
--color-blue-100: #BBDEFB;
|
||||
--color-blue-200: #90CAF9;
|
||||
--color-blue-500: #2196F3;
|
||||
--color-blue-800: #1565C0;
|
||||
--color-blue-900: #0D47A1;
|
||||
|
||||
// blue-gray
|
||||
--color-blue-gray-50: #ECEFF1;
|
||||
--color-blue-gray-100: #CFD8DC;
|
||||
--color-blue-gray-200: #B0BEC5;
|
||||
--color-blue-gray-300: #90A4AE;
|
||||
--color-blue-gray-400: #78909C;
|
||||
--color-blue-gray-700: #455A64;
|
||||
--color-blue-gray-800: #37474F;
|
||||
--color-blue-gray-900: #263238;
|
||||
// blue-light
|
||||
--color-blue-light-50: #E1F5FE;
|
||||
--color-blue-light-100: #B3E5FC;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
/* h1[id]::before,
|
||||
h2[id]::before,
|
||||
h3[id]::before,
|
||||
h4[id]::before,
|
||||
h5[id]::before,
|
||||
h6[id]::before {
|
||||
content: '§';
|
||||
color: var(--color-blue-gray-300);
|
||||
margin-right: 0.5em;
|
||||
} */
|
||||
/* del\ins */
|
||||
del {
|
||||
color: var(--color-red-900);
|
||||
background-color: var(--color-red-50);
|
||||
text-decoration: none;
|
||||
}
|
||||
video {
|
||||
max-width: 100%;
|
||||
}
|
||||
var {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
del:before {
|
||||
content: '- ';
|
||||
font-weight: 400;
|
||||
}
|
||||
ins {
|
||||
color: var(--color-green-900);
|
||||
background-color: var(--color-green-50);
|
||||
text-decoration: none;
|
||||
}
|
||||
ins:before {
|
||||
content: '+ ';
|
||||
font-weight: 400;
|
||||
}
|
||||
table > caption {
|
||||
background-color: var(--color-blue-gray-200);
|
||||
}
|
||||
th {
|
||||
background-color: var(--color-blue-gray-100);
|
||||
}
|
||||
td,th {
|
||||
padding: 3px;
|
||||
border: 1px solid var(--color-blue-gray-400);
|
||||
}
|
||||
/* definiton */
|
||||
dfn {
|
||||
color: var(--color-blue-900);
|
||||
position: relative;
|
||||
}
|
||||
dfn:after {
|
||||
content: "*";
|
||||
color: var(--color-blue-900);
|
||||
}
|
||||
|
||||
dfn:after {
|
||||
content: "*";
|
||||
color: var(--color-blue-900);
|
||||
}
|
||||
dfn::before {
|
||||
transition: all 0.2s ease;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 90vw;
|
||||
min-width: 50px;
|
||||
padding: 3px 6px;
|
||||
background-color: var(--color-blue-50);
|
||||
top:0;
|
||||
font-size: 0.9em;
|
||||
line-height: 0.9em;
|
||||
left: 50%;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
dfn:hover::before {
|
||||
content: attr(title);
|
||||
transform: translate(-50%, -110%);
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
samp {
|
||||
padding: 0 3px;
|
||||
background-color: var(--color-blue-gray-50);
|
||||
border-radius: 3px;
|
||||
font-family: inherit;
|
||||
border-bottom: 1px solid var(--color-blue-gray-300);
|
||||
}
|
||||
samp::before {
|
||||
content: '> ';
|
||||
color: var(--color-blue-gray-300);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
a,
|
||||
a.wc-a {
|
||||
color: var(--color-blue-800);
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a.wc-a:hover {
|
||||
color: var(--color-blue-900);
|
||||
border-color: var(--color-blue-900);
|
||||
}
|
||||
a.wc-a[target=_blank]::after {
|
||||
user-select: none;
|
||||
content: '↗';
|
||||
display: inline-flex;
|
||||
margin-left:5px;
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1em;
|
||||
line-height: 16px;
|
||||
font-size: 0.7em;
|
||||
height: 1em;
|
||||
border: 1px solid var(--color-blue-gray-200);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
a.wc-a[target=_blank]:hover::after {
|
||||
border: 1px solid var(--color-blue-500);
|
||||
background-color: var(--color-blue-500);
|
||||
color: #fff;
|
||||
}
|
||||
blockquote {
|
||||
margin: 10px 0 10px 0;
|
||||
background-color: var(--color-amber-50);
|
||||
color: #412207;
|
||||
padding: 10px 10px 10px 20px;
|
||||
border-left: 2px solid #F57F17;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
}
|
||||
blockquote::before {
|
||||
content: '❝';
|
||||
font-size: 1em;
|
||||
color:#F57F17;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 10px;
|
||||
user-select: none;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
q {
|
||||
background-color: #FFF8E1;
|
||||
display: inline;
|
||||
font-style: italic;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
q:before {
|
||||
content: open-quote;
|
||||
}
|
||||
q:after {
|
||||
content: close-quote;
|
||||
}
|
||||
mark {
|
||||
background-color: var(--color-lime-50);
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.2em;
|
||||
display: inline-block;
|
||||
}
|
||||
strong {
|
||||
background-color: var(--color-deep-orange-50);
|
||||
color: var(--color-deep-orange-900);
|
||||
font-weight: 400;
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
line-height: 1.2em;
|
||||
display: inline-block;
|
||||
}
|
||||
span.inline-code {
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-800);
|
||||
padding: 15px 10px 10px 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
kbd {
|
||||
background-color: #eee;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #b4b4b4;
|
||||
border-bottom: 3px solid #b4b4b4;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-family: inherit;
|
||||
font-size: 0.85em;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
padding: 2px 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* spoiler section */
|
||||
details {
|
||||
border:1px dashed var(--color-blue-gray-200);
|
||||
border-radius: 5px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
details > summary {
|
||||
text-decoration: dotted;
|
||||
color: var(--color-blue-grey-900);
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
details > p {
|
||||
padding: 0 10px 10px 10px;
|
||||
}
|
||||
/* abbr section */
|
||||
abbr {
|
||||
color: #1A237E;
|
||||
position: relative;
|
||||
cursor: help;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
}
|
||||
abbr:hover {
|
||||
background-color: #E3F2FD;
|
||||
}
|
||||
abbr::after {
|
||||
transition: all 0.2s ease;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 33vw;
|
||||
min-width: 50px;
|
||||
padding: 3px 6px;
|
||||
background-color: #BBDEFB;
|
||||
top:0;
|
||||
font-size: 0.9em;
|
||||
line-height: 0.9em;
|
||||
left: 50%;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
abbr:hover::after {
|
||||
content: attr(title);
|
||||
transform: translate(-50%, -110%);
|
||||
}
|
||||
/* code block style */
|
||||
pre, .hljs {
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-900);
|
||||
padding: 15px 10px 10px 10px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
}
|
||||
pre[data-lang]:before {
|
||||
content: attr(data-lang);
|
||||
display: inline-block;
|
||||
background-color: var(--color-blue-gray-100);
|
||||
color: var(--color-blue-grey-900);
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0 5px;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.7em;
|
||||
line-height: 16px;
|
||||
}
|
||||
/* inlinde-code */
|
||||
code {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
line-height: 1.2em;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--color-blue-gray-50);
|
||||
color: var(--color-blue-grey-900);
|
||||
border-radius: 3px;
|
||||
}
|
||||
/* ul\li section */
|
||||
ul,ol {
|
||||
margin-left: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
ol {
|
||||
li { list-style: decimal; margin-left: 1em;}
|
||||
}
|
||||
ul {
|
||||
li { list-style-type: square;margin-left: 1em;}
|
||||
}
|
||||
li[data-listStyle] {
|
||||
list-style: none;
|
||||
list-style-type: none;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
li[data-listStyle]:before {
|
||||
content: attr(data-liststyle);
|
||||
position: absolute;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
/* Images */
|
||||
img {
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
}
|
||||
figure {
|
||||
border-radius: 4px;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border:1px solid var(--color-blue-gray-200);
|
||||
}
|
||||
figure > figcaption {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
hr {
|
||||
display: block;
|
||||
outline: none;
|
||||
border: 1px dashed var(--color-blue-gray-200);
|
||||
margin: 1em 0;
|
||||
}
|
||||
button, .btn {
|
||||
background: var(--color-blue-gray-50);
|
||||
outline: none;
|
||||
padding: 3px 6px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-grey-200);
|
||||
border-bottom: 3px solid var(--color-blue-grey-200);
|
||||
color: #333;
|
||||
min-width: 0px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85em;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-300);
|
||||
}
|
||||
&:focus {
|
||||
border-color: var(--color-blue-500);
|
||||
}
|
||||
&:active {
|
||||
padding-top:2px;
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-700);
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
&:disabled {
|
||||
pointer-events:none;
|
||||
color: var(--color-blue-gray-400);
|
||||
border: 1px solid var(--color-blue-gray-300);
|
||||
background-color: var(--color-blue-gray-200);
|
||||
}
|
||||
& > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
&.-green {
|
||||
border-color: var(--color-green-500)
|
||||
}
|
||||
&.-blue {
|
||||
background-color: var(--color-blue-500);
|
||||
color:#fff;
|
||||
border-color: var(--color-blue-800);
|
||||
&:active {
|
||||
background-color: var(--color-blue-600);
|
||||
border-color: var(--color-blue-900);
|
||||
}
|
||||
}
|
||||
}
|
||||
.-text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.-text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.-text-left {
|
||||
text-align: left;
|
||||
}
|
242
src/sass/wc-wysiwyg.scss
Normal file
242
src/sass/wc-wysiwyg.scss
Normal file
@ -0,0 +1,242 @@
|
||||
|
||||
.wc-wysiwyg {
|
||||
background-color: #eee;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
position: relative;
|
||||
border: 1px solid var(--color-blue-gray-400);
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
&_bt {
|
||||
display: block;
|
||||
padding:5px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
background-color: var(--color-blue-gray-100);
|
||||
& .-errors {
|
||||
background-color: var(--color-red-500);
|
||||
color: var(--color-red-50);
|
||||
padding: 3px;
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
/* custom elements */
|
||||
|
||||
&_ce {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 7px;
|
||||
border: 1px solid var(--color-blue-500);
|
||||
border-radius: 3px;
|
||||
background-color: var(--color-blue-50);
|
||||
}
|
||||
&_ce:before {
|
||||
content: 'HTML5 custom-elements';
|
||||
color: #fff;
|
||||
background-color: var(--color-blue-500);
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
line-height: 0.6em;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
transform: translate(0, -50%);
|
||||
top:0;
|
||||
left:0;
|
||||
}
|
||||
&_ce > button {
|
||||
border-color: var(--color-blue-500);
|
||||
background-color: var(--color-blue-100);
|
||||
&:hover {
|
||||
border-color: var(--color-blue-900);
|
||||
background-color: var(--color-blue-200);
|
||||
}
|
||||
}
|
||||
/* preview */
|
||||
&_pr {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
min-height: 200px;
|
||||
}
|
||||
&_content {
|
||||
padding:5px 5px 2em 5px;
|
||||
border:1px solid #ccc;
|
||||
background: #fff;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
max-width: 960px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
resize: vertical;
|
||||
& .-selected {
|
||||
background-color: var(--color-blue-100);
|
||||
}
|
||||
&:focus, &:active {
|
||||
outline: 5px solid var(--color-green-300);
|
||||
border: none;
|
||||
}
|
||||
&.-invalid:focus {
|
||||
outline: 5px solid var(--color-red-500);
|
||||
}
|
||||
}
|
||||
&_ec {
|
||||
background: var(--color-blue-gray-100);
|
||||
padding: 0.5em 0.25em 0.25em 0.25em;
|
||||
border-radius: 3px;
|
||||
border: 1px solid;
|
||||
border-color: var(--color-blue-gray-100);
|
||||
}
|
||||
&_ec:focus-within {
|
||||
border-color: var(--color-blue-500);
|
||||
}
|
||||
&_btn {
|
||||
background: var(--color-blue-gray-50);
|
||||
outline: none;
|
||||
padding: 3px 6px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-gray-200);
|
||||
border-bottom: 3px solid var(--color-blue-gray-200);
|
||||
color: #333;
|
||||
min-width: 0px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85em;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-300);
|
||||
}
|
||||
&:focus {
|
||||
border-color: var(--color-blue-500);
|
||||
}
|
||||
&:active {
|
||||
padding-top:2px;
|
||||
background: var(--color-blue-gray-100);
|
||||
border-color: var(--color-blue-gray-700);
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
&.-clear {
|
||||
text-decoration: line-through;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
&_ia {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
&_ia > input {
|
||||
box-sizing: border-box;
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
/* inline dialog */
|
||||
&_di {
|
||||
z-index: 99901;
|
||||
position: fixed;
|
||||
bottom:0;
|
||||
width: 100%;
|
||||
background: var(--color-blue-gray-50);
|
||||
padding:3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--color-blue-gray-300);
|
||||
box-sizing: border-box;
|
||||
& > form {
|
||||
&:nth-child(1n+2) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* props form */
|
||||
&_pf {
|
||||
display: flex;
|
||||
border-radius: 3px;
|
||||
padding: 3px;
|
||||
background-color: var(--color-blue-100);
|
||||
flex-wrap: nowrap;
|
||||
font-size: 0.9em;
|
||||
align-items: center;
|
||||
&:before {
|
||||
padding: 0 0 0 5px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
content: '<' attr(data-tag) ' ';
|
||||
text-transform: lowercase;
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
font-weight: bold;
|
||||
margin-right: 5px;
|
||||
|
||||
}
|
||||
& > label {
|
||||
background-color: var(--color-blue-200);
|
||||
color: var(--color-blue-gray-800);
|
||||
padding: 3px 3px 3px 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
margin-right: 5px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
}
|
||||
& input.wc_ed_inp {
|
||||
background: #fff;
|
||||
padding: 0 5px;
|
||||
height: 25px;
|
||||
display: inline-block;
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
&:focus {
|
||||
border: none;
|
||||
outline: 2px solid var(--color-green-500);
|
||||
}
|
||||
}
|
||||
& > button {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
/* hints */
|
||||
& *[data-hint] {
|
||||
position: relative;
|
||||
}
|
||||
& *[data-hint]:hover:after {
|
||||
visibility: visible;
|
||||
z-index: 9900;
|
||||
transform: translate(-50%, -100%);
|
||||
}
|
||||
& *[data-hint]:after {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
transition: transform .2s ease;
|
||||
left: 50%;
|
||||
top: -3px;
|
||||
transform: translate(-50%, 0%);
|
||||
background-color: var(--color-blue-gray-700);
|
||||
color: #fff;
|
||||
content: attr(data-hint);
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
}
|
||||
& .-display-none {
|
||||
display: none;
|
||||
}
|
||||
}
|
731
src/wc-wysiwyg.ts
Normal file
731
src/wc-wysiwyg.ts
Normal file
@ -0,0 +1,731 @@
|
||||
import {t} from './core/translates.js';
|
||||
import { el } from "./core/el.js";
|
||||
|
||||
interface WCWYSIWYGTag {
|
||||
tag:string
|
||||
method?:Function,
|
||||
hint?:string,
|
||||
is?: string,
|
||||
}
|
||||
interface WCWYSIWYGActions {
|
||||
wrapTag: Function,
|
||||
insertImageBlock: Function,
|
||||
insertAudio: Function,
|
||||
insertVideo: Function,
|
||||
}
|
||||
|
||||
//All semantic html5 known editor tags
|
||||
const allTags = [
|
||||
{ tag: 'h1' },
|
||||
{ tag: 'h2' },
|
||||
{ tag: 'h3' },
|
||||
{ tag: 'h4' },
|
||||
{ tag: 'h5' },
|
||||
{ tag: 'h6' },
|
||||
{ tag: 'span' },
|
||||
{ tag: 'mark' },
|
||||
{ tag: 'small' },
|
||||
{ tag: 'dfn' },
|
||||
{ tag: 'a'},
|
||||
{ tag: 'q'},
|
||||
{ tag: 'b'},
|
||||
{ tag: 'i'},
|
||||
{ tag: 'u'},
|
||||
{ tag: 's'},
|
||||
{ tag: 'sup'},
|
||||
{ tag: 'sub'},
|
||||
{ tag: 'kbd'},
|
||||
{ tag: 'abbr'},
|
||||
{ tag: 'strong'},
|
||||
{ tag: 'code'},
|
||||
{ tag: 'samp'},
|
||||
{ tag: 'del'},
|
||||
{ tag: 'ins'},
|
||||
{ tag: 'var'},
|
||||
{ tag: 'ul'},
|
||||
{ tag: 'ol'},
|
||||
{ tag: 'pre'},
|
||||
{ tag: 'time'},
|
||||
{ tag: 'img'},
|
||||
{ tag: 'audio'},
|
||||
{ tag: 'video'},
|
||||
{ tag: 'blockquote'},
|
||||
] as WCWYSIWYGTag[];
|
||||
|
||||
class WCWYSIWYG extends HTMLElement {
|
||||
public EditorTags:WCWYSIWYGTag[]
|
||||
public EditorCustomTags:WCWYSIWYGTag[]
|
||||
//Content editable wc-editor element
|
||||
public EditorNode:HTMLElement
|
||||
public EditorActionsSection:HTMLElement
|
||||
//Inline edites
|
||||
public EditorInlineActions:any[]
|
||||
public EditorInlineDialog:HTMLDialogElement
|
||||
public EditorInlineActionsForm:HTMLElement
|
||||
//Editor props
|
||||
public EditorPropertyForm?:HTMLElement
|
||||
//Clear btn
|
||||
public EditorClearFormatBtn:HTMLElement
|
||||
//Autocomplete area
|
||||
public EditorAutoCompleteForm?:HTMLElement
|
||||
//Bottom actions
|
||||
public EditorBottomForm?:HTMLElement
|
||||
public EditorBottomFormNewP?:HTMLElement
|
||||
public EditorBottomFormViewToggle?:HTMLElement
|
||||
|
||||
public EditorPreviewText:HTMLTextAreaElement
|
||||
public EditorCustomTagsForm?:HTMLElement
|
||||
public EditorTagsMethods:WCWYSIWYGActions
|
||||
public EditorAllowTags:string[]
|
||||
public EditorFullScreenButton?:HTMLElement
|
||||
public lang:string = 'ru'
|
||||
public value:string = ''
|
||||
|
||||
static observedAttributes = ['value'];
|
||||
|
||||
#EditProps:boolean|object
|
||||
#Autocomplete:boolean
|
||||
#SotrageKey:string|null
|
||||
#HideBottomActions:boolean
|
||||
#Connected:boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.classList.add('wc-wysiwyg');
|
||||
|
||||
//Listen root element events
|
||||
this.onpointerup = (event) => {
|
||||
const selection = window.getSelection();
|
||||
//if check exist selection string
|
||||
if(selection !== null && selection.toString().length > 0) {
|
||||
this.EditorInlineActionsForm.style.display = '';
|
||||
this.EditorPropertyForm.style.display = 'none';
|
||||
this.showEditorInlineDialog();
|
||||
} else {
|
||||
this.hideEditorInlineDialog();
|
||||
}
|
||||
};
|
||||
this.onfullscreenchange = (event) => {
|
||||
const isFullScreen = document.fullscreenElement;
|
||||
this.classList.toggle('-fullscreen', isFullScreen !== null);
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if(this.#Connected === false) {
|
||||
//Check Tags
|
||||
const allowTags = this.getAttribute('data-allow-tags') || allTags.map(t => t.tag).join(',');
|
||||
|
||||
//Bind inner textarea to wc-wysiwyg
|
||||
this.EditorPreviewText = this.querySelector('textarea') as HTMLTextAreaElement;
|
||||
this.EditorPreviewText.className = 'wc-wysiwyg_pr -display-none';
|
||||
this.EditorPreviewText.oninput = event => {
|
||||
const target = event.target as HTMLTextAreaElement;
|
||||
this.EditorNode.innerHTML = target.value;
|
||||
this.value = target.value;
|
||||
};
|
||||
|
||||
this.EditorAllowTags = allowTags.split(',');
|
||||
this.EditorTags = allTags.filter(tag => allowTags.includes(tag.tag));
|
||||
|
||||
this.#EditProps = this.getAttribute('data-edit-props') !== null ? JSON.parse(this.getAttribute('data-edit-props')) : false;
|
||||
this.#Autocomplete = this.getAttribute('data-autocomplete') === '1';
|
||||
this.#HideBottomActions = this.getAttribute('data-hide-bottom-actions') === '1';
|
||||
//allow inline without ['video','audio','img']
|
||||
this.EditorInlineActions = this.EditorTags.filter(action => ['video','audio','img'].includes(action.tag) === false);
|
||||
|
||||
//Check local storage key
|
||||
this.#SotrageKey = this.getAttribute('data-storage');
|
||||
if(this.#SotrageKey) {
|
||||
let storeValue = window.localStorage.getItem(this.#SotrageKey);
|
||||
if(storeValue) {
|
||||
this.value = storeValue;
|
||||
}
|
||||
}
|
||||
this.EditorActionsSection = el('section', { classList: ['wc-wysiwyg_ec'] });
|
||||
//Clear format button
|
||||
this.EditorClearFormatBtn = el('button', {
|
||||
classList: ['wc-wysiwyg_btn', '-clear'],
|
||||
attrs: {
|
||||
'data-hint': this.#t('clearFormat'),
|
||||
},
|
||||
props: {
|
||||
innerHTML:'Ⱦ',
|
||||
},
|
||||
});
|
||||
//Inline selection actions panel
|
||||
this.EditorInlineActionsForm = el('form');
|
||||
this.EditorInlineDialog = el('dialog', {
|
||||
classList: ['wc-wysiwyg_di'],
|
||||
append: [this.EditorInlineActionsForm, this.EditorClearFormatBtn],
|
||||
props: {
|
||||
//prevent submit
|
||||
onsubmit: event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
//Edit props
|
||||
if(this.#EditProps) {
|
||||
//Inline property editor
|
||||
this.EditorPropertyForm = el('form',{
|
||||
styles: { display: 'none' },
|
||||
classList: ['wc-wysiwyg_pf'],
|
||||
props: {
|
||||
onsubmit: event => {
|
||||
event.preventDefault();
|
||||
this.hideEditorInlineDialog();
|
||||
},
|
||||
onpointerup: event => event.stopPropagation(),
|
||||
}
|
||||
});
|
||||
this.EditorInlineDialog.append(this.EditorPropertyForm);
|
||||
}
|
||||
|
||||
//Autocomplete form
|
||||
if(this.#Autocomplete) {
|
||||
this.EditorAutoCompleteForm = el('form', {
|
||||
classList: ['wc-wysiwyg_au'],
|
||||
props: {
|
||||
onsubmit: submitEvent => {
|
||||
submitEvent.preventDefault();
|
||||
submitEvent.stopPropagation();
|
||||
const tagName = submitEvent.submitter.value;
|
||||
const newEl = el(tagName, {
|
||||
props: {
|
||||
innerHTML: tagName
|
||||
}
|
||||
});
|
||||
submitEvent.target.parentElement.replaceWith(newEl);
|
||||
newEl.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Actions in footer
|
||||
this.EditorBottomForm = el('fieldset', {
|
||||
classList: ['wc-wysiwyg_bt'],
|
||||
});
|
||||
|
||||
if(this.#HideBottomActions === false) {
|
||||
//Toggler btn text/html
|
||||
this.EditorBottomFormViewToggle = el('button', {
|
||||
classList: ['wc-wysiwyg_btn'],
|
||||
attrs: {
|
||||
'data-hint': this.#t('toggleViewMode'),
|
||||
'data-mode': 'html5',
|
||||
},
|
||||
props: {
|
||||
type:'button',
|
||||
innerText: 'текст/html5',
|
||||
onpointerup: event => {
|
||||
let mode = this.EditorBottomFormViewToggle.getAttribute('data-mode');
|
||||
let newMode = mode === 'html5' ? 'text' : 'html5';
|
||||
this.EditorBottomFormViewToggle.setAttribute('data-mode', newMode);
|
||||
this.EditorNode.style.display = newMode === 'html5' ? '' : 'none';
|
||||
this.EditorPreviewText.classList.toggle('-display-none', newMode === 'html5' ? true : false)
|
||||
if(newMode === 'text') {
|
||||
this.EditorPreviewText.value = this.EditorNode.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
///New <p> append btn
|
||||
this.EditorBottomFormNewP = el('button', {
|
||||
classList: ['wc-wysiwyg_btn'],
|
||||
attrs: {
|
||||
'data-hint': this.#t('addNewParahraph'),
|
||||
},
|
||||
props: {
|
||||
type:'button',
|
||||
innerText: '+ P',
|
||||
onpointerup: event => {
|
||||
const P = el('p', {props: {innerText: '/'}});
|
||||
this.EditorNode.appendChild(P);
|
||||
P.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
//Fullscreen button
|
||||
this.EditorFullScreenButton = el('button', {
|
||||
classList: ['wc-wysiwyg_btn'],
|
||||
attrs: {
|
||||
'data-hint': this.#t('fullScreen'),
|
||||
},
|
||||
props: {
|
||||
type: "button",
|
||||
ariaRoleDescription: "button",
|
||||
innerText: '🖥️',
|
||||
onpointerup: event => {
|
||||
this.requestFullscreen();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.EditorBottomForm.append(
|
||||
this.EditorBottomFormNewP,
|
||||
this.EditorBottomFormViewToggle,
|
||||
this.EditorFullScreenButton,
|
||||
);
|
||||
}
|
||||
|
||||
//Check custom tags
|
||||
this.EditorCustomTags = JSON.parse( String(this.getAttribute('data-custom-tags')) );
|
||||
if(this.EditorCustomTags !== null) {
|
||||
//Custom panel tags
|
||||
this.EditorCustomTagsForm = el('fieldset', {
|
||||
classList: ['wc-wysiwyg_ce'],
|
||||
});
|
||||
//Make custom actions buttons panel
|
||||
this.#makeActionButtons(this.EditorCustomTagsForm, this.EditorCustomTags);
|
||||
|
||||
this.appendChild(this.EditorCustomTagsForm);
|
||||
}
|
||||
|
||||
//Node editable
|
||||
this.EditorNode = el('article', {
|
||||
classList: ['wc-wysiwyg_content', this.getAttribute('data-content-class')],
|
||||
props: {
|
||||
contentEditable: true,
|
||||
onpointerup: event => {
|
||||
this.checkCanClearElement(event);
|
||||
if(this.#EditProps) {
|
||||
this.checkEditProps(event);
|
||||
}
|
||||
},
|
||||
oninput: event => {
|
||||
this.updateContent();
|
||||
if(this.#Autocomplete) {
|
||||
this.checkAutoComplete();
|
||||
}
|
||||
},
|
||||
//Handle key bindings
|
||||
onkeydown: event => {
|
||||
//check hold alt
|
||||
if(event.altKey) {
|
||||
//alt+space - move caret to parent node next sibling
|
||||
if(event.code === 'Space') {
|
||||
const Selection = window.getSelection();
|
||||
if(Selection.type === 'Caret') {
|
||||
//insertAdjacentElement dont support textNodes, first insert span
|
||||
const span = el('span');
|
||||
Selection.anchorNode.parentElement.insertAdjacentElement('afterend', span)
|
||||
//after replace span with textnode and select it
|
||||
const textN = document.createTextNode(' ');
|
||||
span.replaceWith(textN);
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(textN);
|
||||
Selection.removeAllRanges();
|
||||
Selection.addRange(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
//tag - hide editor dialog
|
||||
if(event.code === 'Escape') {
|
||||
this.hideEditorInlineDialog();
|
||||
}
|
||||
//enter - set p as default tag in newline
|
||||
if(event.code === 'Enter' && event.shiftKey === false) {
|
||||
const Selection = window.getSelection();
|
||||
let tagName = 'p';
|
||||
//tags with return default browser behavior
|
||||
if(['LI', 'ARTICLE', 'P'].includes(Selection.anchorNode.parentElement.tagName)) {
|
||||
return true;
|
||||
}
|
||||
const p = el(tagName, { props: { innerHTML: ` ` } });
|
||||
Selection.anchorNode.parentElement.insertAdjacentElement('afterend', p);
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(p);
|
||||
Selection.removeAllRanges();
|
||||
Selection.addRange(range);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
//Make action buttons
|
||||
this.#makeActionButtons(this.EditorActionsSection, this.EditorTags);
|
||||
this.#makeActionButtons(this.EditorInlineActionsForm, this.EditorInlineActions);
|
||||
|
||||
//Inser wc-editor after textarea node
|
||||
this.append(
|
||||
this.EditorActionsSection,
|
||||
this.EditorInlineDialog,
|
||||
this.EditorNode,
|
||||
this.EditorPreviewText,
|
||||
this.EditorBottomForm,
|
||||
);
|
||||
this.EditorNode.innerHTML = this.EditorPreviewText.value;
|
||||
this.updateContent();
|
||||
|
||||
this.#Connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update content value and update behaviors
|
||||
*/
|
||||
updateContent() {
|
||||
this.value = this.EditorNode.innerHTML;
|
||||
this.checkValidity();
|
||||
if(this.#SotrageKey) {
|
||||
window.localStorage.setItem(this.#SotrageKey, this.value);
|
||||
}
|
||||
this.dispatchEvent(new Event('oninput', { bubbles: true, cancelable: false }));
|
||||
this.updatePreviewEl(this.getAttribute('data-preview-el'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update content at preview element if exists
|
||||
* @param selector css
|
||||
*/
|
||||
updatePreviewEl(selector) {
|
||||
if(selector) {
|
||||
const previewEl = window.document.body.querySelector(selector);
|
||||
if(previewEl) {
|
||||
previewEl.innerHTML = this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate content
|
||||
* @returns boolean hasErrors
|
||||
*/
|
||||
checkValidity() {
|
||||
let hasErros = false,
|
||||
errors= [];
|
||||
|
||||
//Check attrs
|
||||
if(this.getAttribute('required') !== null) {
|
||||
if(String(this.EditorNode.textContent).length === 0) {
|
||||
hasErros = true;
|
||||
errors.push(this.#t('required'));
|
||||
}
|
||||
}
|
||||
if(Number(this.getAttribute('minlength'))) {
|
||||
if(String(this.EditorNode.textContent).length < Number(this.getAttribute('minlength'))) {
|
||||
hasErros = true;
|
||||
errors.push(`${this.#t('minlength')} ${this.getAttribute('minlength')}`);
|
||||
}
|
||||
}
|
||||
if(Number(this.getAttribute('maxlength'))) {
|
||||
if(String(this.EditorNode.textContent).length > Number(this.getAttribute('maxlength'))) {
|
||||
hasErros = true;
|
||||
errors.push(`${this.#t('maxlength')} ${this.getAttribute('maxlength')}`);
|
||||
}
|
||||
}
|
||||
if(this.getAttribute('filtertags')) {
|
||||
const disallowTags = this.getAttribute('filtertags').split(',');
|
||||
for (let i = 0; i < disallowTags.length; i++) {
|
||||
const checkTag = disallowTags[i];
|
||||
if(this.EditorNode.querySelector(checkTag)) {
|
||||
hasErros = true;
|
||||
errors.push(`${this.#t('filtertags')} ${checkTag}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.EditorNode.classList.toggle('-invalid', hasErros);
|
||||
let oldErrors = this.querySelector('.-errors');
|
||||
if(oldErrors) {
|
||||
oldErrors.parentElement.removeChild(oldErrors);
|
||||
}
|
||||
if(hasErros) {
|
||||
const errosEl = el('p', {
|
||||
props: {
|
||||
innerHTML: errors.join('<br>')
|
||||
},
|
||||
classList: ['-errors'],
|
||||
})
|
||||
|
||||
this.append(errosEl);
|
||||
}
|
||||
return hasErros === false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if need append autocompleted tags variants
|
||||
*/
|
||||
checkAutoComplete() {
|
||||
//CHeck autococmplete
|
||||
const Selecton = window.getSelection();
|
||||
if(Selecton !== null && Selecton.anchorNode !== null) {
|
||||
const SelectionParentEl = Selecton.anchorNode.parentElement as HTMLParagraphElement;
|
||||
|
||||
if(SelectionParentEl !== null &&
|
||||
//if empty selection
|
||||
Selecton.toString() === '' &&
|
||||
//and parent node is <p>
|
||||
SelectionParentEl.nodeName === 'P' &&
|
||||
//and parent <p> is parentElement in EditorNode
|
||||
SelectionParentEl.parentElement === this.EditorNode) {
|
||||
//and parent <p> inner text starts with `/`
|
||||
if(SelectionParentEl.innerText.startsWith('/')) {
|
||||
const parsedTagName = SelectionParentEl.innerText.replace('/', '');
|
||||
const filteredActions = this.EditorTags.filter(action => action.tag.toLocaleLowerCase().startsWith(parsedTagName.toLocaleLowerCase()));
|
||||
if(filteredActions.length > 0) {
|
||||
this.EditorAutoCompleteForm.innerHTML = '';
|
||||
filteredActions.forEach(action => {
|
||||
this.EditorAutoCompleteForm.appendChild(el('button', {
|
||||
classList: ['wc-wysiwyg_btn', `-${action.tag}`],
|
||||
attrs: {
|
||||
'data-hint': this.#t(action.tag) || null,
|
||||
},
|
||||
props: {
|
||||
type: 'submit',
|
||||
innerText: action.tag,
|
||||
value: action.tag,
|
||||
}
|
||||
}))
|
||||
});
|
||||
SelectionParentEl.appendChild(this.EditorAutoCompleteForm);
|
||||
} else {
|
||||
//clear form
|
||||
this.EditorAutoCompleteForm.innerHTML = '';
|
||||
//if exist in DOM detach
|
||||
if(this.EditorAutoCompleteForm.parentElement) {
|
||||
this.EditorAutoCompleteForm.parentElement.removeChild(this.EditorAutoCompleteForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show and position inline actions dialog at targetNode
|
||||
**/
|
||||
showEditorInlineDialog() {
|
||||
this.EditorInlineDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide inline dialog
|
||||
**/
|
||||
hideEditorInlineDialog() {
|
||||
if(this.#EditProps){
|
||||
this.EditorPropertyForm.style.display = 'none';
|
||||
}
|
||||
this.EditorInlineDialog.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking and clear tag, if can do it
|
||||
* @param event
|
||||
*/
|
||||
checkCanClearElement(event:Event) {
|
||||
const eventTarget = event.target as HTMLElement;
|
||||
if(eventTarget !== this.EditorNode) {
|
||||
if(eventTarget.nodeName !== 'P'
|
||||
&& eventTarget.nodeName !== 'SPAN') {
|
||||
this.EditorClearFormatBtn.style.display = 'inline-block';
|
||||
this.EditorClearFormatBtn.innerHTML = `Ⱦ ${eventTarget.nodeName}`,
|
||||
this.EditorClearFormatBtn.onpointerup = (event) => {
|
||||
eventTarget.replaceWith(document.createTextNode(eventTarget.textContent));
|
||||
}
|
||||
this.showEditorInlineDialog();
|
||||
} else {
|
||||
this.EditorClearFormatBtn.style.display = 'none';
|
||||
this.EditorClearFormatBtn.onpointerup = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking click tag for editable props
|
||||
**/
|
||||
checkEditProps(event) {
|
||||
//Check need edit props
|
||||
const eventTarget = event.target as HTMLElement;
|
||||
|
||||
//Check exist prop\attr
|
||||
if(this.#EditProps[eventTarget.nodeName]) {
|
||||
const props = this.#EditProps[eventTarget.nodeName];
|
||||
event.stopPropagation();
|
||||
this.EditorPropertyForm.style.display = '';
|
||||
this.showEditorInlineDialog();
|
||||
this.EditorPropertyForm.setAttribute('data-tag', eventTarget.nodeName);
|
||||
this.EditorPropertyForm.innerHTML = '';
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
const tagProp = props[i];
|
||||
const isAttr = tagProp.indexOf('data-') > -1 || tagProp === 'class';
|
||||
this.EditorPropertyForm.append(el('label', {
|
||||
props: { innerText: `${tagProp}=` },
|
||||
append: [
|
||||
el('input', {
|
||||
attrs: { placeholder: tagProp },
|
||||
classList: ['wc-wysiwyg_inp'],
|
||||
props: {
|
||||
value: isAttr ? eventTarget.getAttribute(tagProp) : eventTarget[tagProp] || '',
|
||||
oninput: (eventInput) => {
|
||||
const eventInputTarget = eventInput.target as HTMLInputElement;
|
||||
if(tagProp === 'class') {
|
||||
eventTarget.className = eventInputTarget.value;
|
||||
}
|
||||
if((isAttr || tagProp === 'datetime') && eventInputTarget !== null) {
|
||||
eventTarget.setAttribute(tagProp, eventInputTarget.value)
|
||||
} else {
|
||||
eventTarget[tagProp] = eventInputTarget.value;
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}));
|
||||
}
|
||||
//add submit button for better UX
|
||||
this.EditorPropertyForm.append(el('button', {
|
||||
classList: ['wc-wysiwyg_btn'],
|
||||
props: {
|
||||
type: 'submit',
|
||||
innerHTML: '↳',
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#makeActionButtons(toEl:HTMLElement, actions) {
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
const action = actions[i];
|
||||
const button = el('button', {
|
||||
classList: ['wc-wysiwyg_btn', `-${action.tag}`],
|
||||
props: {
|
||||
tabIndex: -1,
|
||||
type:'button',
|
||||
textContent: action.is ? `${action.tag} is=${action.is}` : action.tag,
|
||||
onpointerup: (event) => this.#tag(action.tag, event, action.is),
|
||||
},
|
||||
attrs: {
|
||||
'data-hint': action.hint ? action.hint : this.#t(action.tag) || '-',
|
||||
}
|
||||
});
|
||||
//-wc
|
||||
//Make button with
|
||||
toEl.appendChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default behaviors fot tag actions
|
||||
*/
|
||||
#tag = (tag:string, event:Event|false = false, is:boolean|string = false) => {
|
||||
switch (tag) {
|
||||
case 'audio':
|
||||
this.#Media('audio');
|
||||
break;
|
||||
case 'video':
|
||||
this.#Media('video');
|
||||
break;
|
||||
case 'img':
|
||||
this.#Image();
|
||||
break;
|
||||
default:
|
||||
this.#wrapTag(tag, is);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap content in <tag>
|
||||
**/
|
||||
#wrapTag = (tag, is:boolean|string = false) => {
|
||||
const isList = ['ul', 'ol'].includes(tag);
|
||||
const Selection = window.getSelection();
|
||||
let className = null;
|
||||
let defaultOptions = {
|
||||
classList: className ? className : undefined,
|
||||
} as any;
|
||||
if(isList) {
|
||||
tag = 'li';
|
||||
}
|
||||
if(is) {
|
||||
defaultOptions.options = {is};
|
||||
}
|
||||
let tagNode = el(tag, defaultOptions);
|
||||
|
||||
if (Selection !== null && Selection.rangeCount) {
|
||||
if(['ul', 'ol'].includes(tag)) {
|
||||
const list = el(tag);
|
||||
tagNode.replaceWith(list);
|
||||
list.append(tagNode)
|
||||
}
|
||||
const range = Selection.getRangeAt(0).cloneRange();
|
||||
range.surroundContents(tagNode);
|
||||
Selection.removeAllRanges();
|
||||
Selection.addRange(range);
|
||||
if(Selection.toString().length === 0) {
|
||||
tagNode.innerText = tag;
|
||||
}
|
||||
this.updateContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert <audio>
|
||||
**/
|
||||
#Media = (tagName:string) => {
|
||||
const mediaSrc = prompt('src', '');
|
||||
if(mediaSrc === '') {
|
||||
return false;
|
||||
}
|
||||
const mediaEl = el(tagName, { attrs: { controls: true }, props: { src: mediaSrc } } );
|
||||
this.EditorNode.append(mediaEl);
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert <img>
|
||||
**/
|
||||
#Image = () => {
|
||||
const src = prompt('IMG URL') ;
|
||||
const caption = prompt('IMG caption');
|
||||
const img = new Image();
|
||||
if(src) {
|
||||
img.src = src;
|
||||
} else {
|
||||
//@todo
|
||||
return alert('Invalid src');
|
||||
}
|
||||
|
||||
if(caption) {
|
||||
const figure = el('figure');
|
||||
|
||||
const figcaption = el('figcaption', {
|
||||
props: {
|
||||
textContent: caption
|
||||
}
|
||||
});
|
||||
figure.appendChild(img);
|
||||
figure.appendChild(figcaption);
|
||||
|
||||
img.setAttribute('alt', caption);
|
||||
this.EditorNode.appendChild(figure);
|
||||
} else {
|
||||
this.EditorNode.appendChild(img);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate function
|
||||
* @param key:string phrase key
|
||||
* @returns
|
||||
*/
|
||||
#t(key:string):string {
|
||||
let lang = this.lang;
|
||||
return t[lang] ? t[lang][key] || "-" : t["en"][key];
|
||||
}
|
||||
//define WCWYSIWYG as custom element
|
||||
static define(name = 'wc-wysiwyg') {
|
||||
window.customElements.define(name, WCWYSIWYG);
|
||||
}
|
||||
}
|
||||
export default WCWYSIWYG;
|
||||
export const define = WCWYSIWYG.define;
|
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": ["src/wc-wysiwyg.ts"],
|
||||
"compilerOptions": {
|
||||
"module": "es2022",
|
||||
"skipLibCheck": true,
|
||||
"allowJs": false,
|
||||
"declaration": false,
|
||||
"outDir": "./dist",
|
||||
"declarationMap": false,
|
||||
"target": "ESNEXT",
|
||||
"removeComments": true,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user