diff --git a/dev/Common/Html.js b/dev/Common/Html.js index 0e8029fbd..0be300ec9 100644 --- a/dev/Common/Html.js +++ b/dev/Common/Html.js @@ -360,7 +360,7 @@ export const }); */ - isMsg && [...tmpl.content.querySelectorAll('*')].forEach(oElement => { + [...tmpl.content.querySelectorAll('*')].forEach(oElement => { const name = oElement.tagName, oStyle = oElement.style; @@ -485,71 +485,73 @@ export const */ let skipStyle = false; - value = delAttribute('src'); - if (value) { - if ('IMG' === name) { - oElement.loading = 'lazy'; - let attachment; - if (value.startsWith('cid:')) - { - value = value.slice(4); - setAttribute('data-x-src-cid', value); - attachment = findAttachmentByCid(value); - if (attachment?.download) { - oElement.src = attachment.linkPreview(); - oElement.title += ' ('+attachment.fileName+')'; - attachment.isInline(true); - attachment.isLinked(true); + if (isMsg) { + value = isMsg && delAttribute('src'); + if (value) { + if ('IMG' === name) { + oElement.loading = 'lazy'; + let attachment; + if (value.startsWith('cid:')) + { + value = value.slice(4); + setAttribute('data-x-src-cid', value); + attachment = findAttachmentByCid(value); + if (attachment?.download) { + oElement.src = attachment.linkPreview(); + oElement.title += ' ('+attachment.fileName+')'; + attachment.isInline(true); + attachment.isLinked(true); + } } - } - else if ((attachment = findLocationByCid(value))) - { - if (attachment.download) { - oElement.src = attachment.linkPreview(); - attachment.isLinked(true); + else if ((attachment = findLocationByCid(value))) + { + if (attachment.download) { + oElement.src = attachment.linkPreview(); + attachment.isLinked(true); + } } - } - else if (detectHiddenImages - && ((oStyle.maxHeight && 3 > pInt(oStyle.maxHeight)) // TODO: issue with 'in' - || (oStyle.maxWidth && 3 > pInt(oStyle.maxWidth)) // TODO: issue with 'in' - || (oStyle.width && 2 > pInt(oStyle.width)) - || [ - 'email.microsoftemail.com/open', - 'github.com/notifications/beacon/', - '/track/open', // mandrillapp.com list-manage.com - 'google-analytics.com' - ].filter(uri => value.toLowerCase().includes(uri)).length - )) { - skipStyle = true; - oStyle.display = 'none'; -// setAttribute('style', 'display:none'); - setAttribute('data-x-src-hidden', value); -// result.tracking = true; - } - else if (httpre.test(value)) - { - let src = stripTracking(value); - if (src != value) { - result.tracking = true; - setAttribute('data-x-src-tracking', value); + else if (detectHiddenImages + && ((oStyle.maxHeight && 3 > pInt(oStyle.maxHeight)) // TODO: issue with 'in' + || (oStyle.maxWidth && 3 > pInt(oStyle.maxWidth)) // TODO: issue with 'in' + || (oStyle.width && 2 > pInt(oStyle.width)) + || [ + 'email.microsoftemail.com/open', + 'github.com/notifications/beacon/', + '/track/open', // mandrillapp.com list-manage.com + 'google-analytics.com' + ].filter(uri => value.toLowerCase().includes(uri)).length + )) { + skipStyle = true; + oStyle.display = 'none'; + // setAttribute('style', 'display:none'); + setAttribute('data-x-src-hidden', value); + // result.tracking = true; + } + else if (httpre.test(value)) + { + let src = stripTracking(value); + if (src != value) { + result.tracking = true; + setAttribute('data-x-src-tracking', value); + } + setAttribute('data-x-src', src); + result.hasExternals = true; + oElement.alt || (oElement.alt = src.replace(/^.+\/([^/?]+).*$/, '$1').slice(-20)); + } + else if (value.startsWith('data:image/')) + { + oElement.src = value; + } + else + { + setAttribute('data-x-src-broken', value); } - setAttribute('data-x-src', src); - result.hasExternals = true; - oElement.alt || (oElement.alt = src.replace(/^.+\/([^/?]+).*$/, '$1').slice(-20)); - } - else if (value.startsWith('data:image/')) - { - oElement.src = value; } else { setAttribute('data-x-src-broken', value); } } - else - { - setAttribute('data-x-src-broken', value); - } } if (hasAttribute('background')) { diff --git a/dev/External/SquireUI.js b/dev/External/SquireUI.js index fe07975d2..b1e50fcad 100644 --- a/dev/External/SquireUI.js +++ b/dev/External/SquireUI.js @@ -386,6 +386,44 @@ class SquireUI changes.redo.input.disabled = !e.detail.canRedo; }); + squire.addEventListener('pasteImage', e => { + const items = e.detail.clipboardData.items; + let l = items.length; + while (l--) { + const item = items[l]; + if (/^image\/(png|jpeg|webp)/.test(item.type)) { + let reader = new FileReader(); + reader.onload = event => { + let img = createElement("img"), + canvas = createElement("canvas"), + ctx = canvas.getContext('2d'); + img.onload = ()=>{ + ctx.drawImage(img, 0, 0); + let width = img.width, height = img.height; + if (width > height) { + // Landscape + if (width > 1024) { + height = height * 1024 / width; + width = 1024; + } + } else if (height > 1024) { + // Portrait + width = width * 1024 / height; + height = 1024; + } + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + squire.insertHTML('', true); + }; + img.src = event.target.result; + } + reader.readAsDataURL(item.getAsFile()); + break; + } + } + }); + actions.font.fontSize.input.selectedIndex = actions.font.fontSize.defaultValueIndex; // squire.addEventListener('focus', () => shortcuts.off()); diff --git a/vendors/squire2/dist/squire-raw.js b/vendors/squire2/dist/squire-raw.js index 4367a29dd..d69f0abe5 100644 --- a/vendors/squire2/dist/squire-raw.js +++ b/vendors/squire2/dist/squire-raw.js @@ -58,7 +58,7 @@ var notWS = /[^ \t\r\n]/; // source/node/Category.ts - var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:FRAME|MG|NPUT|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/; + var inlineNodeNames = /^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:ATA|EL|FN)|EM|FONT|HR|I(?:MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:AMP|MALL|PAN|TR(?:IKE|ONG)|U[BP])?|TIME|U|VAR|WBR)$/; var leafNodeNames = /* @__PURE__ */ new Set(["BR", "HR", "IMG"]); var UNKNOWN = 0; var INLINE = 1; @@ -198,7 +198,7 @@ // okay if data is 'undefined' here. notWS.test(node.data) ); - var isLineBreak = (br, isLBIfEmptyBlock) => { + var isLineBreak = (br) => { let block = br.parentNode; while (isInline(block)) { block = block.parentNode; @@ -209,7 +209,7 @@ notWSTextNode ); walker.currentNode = br; - return !!walker.nextNode() || isLBIfEmptyBlock && !walker.previousNode(); + return !!walker.nextNode(); }; var removeZWS = (root, keepNode) => { const walker = createTreeWalker(root, SHOW_TEXT); @@ -267,7 +267,7 @@ textChild = prev; } startContainer = textChild; - startOffset = textChild.data.length; + startOffset = textChild.length; } } break; @@ -279,7 +279,7 @@ while (!(endContainer instanceof Text)) { const child = endContainer.childNodes[endOffset - 1]; if (!child || isLeaf(child)) { - if (child && child.nodeName === "BR" && !isLineBreak(child, false)) { + if (child && child.nodeName === "BR" && !isLineBreak(child)) { --endOffset; continue; } @@ -323,7 +323,7 @@ if (endContainer === endMax || endContainer === root) { break; } - if (endContainer.nodeType !== TEXT_NODE && endContainer.childNodes[endOffset] && endContainer.childNodes[endOffset].nodeName === "BR" && !isLineBreak(endContainer.childNodes[endOffset], false)) { + if (endContainer.nodeType !== TEXT_NODE && endContainer.childNodes[endOffset] && endContainer.childNodes[endOffset].nodeName === "BR" && !isLineBreak(endContainer.childNodes[endOffset])) { ++endOffset; } if (endOffset !== getLength(endContainer)) { @@ -529,30 +529,23 @@ if (isInline(child) && !child.firstChild) { node.removeChild(child); } - } else if (child instanceof Text && !child.data) { + } else if (child instanceof Text && !child.length) { node.removeChild(child); } } }; var cleanupBRs = (node) => { - const brs = node.querySelectorAll("BR"); - const brBreaksLine = []; + const brs = node.querySelectorAll("BR:last-child"); let l = brs.length; - for (let i = 0; i < l; ++i) { - brBreaksLine[i] = isLineBreak(brs[i], false); - } while (l--) { const br = brs[l]; - const parent = br.parentNode; - if (parent) { - if (!brBreaksLine[l]) { - detach(br); - } + if (!isLineBreak(br)) { + br.remove(); } } }; var escapeHTML = (text) => { - return text.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join("""); + return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """); }; // source/node/MergeSplit.ts @@ -980,7 +973,7 @@ const iterator = createTreeWalker(root, SHOW_ELEMENT_OR_TEXT); let afterNode = startContainer; let afterOffset = startOffset; - if (!(afterNode instanceof Text) || afterOffset === afterNode.data.length) { + if (!(afterNode instanceof Text) || afterOffset === afterNode.length) { afterNode = getAdjacentInlineNode(iterator, "nextNode", afterNode); afterOffset = 0; } @@ -993,7 +986,7 @@ afterNode || (startContainer instanceof Text ? startContainer : startContainer.childNodes[startOffset] || startContainer) ); if (beforeNode instanceof Text) { - beforeOffset = beforeNode.data.length; + beforeOffset = beforeNode.length; } } let node = null; @@ -3171,7 +3164,7 @@ nodeAfterSplit = child; break; } - while (child && child instanceof Text && !child.data) { + while (child && child instanceof Text && !child.length) { next = child.nextSibling; if (!next || next.nodeName === "BR") { break; @@ -3517,7 +3510,7 @@ const brBreaksLine = []; let l = nodes.length; for (let i = 0; i < l; ++i) { - brBreaksLine[i] = isLineBreak(nodes[i], false); + brBreaksLine[i] = isLineBreak(nodes[i]); } while (l--) { const br = nodes[l];