mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-06 16:07:03 +03:00
Improved Squire by visualizing some active buttons states
This commit is contained in:
parent
baacddd324
commit
2e0fc1585d
3 changed files with 62 additions and 39 deletions
67
dev/External/SquireUI.js
vendored
67
dev/External/SquireUI.js
vendored
|
|
@ -19,6 +19,8 @@ const
|
||||||
htmlToPlain = html => rl.Utils.htmlToPlain(html).trim(),
|
htmlToPlain = html => rl.Utils.htmlToPlain(html).trim(),
|
||||||
plainToHtml = text => rl.Utils.plainToHtml(text),
|
plainToHtml = text => rl.Utils.plainToHtml(text),
|
||||||
|
|
||||||
|
forEachObjectValue = (obj, fn) => Object.values(obj).forEach(fn),
|
||||||
|
|
||||||
getFragmentOfChildren = parent => {
|
getFragmentOfChildren = parent => {
|
||||||
let frag = doc.createDocumentFragment();
|
let frag = doc.createDocumentFragment();
|
||||||
frag.append(...parent.childNodes);
|
frag.append(...parent.childNodes);
|
||||||
|
|
@ -127,37 +129,43 @@ class SquireUI
|
||||||
html: 'B',
|
html: 'B',
|
||||||
cmd: () => this.doAction('bold'),
|
cmd: () => this.doAction('bold'),
|
||||||
key: 'B',
|
key: 'B',
|
||||||
hint: 'Bold'
|
hint: 'Bold',
|
||||||
|
matches: 'B,STRONT'
|
||||||
},
|
},
|
||||||
italic: {
|
italic: {
|
||||||
html: 'I',
|
html: 'I',
|
||||||
cmd: () => this.doAction('italic'),
|
cmd: () => this.doAction('italic'),
|
||||||
key: 'I',
|
key: 'I',
|
||||||
hint: 'Italic'
|
hint: 'Italic',
|
||||||
|
matches: 'I'
|
||||||
},
|
},
|
||||||
underline: {
|
underline: {
|
||||||
html: '<u>U</u>',
|
html: '<u>U</u>',
|
||||||
cmd: () => this.doAction('underline'),
|
cmd: () => this.doAction('underline'),
|
||||||
key: 'U',
|
key: 'U',
|
||||||
hint: 'Underline'
|
hint: 'Underline',
|
||||||
|
matches: 'U'
|
||||||
},
|
},
|
||||||
strike: {
|
strike: {
|
||||||
html: '<s>S</s>',
|
html: '<s>S</s>',
|
||||||
cmd: () => this.doAction('strikethrough'),
|
cmd: () => this.doAction('strikethrough'),
|
||||||
key: 'Shift + 7',
|
key: 'Shift + 7',
|
||||||
hint: 'Strikethrough'
|
hint: 'Strikethrough',
|
||||||
|
matches: 'S'
|
||||||
},
|
},
|
||||||
sub: {
|
sub: {
|
||||||
html: 'Xₙ',
|
html: 'Xₙ',
|
||||||
cmd: () => this.doAction('subscript'),
|
cmd: () => this.doAction('subscript'),
|
||||||
key: 'Shift + 5',
|
key: 'Shift + 5',
|
||||||
hint: 'Subscript'
|
hint: 'Subscript',
|
||||||
|
matches: 'SUB'
|
||||||
},
|
},
|
||||||
sup: {
|
sup: {
|
||||||
html: 'Xⁿ',
|
html: 'Xⁿ',
|
||||||
cmd: () => this.doAction('superscript'),
|
cmd: () => this.doAction('superscript'),
|
||||||
key: 'Shift + 6',
|
key: 'Shift + 6',
|
||||||
hint: 'Superscript'
|
hint: 'Superscript',
|
||||||
|
matches: 'SUP'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
block: {
|
block: {
|
||||||
|
|
@ -165,13 +173,15 @@ class SquireUI
|
||||||
html: '#',
|
html: '#',
|
||||||
cmd: () => this.doList('OL'),
|
cmd: () => this.doList('OL'),
|
||||||
key: 'Shift + 8',
|
key: 'Shift + 8',
|
||||||
hint: 'Ordered list'
|
hint: 'Ordered list',
|
||||||
|
matches: 'OL'
|
||||||
},
|
},
|
||||||
ul: {
|
ul: {
|
||||||
html: '⋮',
|
html: '⋮',
|
||||||
cmd: () => this.doList('UL'),
|
cmd: () => this.doList('UL'),
|
||||||
key: 'Shift + 9',
|
key: 'Shift + 9',
|
||||||
hint: 'Unordered list'
|
hint: 'Unordered list',
|
||||||
|
matches: 'UL'
|
||||||
},
|
},
|
||||||
quote: {
|
quote: {
|
||||||
html: '"',
|
html: '"',
|
||||||
|
|
@ -179,7 +189,8 @@ class SquireUI
|
||||||
let parent = squire.getSelectionClosest('UL,OL,BLOCKQUOTE')?.nodeName;
|
let parent = squire.getSelectionClosest('UL,OL,BLOCKQUOTE')?.nodeName;
|
||||||
('BLOCKQUOTE' == parent) ? squire.decreaseQuoteLevel() : squire.increaseQuoteLevel();
|
('BLOCKQUOTE' == parent) ? squire.decreaseQuoteLevel() : squire.increaseQuoteLevel();
|
||||||
},
|
},
|
||||||
hint: 'Blockquote'
|
hint: 'Blockquote',
|
||||||
|
matches: 'BLOCKQUOTE'
|
||||||
},
|
},
|
||||||
indentDecrease: {
|
indentDecrease: {
|
||||||
html: '⇤',
|
html: '⇤',
|
||||||
|
|
@ -204,7 +215,8 @@ class SquireUI
|
||||||
url.length ? squire.makeLink(url) : (node && squire.removeLink());
|
url.length ? squire.makeLink(url) : (node && squire.removeLink());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hint: 'Link'
|
hint: 'Link',
|
||||||
|
matches: 'A'
|
||||||
},
|
},
|
||||||
imageUrl: {
|
imageUrl: {
|
||||||
html: '🖼️',
|
html: '🖼️',
|
||||||
|
|
@ -213,12 +225,14 @@ class SquireUI
|
||||||
src = prompt("Image", node?.src || "https://");
|
src = prompt("Image", node?.src || "https://");
|
||||||
src?.length ? squire.insertImage(src) : (node && squire.detach(node));
|
src?.length ? squire.insertImage(src) : (node && squire.detach(node));
|
||||||
},
|
},
|
||||||
hint: 'Image URL'
|
hint: 'Image URL',
|
||||||
|
matches: 'IMG'
|
||||||
},
|
},
|
||||||
imageUpload: {
|
imageUpload: {
|
||||||
html: '📂️',
|
html: '📂️',
|
||||||
cmd: () => browseImage.click(),
|
cmd: () => browseImage.click(),
|
||||||
hint: 'Image select',
|
hint: 'Image select',
|
||||||
|
matches: 'IMG'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
|
|
@ -241,7 +255,10 @@ class SquireUI
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
html: '👁',
|
html: '👁',
|
||||||
cmd: () => this.setMode('source' == this.mode ? 'wysiwyg' : 'source'),
|
cmd: btn => {
|
||||||
|
this.setMode('source' == this.mode ? 'wysiwyg' : 'source');
|
||||||
|
btn.classList.toggle('active', 'source' == this.mode);
|
||||||
|
},
|
||||||
hint: i18n('EDITOR/TEXT_SWITCHER_SOURCE', 'Source')
|
hint: i18n('EDITOR/TEXT_SWITCHER_SOURCE', 'Source')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -362,15 +379,21 @@ class SquireUI
|
||||||
|
|
||||||
container.append(toolbar, wysiwyg, plain);
|
container.append(toolbar, wysiwyg, plain);
|
||||||
|
|
||||||
|
squire.addEventListener('pathChange', e => {
|
||||||
|
forEachObjectValue(actions, entries => {
|
||||||
|
forEachObjectValue(entries, cfg => {
|
||||||
|
// cfg.matches && cfg.input.classList.toggle('active', e.element && e.element.matches(cfg.matches));
|
||||||
|
cfg.matches && cfg.input.classList.toggle('active', e.element && e.element.closestWithin(cfg.matches, squire.getRoot()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
/*
|
/*
|
||||||
squire.addEventListener('dragover', );
|
squire.addEventListener('cursor', e => {
|
||||||
squire.addEventListener('drop', );
|
console.dir({cursor:e.range});
|
||||||
squire.addEventListener('pathChange', );
|
});
|
||||||
squire.addEventListener('cursor', );
|
squire.addEventListener('select', e => {
|
||||||
squire.addEventListener('select', );
|
console.dir({select:e.range});
|
||||||
squire.addEventListener('input', );
|
});
|
||||||
squire.addEventListener( 'keydown keyup', monitorShiftKey )
|
|
||||||
squire.addEventListener( 'keydown', onKey )
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// CKEditor gimmicks used by HtmlEditor
|
// CKEditor gimmicks used by HtmlEditor
|
||||||
|
|
@ -393,11 +416,11 @@ class SquireUI
|
||||||
fn = {UL:'makeUnorderedList',OL:'makeOrderedList'};
|
fn = {UL:'makeUnorderedList',OL:'makeOrderedList'};
|
||||||
(parent == type) ? this.squire.removeList() : this.squire[fn[type]]();
|
(parent == type) ? this.squire.removeList() : this.squire[fn[type]]();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
testPresenceinSelection(format, validation) {
|
testPresenceinSelection(format, validation) {
|
||||||
return validation.test(this.squire.getPath()) || this.squire.hasFormat(format);
|
return validation.test(this.squire.getPath()) || this.squire.hasFormat(format);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
setMode(mode) {
|
setMode(mode) {
|
||||||
if (this.mode != mode) {
|
if (this.mode != mode) {
|
||||||
let cl = this.container.classList, source = 'source' == this.mode;
|
let cl = this.container.classList, source = 'source' == this.mode;
|
||||||
|
|
|
||||||
|
|
@ -266,8 +266,7 @@ trait ResponseParser
|
||||||
$oImapResponse, true, $sPreviousAtomUpperCase, '['
|
$oImapResponse, true, $sPreviousAtomUpperCase, '['
|
||||||
);
|
);
|
||||||
|
|
||||||
if (null !== $sListBlock)
|
if (null !== $sListBlock) {
|
||||||
{
|
|
||||||
$sAtomBuilder .= $sListBlock.']';
|
$sAtomBuilder .= $sListBlock.']';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
31
vendors/squire/build/squire-raw.js
vendored
31
vendors/squire/build/squire-raw.js
vendored
|
|
@ -76,7 +76,8 @@ const
|
||||||
BLOCK = 2,
|
BLOCK = 2,
|
||||||
CONTAINER = 3,
|
CONTAINER = 3,
|
||||||
|
|
||||||
isLeaf = node => node.nodeType === ELEMENT_NODE && !!leafNodeNames[ node.nodeName ],
|
isElement = node => node.nodeType === ELEMENT_NODE,
|
||||||
|
isLeaf = node => isElement(node) && !!leafNodeNames[ node.nodeName ],
|
||||||
|
|
||||||
getNodeCategory = node => {
|
getNodeCategory = node => {
|
||||||
switch (node.nodeType) {
|
switch (node.nodeType) {
|
||||||
|
|
@ -157,7 +158,7 @@ const
|
||||||
let path = '', style;
|
let path = '', style;
|
||||||
if (node && node !== root) {
|
if (node && node !== root) {
|
||||||
path = getPath(node.parentNode, root);
|
path = getPath(node.parentNode, root);
|
||||||
if (node.nodeType === ELEMENT_NODE) {
|
if (isElement(node)) {
|
||||||
path += (path ? '>' : '') + node.nodeName;
|
path += (path ? '>' : '') + node.nodeName;
|
||||||
if (node.id) {
|
if (node.id) {
|
||||||
path += '#' + node.id;
|
path += '#' + node.id;
|
||||||
|
|
@ -395,7 +396,7 @@ const
|
||||||
frags.push(empty(child));
|
frags.push(empty(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (child.nodeType === ELEMENT_NODE) {
|
else if (isElement(child)) {
|
||||||
child.append(...frags.reverse());
|
child.append(...frags.reverse());
|
||||||
frags = [];
|
frags = [];
|
||||||
_mergeInlines(child, fakeRange);
|
_mergeInlines(child, fakeRange);
|
||||||
|
|
@ -407,7 +408,7 @@ const
|
||||||
if (node.nodeType === TEXT_NODE) {
|
if (node.nodeType === TEXT_NODE) {
|
||||||
node = node.parentNode;
|
node = node.parentNode;
|
||||||
}
|
}
|
||||||
if (node.nodeType === ELEMENT_NODE) {
|
if (isElement(node)) {
|
||||||
let fakeRange = {
|
let fakeRange = {
|
||||||
startContainer: range.startContainer,
|
startContainer: range.startContainer,
|
||||||
startOffset: range.startOffset,
|
startOffset: range.startOffset,
|
||||||
|
|
@ -425,7 +426,7 @@ const
|
||||||
let parent, last, offset;
|
let parent, last, offset;
|
||||||
while ((parent = container.parentNode) &&
|
while ((parent = container.parentNode) &&
|
||||||
parent !== root &&
|
parent !== root &&
|
||||||
parent.nodeType === ELEMENT_NODE &&
|
isElement(parent) &&
|
||||||
parent.childNodes.length === 1) {
|
parent.childNodes.length === 1) {
|
||||||
container = parent;
|
container = parent;
|
||||||
}
|
}
|
||||||
|
|
@ -485,7 +486,7 @@ const
|
||||||
|
|
||||||
getNodeBefore = (node, offset) => {
|
getNodeBefore = (node, offset) => {
|
||||||
let children = node.childNodes;
|
let children = node.childNodes;
|
||||||
while (offset && node.nodeType === ELEMENT_NODE) {
|
while (offset && isElement(node)) {
|
||||||
node = children[ offset - 1 ];
|
node = children[ offset - 1 ];
|
||||||
children = node.childNodes;
|
children = node.childNodes;
|
||||||
offset = children.length;
|
offset = children.length;
|
||||||
|
|
@ -494,7 +495,7 @@ const
|
||||||
},
|
},
|
||||||
|
|
||||||
getNodeAfter = (node, offset) => {
|
getNodeAfter = (node, offset) => {
|
||||||
if (node.nodeType === ELEMENT_NODE) {
|
if (isElement(node)) {
|
||||||
let children = node.childNodes;
|
let children = node.childNodes;
|
||||||
if (offset < children.length) {
|
if (offset < children.length) {
|
||||||
node = children[ offset ];
|
node = children[ offset ];
|
||||||
|
|
@ -1221,7 +1222,7 @@ const
|
||||||
// Focus cursor
|
// Focus cursor
|
||||||
// If there's a <b>/<i> etc. at the beginning of the split
|
// If there's a <b>/<i> etc. at the beginning of the split
|
||||||
// make sure we focus inside it.
|
// make sure we focus inside it.
|
||||||
while (nodeAfterSplit.nodeType === ELEMENT_NODE) {
|
while (isElement(nodeAfterSplit)) {
|
||||||
let child = nodeAfterSplit.firstChild,
|
let child = nodeAfterSplit.firstChild,
|
||||||
next;
|
next;
|
||||||
|
|
||||||
|
|
@ -1525,7 +1526,7 @@ const
|
||||||
child;
|
child;
|
||||||
while (l--) {
|
while (l--) {
|
||||||
child = children[l];
|
child = children[l];
|
||||||
if (child.nodeType === ELEMENT_NODE && !isLeaf(child)) {
|
if (isElement(child) && !isLeaf(child)) {
|
||||||
removeEmptyInlines(child);
|
removeEmptyInlines(child);
|
||||||
if (!child.firstChild && isInline(child)) {
|
if (!child.firstChild && isInline(child)) {
|
||||||
child.remove();
|
child.remove();
|
||||||
|
|
@ -1538,7 +1539,7 @@ const
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
notWSTextNode = node => node.nodeType === ELEMENT_NODE ? node.nodeName === 'BR' : notWS.test(node.data),
|
notWSTextNode = node => isElement(node) ? node.nodeName === 'BR' : notWS.test(node.data),
|
||||||
isLineBreak = (br, isLBIfEmptyBlock) => {
|
isLineBreak = (br, isLBIfEmptyBlock) => {
|
||||||
let walker, block = br.parentNode;
|
let walker, block = br.parentNode;
|
||||||
while (isInline(block)) {
|
while (isInline(block)) {
|
||||||
|
|
@ -2139,7 +2140,7 @@ let keyHandlers = {
|
||||||
moveRangeBoundariesUpTree(range, root, root, root);
|
moveRangeBoundariesUpTree(range, root, root, root);
|
||||||
cursorContainer = range.endContainer;
|
cursorContainer = range.endContainer;
|
||||||
cursorOffset = range.endOffset;
|
cursorOffset = range.endOffset;
|
||||||
if (cursorContainer.nodeType === ELEMENT_NODE) {
|
if (isElement(cursorContainer)) {
|
||||||
nodeAfterCursor = cursorContainer.childNodes[ cursorOffset ];
|
nodeAfterCursor = cursorContainer.childNodes[ cursorOffset ];
|
||||||
if (nodeAfterCursor?.nodeName === 'IMG') {
|
if (nodeAfterCursor?.nodeName === 'IMG') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -2660,15 +2661,15 @@ class Squire
|
||||||
if (range) {
|
if (range) {
|
||||||
let anchor = range.startContainer,
|
let anchor = range.startContainer,
|
||||||
focus = range.endContainer,
|
focus = range.endContainer,
|
||||||
newPath;
|
newPath, node;
|
||||||
if (force || anchor !== this._lastAnchorNode || focus !== this._lastFocusNode) {
|
if (force || anchor !== this._lastAnchorNode || focus !== this._lastFocusNode) {
|
||||||
this._lastAnchorNode = anchor;
|
this._lastAnchorNode = anchor;
|
||||||
this._lastFocusNode = focus;
|
this._lastFocusNode = focus;
|
||||||
newPath = (anchor && focus) ? (anchor === focus ?
|
node = anchor === focus ? focus : null;
|
||||||
getPath(focus, this._root) : '(selection)') : '';
|
newPath = (anchor && focus) ? (node ? getPath(focus, this._root) : '(selection)') : '';
|
||||||
if (this._path !== newPath) {
|
if (this._path !== newPath) {
|
||||||
this._path = newPath;
|
this._path = newPath;
|
||||||
this.fireEvent('pathChange', { path: newPath });
|
this.fireEvent('pathChange', { path: newPath, element: isElement(node) ? node : node.parentElement });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.fireEvent(range.collapsed ? 'cursor' : 'select', {
|
this.fireEvent(range.collapsed ? 'cursor' : 'select', {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue