improve: max occurrence limit
This commit is contained in:
161
邮件编辑器.html
Normal file
161
邮件编辑器.html
Normal file
@@ -0,0 +1,161 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css" rel="stylesheet">
|
||||
<link href="http://antifavicon.com/ex8.png" rel="icon">
|
||||
<title>编辑邮件</title>
|
||||
<style>
|
||||
body {
|
||||
height: 85vh;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px;
|
||||
max-height: fit-content;
|
||||
}
|
||||
#subject {
|
||||
border: 0px;
|
||||
border-left: 1px solid #CCC;
|
||||
border-right: 1px solid #CCC;
|
||||
padding: 10.5px 16px 10.5px 16px;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: calc(1.5 / 1);
|
||||
}
|
||||
input:-webkit-autofill {
|
||||
-webkit-box-shadow: 0 0 0px 1000px white inset;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="toolbar">
|
||||
<span class="ql-formats">
|
||||
<!-- Add font size dropdown -->
|
||||
<select class="ql-font">
|
||||
</select>
|
||||
<select class="ql-header">
|
||||
<option value="1"></option>
|
||||
<option value="2"></option>
|
||||
<option value="3"></option>
|
||||
<option value="4"></option>
|
||||
<!-- Note a missing, thus falsy value, is used to reset to default -->
|
||||
<option selected></option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<button class="ql-bold"></button>
|
||||
<button class="ql-italic"></button>
|
||||
<button class="ql-underline"></button>
|
||||
<button class="ql-strike"></button>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<button class="ql-script" value="sub"></button>
|
||||
<button class="ql-script" value="super"></button>
|
||||
<button class="ql-list" value="ordered"></button>
|
||||
<button class="ql-list" value="bullet"></button>
|
||||
</span>
|
||||
<span class="ql-formats">
|
||||
<button id="load">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="oklch(0.269 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M14 3v4a1 1 0 0 0 1 1h4" />
|
||||
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" />
|
||||
<path d="M12 11l0 6" />
|
||||
<path d="M9 14l6 0" />
|
||||
</svg>
|
||||
</button>
|
||||
<button id="save">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="oklch(0.269 0 0)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M6 4h10l4 4v10a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2" />
|
||||
<path d="M12 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
|
||||
<path d="M14 4l0 4l-6 0l0 -4" />
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<input id="subject" name="subject" type="text" />
|
||||
<div id="editor"></div>
|
||||
</body>
|
||||
<script>
|
||||
const quill = new Quill('#editor', {
|
||||
theme: 'snow',
|
||||
modules: {
|
||||
toolbar: '#toolbar'
|
||||
}
|
||||
});
|
||||
|
||||
const loadButton = document.querySelector("#load");
|
||||
const saveButton = document.querySelector('#save');
|
||||
const editor = document.querySelector('#editor');
|
||||
const input = document.querySelector('#subject');
|
||||
|
||||
let reader = new FileReader();
|
||||
let parser = new DOMParser();
|
||||
let fileHandle = 'desktop';
|
||||
|
||||
reader.addEventListener('load', () => {
|
||||
const contents = reader.result;
|
||||
const virtual = parser.parseFromString(contents, 'text/html');
|
||||
|
||||
const body = virtual.querySelector('body');
|
||||
const html = body ? body.innerHTML : contents;
|
||||
|
||||
const delta = quill.clipboard.convert({ html });
|
||||
quill.setContents(delta, 'silent');
|
||||
});
|
||||
|
||||
loadButton.addEventListener('click', async () => {
|
||||
[fileHandle] = await window.showOpenFilePicker({
|
||||
startIn: fileHandle,
|
||||
types: [
|
||||
{ accept: { "text/html": [".html"] }},
|
||||
],
|
||||
});
|
||||
const file = await fileHandle.getFile();
|
||||
const name = fileHandle.name;
|
||||
const subject = name.substring(0, name.lastIndexOf('.'));
|
||||
|
||||
input.value = subject;
|
||||
reader.readAsText(file);
|
||||
});
|
||||
|
||||
saveButton.addEventListener('click', async () => {
|
||||
fileHandle = await window.showSaveFilePicker({
|
||||
startIn: fileHandle,
|
||||
suggestedName: input.value,
|
||||
types: [
|
||||
{ accept: { "text/html": [".html"] }},
|
||||
],
|
||||
});
|
||||
let writable = await fileHandle.createWritable();
|
||||
let contents = editor.firstChild.innerHTML;
|
||||
|
||||
const name = fileHandle.name;
|
||||
const subject = name.substring(0, name.lastIndexOf('.'));
|
||||
input.value = subject;
|
||||
|
||||
let html = document.createElement('html');
|
||||
let body = document.createElement('body');
|
||||
let meta = document.createElement('meta');
|
||||
let link = document.createElement('link');
|
||||
|
||||
if (!(/<html>[\s\S]*<\/html>/i).test(contents)) {
|
||||
meta.setAttribute('charset', "UTF-8");
|
||||
link.setAttribute('href', "https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css");
|
||||
link.setAttribute('rel', "stylesheet");
|
||||
body.setAttribute('class', "ql-container ql-editor ql-snow");
|
||||
body.innerHTML = contents;
|
||||
html.appendChild(meta);
|
||||
html.appendChild(link);
|
||||
html.appendChild(body);
|
||||
contents = html.outerHTML;
|
||||
}
|
||||
|
||||
await writable.write(contents);
|
||||
await writable.close();
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
Reference in New Issue
Block a user