diff --git a/dev/External/SquireUI.js b/dev/External/SquireUI.js
index 563f8562f..b46d402ed 100644
--- a/dev/External/SquireUI.js
+++ b/dev/External/SquireUI.js
@@ -68,7 +68,12 @@ class SquireUI
clr.style.width = input.offsetWidth + 'px';
clr.value = '';
- clr.onchange = () => squire.setStyle({[name]:clr.value});
+ clr.onchange = () => {
+ if (name === 'color')
+ squire.setTextColor(clr.value);
+ else if (name === 'backgroundColor')
+ squire.setHighlightColor(clr.value);
+ }
// Chrome 110+ https://github.com/the-djmaze/snappymail/issues/1199
// clr.oninput = () => squire.setStyle({[name]:clr.value});
setTimeout(()=>clr.click(),1);
@@ -106,12 +111,13 @@ class SquireUI
Georgia: "'URW Palladio L', Georgia, Times, serif"
}
},
- cmd: s => squire.setStyle({ fontFamily: s.value })
+ defaultValueIndex: 4,
+ cmd: s => this.squire.setFontFace(s.value)
},
fontSize: {
select: ['11px','13px','16px','20px','24px','30px'],
defaultValueIndex: 2,
- cmd: s => squire.setStyle({ fontSize: s.value })
+ cmd: s => this.squire.setFontSize(s.value)
// TODO: maybe consider using https://developer.mozilla.org/en-US/docs/Web/CSS/font-size#values
// example:
// select: ['xx-small', 'x-small',' small',' medium', 'large', 'x-large', 'xx-large', 'xxx-large'],
@@ -130,16 +136,6 @@ class SquireUI
// }
// }
},
- dir: {
- dir_ltr: {
- html: '⁋',
- cmd: () => squire.setTextDirection('ltr')
- },
- dir_rtl: {
- html: '¶',
- cmd: () => squire.setTextDirection('rtl')
- }
- },
colors: {
textColor: {
html: 'A▾',
@@ -153,81 +149,244 @@ class SquireUI
inline: {
bold: {
html: 'B',
- cmd: () => this.doAction('bold'),
+ cmd: () => this.squire.hasFormat('b') ? this.doAction('removeBold') : this.doAction('bold'),
key: 'B',
matches: 'B,STRONT'
},
italic: {
html: 'I',
- cmd: () => this.doAction('italic'),
+ cmd: () => this.squire.hasFormat('i') ? this.doAction('removeItalic') : this.doAction('italic'),
key: 'I',
matches: 'I'
},
underline: {
html: 'U',
- cmd: () => this.doAction('underline'),
+ cmd: () => this.squire.hasFormat('u') ? this.doAction('removeUnderline') : this.doAction('underline'),
key: 'U',
matches: 'U'
},
strike: {
html: 'S',
- cmd: () => this.doAction('strikethrough'),
+ cmd: () => this.squire.hasFormat('s') ? this.doAction('removeStrikethrough') : this.doAction('strikethrough'),
key: 'Shift + 7',
matches: 'S'
},
sub: {
html: 'Xₙ',
- cmd: () => this.doAction('subscript'),
+ cmd: () => this.squire.hasFormat('sub') ? this.doAction('removeSubscript') : this.doAction('subscript'),
key: 'Shift + 5',
matches: 'SUB'
},
sup: {
html: 'Xⁿ',
- cmd: () => this.doAction('superscript'),
+ cmd: () => this.squire.hasFormat('sup') ? this.doAction('removeSuperscript') : this.doAction('superscript'),
key: 'Shift + 6',
matches: 'SUP'
}
},
block: {
+ quote: {
+ html: '"',
+ cmd: () => this.squire.hasFormat('blockquote') ? this.doAction('decreaseQuoteLevel') : this.doAction('increaseQuoteLevel'),
+ matches: 'BLOCKQUOTE'
+ },
+ indentDecrease: {
+ html: ``,
+ cmd: () => this.doAction('decreaseQuoteLevel'),
+ key: ']'
+ },
+ indentIncrease: {
+ html: ``,
+ cmd: () => this.doAction('increaseQuoteLevel'),
+ key: '['
+ },
ol: {
- html: '#',
- cmd: () => this.doList('OL'),
+ html: ``,
+ cmd: () => this.doList('ol'),
key: 'Shift + 8',
matches: 'OL'
},
ul: {
- html: '⋮',
- cmd: () => this.doList('UL'),
+ html: ``,
+ cmd: () => this.doList('ul'),
key: 'Shift + 9',
matches: 'UL'
+ }
+ },
+ alighnment: {
+ leftAlign: {
+ html: ``,
+ cmd: () => this.squire.setTextAlignment('left'),
+ // matches: ''
},
- quote: {
- html: '"',
- cmd: () => {
- let parent = squire.getSelectionClosest('UL,OL,BLOCKQUOTE')?.nodeName;
- ('BLOCKQUOTE' == parent) ? squire.decreaseQuoteLevel() : squire.increaseQuoteLevel();
- },
- matches: 'BLOCKQUOTE'
+ centerAlign: {
+ html: ``,
+ cmd: () => this.squire.setTextAlignment('center'),
+ // matches: ''
},
- indentDecrease: {
- html: '⇤',
- cmd: () => squire.changeIndentationLevel('decrease'),
- key: ']'
+ rightAlign: {
+ html: ``,
+ cmd: () => this.squire.setTextAlignment('right'),
+ // matches: ''
},
- indentIncrease: {
- html: '⇥',
- cmd: () => squire.changeIndentationLevel('increase'),
- key: '['
+ justifyAlign: {
+ html: ``,
+ cmd: () => this.squire.setTextAlignment('justify'),
+ // matches: ''
+ },
+ },
+ dir: {
+ dir_ltr: {
+ html: ``,
+ cmd: () => this.squire.setTextDirection('ltr')
+ },
+ dir_rtl: {
+ html: ``,
+ cmd: () => this.squire.setTextDirection('rtl')
}
},
targets: {
link: {
html: '🔗',
cmd: () => {
- let node = squire.getSelectionClosest('A'),
+ let node = this.squire.getSelection(),
url = prompt("Link", node?.href || "https://");
if (url != null) {
- url.length ? squire.makeLink(url) : (node && squire.removeLink());
+ url.length ? this.squire.makeLink(url) : (node && this.squire.removeLink());
}
},
matches: 'A'
@@ -235,9 +394,9 @@ class SquireUI
imageUrl: {
html: '🖼️',
cmd: () => {
- let node = squire.getSelectionClosest('IMG'),
+ let node = this.squire.getSelection(),
src = prompt("Image", node?.src || "https://");
- src?.length ? squire.insertImage(src) : node?.remove();
+ src?.length ? this.squire.insertImage(src) : (node && this.squire.detach(node));
},
matches: 'IMG'
},
@@ -255,12 +414,12 @@ class SquireUI
changes: {
undo: {
html: '↶',
- cmd: () => squire.undo(),
+ cmd: () => this.squire.undo(),
key: 'Z'
},
redo: {
html: '↷',
- cmd: () => squire.redo(),
+ cmd: () => this.squire.redo(),
key: 'Y'
},
source: {
@@ -275,7 +434,7 @@ class SquireUI
clear: {
removeStyle: {
html: '⎚',
- cmd: () => squire.setStyle()
+ cmd: () => this.squire.setStyle()
}
}
},
@@ -317,7 +476,7 @@ class SquireUI
if (browseImage.files.length) {
let reader = new FileReader();
reader.readAsDataURL(browseImage.files[0]);
- reader.onloadend = () => reader.result && squire.insertImage(reader.result);
+ reader.onloadend = () => reader.result && this.squire.insertImage(reader.result);
}
}
@@ -403,12 +562,12 @@ class SquireUI
this.modeSelect = actions.mode.plain.input;
- let changes = actions.changes;
- changes.undo.input.disabled = changes.redo.input.disabled = true;
- squire.addEventListener('undoStateChange', e => {
- changes.undo.input.disabled = !e.detail.canUndo;
- changes.redo.input.disabled = !e.detail.canRedo;
- });
+ // let changes = actions.changes;
+ // changes.undo.input.disabled = changes.redo.input.disabled = true;
+ // squire.addEventListener('undoStateChange', state => {
+ // changes.undo.input.disabled = !state.canUndo;
+ // changes.redo.input.disabled = !state.canRedo;
+ // });
actions.font.fontSize.input.selectedIndex = actions.font.fontSize.defaultValueIndex;
@@ -540,9 +699,8 @@ class SquireUI
}
doList(type) {
- let parent = this.squire.getSelectionClosest('UL,OL')?.nodeName,
- fn = {UL:'makeUnorderedList',OL:'makeOrderedList'};
- (parent == type) ? this.squire.removeList() : this.squire[fn[type]]();
+ let fn = {ul:'makeUnorderedList',ol:'makeOrderedList'};
+ this.squire.hasFormat(type) ? this.squire.removeList() : this.squire[fn[type]]()
}
/*
testPresenceinSelection(format, validation) {
diff --git a/dev/Styles/User/SquireUI.less b/dev/Styles/User/SquireUI.less
index 646ee4dd1..6007485bb 100644
--- a/dev/Styles/User/SquireUI.less
+++ b/dev/Styles/User/SquireUI.less
@@ -2,11 +2,15 @@
.squire-toolbar {
border-bottom: 1px solid #b6b6b6;
min-height: 28px;
- overflow-x: auto;
- overflow-y: hidden;
- padding: 2px;
+ overflow: hidden;
+ padding: 10px 5px;
position: relative;
white-space: nowrap;
+ display: flex;
+ flex-wrap: wrap;
+ align-content: center;
+ box-sizing: content-box;
+
}
.squire-toolbar input[type="color"] {
@@ -17,18 +21,31 @@
width: 40px;
}
+.squire-toolbar input[type="color"][list="squire-colors"] {
+ top: 10px;
+}
+
.squire-toolbar select {
font-size: 85%;
padding: 4px 1.5em 4px 6px;
- text-align: var(--left, left);
+ text-align: left;
vertical-align: middle;
- width: 7em;
+ width: fit-content;;
+ background-color: unset;
+ border: unset;
+ text-shadow: none;
+ box-shadow: none !important;
}
.squire-toolbar select[data-action="fontSize"] {
width: 5em;
}
.squire-toolbar button {
- font-family: snappymail, var(--fontSans)
+ font-family: snappymail, var(--fontSans);
+ padding: 2px 10px 4px 10px !important;
+ background-color: unset;
+ border: unset;
+ text-shadow: none;
+ box-shadow: none !important;
}
.squire-toolbar button[data-action="bold"] {
font-weight: bold;
@@ -44,6 +61,25 @@
text-decoration: line-through;
}
*/
+.squire-toolbar button:hover {
+ transform: scale(1.2);
+}
+
+.squire-toolbar button img {
+ width: 12px;
+ height: 12px;
+}
+
+.squire-toolbar button svg {
+ width: 18px;
+ height: 18px;
+ margin-top: 8px;
+}
+
+[dir="rtl"] .squire-toolbar.btn-toolbar div.btn-group {
+ display: flex;
+ flex-direction: row-reverse;
+}
.squire-wysiwyg, .squire-plain {
height: 100%;
@@ -55,16 +91,19 @@
.squire-wysiwyg {
font-family: var(--fontSans);
+ line-height: 1.6;
ul {
- padding-left: 40px;
+ padding-left: 20px;
+ padding-right: 20px;
li {
list-style-type: disc !important;
}
}
ol {
- padding-left: 40px;
+ padding-left: 20px;
+ padding-right: 20px;
li {
list-style-type: decimal !important;
}
diff --git a/snappymail/v/0.0.0/app/localization/en/user.json b/snappymail/v/0.0.0/app/localization/en/user.json
index 44bf9b67c..c33a398bc 100644
--- a/snappymail/v/0.0.0/app/localization/en/user.json
+++ b/snappymail/v/0.0.0/app/localization/en/user.json
@@ -428,7 +428,11 @@
"IMAGEUPLOAD": "Image select",
"UNDO": "Undo",
"REDO": "Redo",
- "REMOVESTYLE": "Remove style"
+ "REMOVESTYLE": "Remove style",
+ "LEFTALIGN": "Right",
+ "CENTERALIGN": "Center",
+ "RIGHTALIGN": "Left",
+ "JUSTIFYALIGN": "Justify"
},
"SETTINGS_LABELS": {
"GENERAL": "General",
diff --git a/snappymail/v/0.0.0/app/localization/fa/user.json b/snappymail/v/0.0.0/app/localization/fa/user.json
index e11831efc..e5aa420f2 100644
--- a/snappymail/v/0.0.0/app/localization/fa/user.json
+++ b/snappymail/v/0.0.0/app/localization/fa/user.json
@@ -428,7 +428,11 @@
"IMAGEUPLOAD": "Image select",
"UNDO": "Undo",
"REDO": "Redo",
- "REMOVESTYLE": "Remove style"
+ "REMOVESTYLE": "Remove style",
+ "LEFTALIGN": "Right",
+ "CENTERALIGN": "Center",
+ "RIGHTALIGN": "Left",
+ "JUSTIFYALIGN": "Justify"
},
"SETTINGS_LABELS": {
"GENERAL": "عمومی",
@@ -465,8 +469,8 @@
"LAYOUT_HORIZONTAL_SPLIT": "تقسیم افقی",
"SHOW_NEXT_MESSAGE": "Show next message when (re)move current message",
"EDITOR": "ویرایشگر پیشفرض",
- "EDITOR_HTML": "تحت فرمت Html",
- "EDITOR_PLAIN": "ساده",
+ "EDITOR_HTML": "فرمت HTML",
+ "EDITOR_PLAIN": "فرمت ساده",
"VIEW_OPTIONS": "مشاهده گزینهها",
"USE_PREVIEW_PANE": "استفاده از پنجره پیشنمایش",
"HIDE_DELETED_MESSAGES": "پنهان کردن پیام های علامت گذاری شده برای حذف",
diff --git a/tasks/config.js b/tasks/config.js
index 01bd89b2a..3c91151f1 100644
--- a/tasks/config.js
+++ b/tasks/config.js
@@ -63,7 +63,8 @@ config.paths.js = {
'vendors/bootstrap/js/bootstrap.native.js',
'vendors/knockout/build/output/knockout-latest.js',
// 'vendors/knockout/build/output/knockout-latest.debug.js',
- 'vendors/squire/build/squire-raw.js',
+ 'vendors/dompurify/dist/purify.js',
+ 'vendors/squire-rte/dist/squire-raw.js',
'vendors/mathiasbynens/punycode.js',
'dev/External/SquireUI.js'
]