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' ]