Initial WinUI switch.

This commit is contained in:
Burak Kaan Köse
2025-09-29 11:16:14 +02:00
parent f9c53ca2c9
commit e67b893ae4
345 changed files with 22458 additions and 746 deletions
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="language" content="english">
<script src="./libs/jodit.min.js"></script>
<script src="./libs/darkreader.js"></script>
<link rel="stylesheet" href="./libs/jodit.min.css" />
<link rel="stylesheet" href="./global.css" />
<style>
.jodit-toolbar-button__trigger svg > path {
fill: black;
}
.jodit-container:not(.jodit_inline) {
background-color: transparent;
border: none;
border-radius: initial;
}
/* Hide taskbar in css. Should not be hidden from configuration, because it's used to sync state with native buttons. */
.jodit-toolbar__box {
display: none;
}
html, body, .jodit-container, .jodit-workplace {
height: 100%;
}
</style>
</head>
<body>
<meta name="color-scheme" content="dark light">
<textarea id="editor" name="editor"></textarea>
<!-- hidden input to handle image uploads -->
<input type="file" id="imageInput" style="display:none;">
<script src="/editor.js"></script>
</body>
</html>
+130
View File
@@ -0,0 +1,130 @@
const joditConfig = {
"useSearch": false,
"toolbar": true,
"buttons": "bold,italic,underline,strikethrough,brush,ul,ol,font,fontsize,paragraph,image,link,indent,outdent,align,lineHeight,table",
"inline": true,
"toolbarAdaptive": false,
"toolbarInlineForSelection": false,
"showCharsCounter": false,
"showWordsCounter": false,
"showXPathInStatusbar": false,
"link": {
"processVideoLink": false
},
"disablePlugins": "add-new-line,backspace",
"showPlaceholder": false,
"uploader": {
"insertImageAsBase64URI": true
},
"enter": "DIV"
}
// This method should be called first all the time.
function initializeJodit(fonts, defaultComposerFont, defaultComposerFontSize, defaultReaderFont, defaultReaderFontSize) {
const fontsWithFallabckObject = fonts.reduce((acc, font) => { acc[`'${font}',Arial,sans-serif`] = font; return acc; }, {});
const mergedConfig = {
...joditConfig,
controls: {
font: {
list: Jodit.atom(fontsWithFallabckObject)
}
},
style: { font: `${defaultReaderFontSize}px ${defaultReaderFont}` },
}
Jodit.plugins.add('inlineFonts', jodit => {
jodit.events.on('afterEnter', e => {
const current = jodit.selection.current().parentNode;
current.style.fontFamily = `'${defaultComposerFont}',Arial,sans-serif`;
current.style.fontSize = `${defaultComposerFontSize}px`;
});
});
// Don't add const/let/var here, it should be global
editor = Jodit.make("#editor", mergedConfig);
// Handle the image input change event
imageInput.addEventListener('change', () => {
const file = imageInput.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (event) {
const base64Image = event.target.result;
insertImages([{ data: base64Image, name: file.name }]);
};
reader.readAsDataURL(file);
}
});
// Listeners for button events
const disabledButtons = ["indent", "outdent"];
const ariaPressedButtons = ["bold", "italic", "underline", "strikethrough", "ul", "ol"];
const alignmentButton = document.querySelector(`[ref='left']`).firstChild.firstChild;
const alignmentObserver = new MutationObserver(function () {
const value = alignmentButton.firstChild.getAttribute('class').split(' ')[0];
window.chrome.webview.postMessage({ type: 'alignment', value: value });
});
alignmentObserver.observe(alignmentButton, { childList: true, attributes: true, attributeFilter: ["class"] });
const ariaObservers = ariaPressedButtons.map(button => {
const buttonContainer = document.querySelector(`[ref='${button}']`);
const observer = new MutationObserver(function () { pressedChanged(buttonContainer) });
observer.observe(buttonContainer.firstChild, { attributes: true, attributeFilter: ["aria-pressed"] });
return observer;
});
const disabledObservers = disabledButtons.map(button => {
const buttonContainer = document.querySelector(`[ref='${button}']`);
const observer = new MutationObserver(function () { disabledButtonChanged(buttonContainer) });
observer.observe(buttonContainer.firstChild, { attributes: true, attributeFilter: ["disabled"] });
return observer;
});
function pressedChanged(buttonContainer) {
const ref = buttonContainer.getAttribute('ref');
const value = buttonContainer.firstChild.getAttribute('aria-pressed');
window.chrome.webview.postMessage({ type: ref, value: value });
}
function disabledButtonChanged(buttonContainer) {
const ref = buttonContainer.getAttribute('ref');
const value = buttonContainer.firstChild.getAttribute('disabled');
window.chrome.webview.postMessage({ type: ref, value: value });
}
}
function RenderHTML(htmlString) {
editor.s.insertHTML(htmlString);
editor.synchronizeValues();
}
function GetHTMLContent() {
return editor.value;
}
function SetLightEditor() {
DarkReader.disable();
}
function SetDarkEditor() {
DarkReader.enable();
}
function toggleToolbar(enable) {
const toolbar = document.querySelector('.jodit-toolbar__box');
if (enable) {
toolbar.style.display = 'flex';
}
else {
toolbar.style.display = 'none';
}
}
function insertImages(imagesInfo) {
imagesInfo.forEach(imageInfo => {
editor.selection.insertHTML(`<img src="${imageInfo.data}" alt="${imageInfo.name}">`);
});
};
+4
View File
@@ -0,0 +1,4 @@
* {
scrollbar-color: auto !important;
scrollbar-width: thin !important;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
var linkifyElement=function(e){"use strict";const t=1,n=3;function r(e,t,n){let r=n[n.length-1];e.replaceChild(r,t);for(let t=n.length-2;t>=0;t--)e.insertBefore(n[t],r),r=n[t]}function i(e,t,n){const r=[];for(let i=0;i<e.length;i++){const o=e[i];"nl"===o.t&&t.get("nl2br")?r.push(n.createElement("br")):o.isLink&&t.check(o)?r.push(t.render(o)):r.push(n.createTextNode(o.toString()))}return r}function o(l,a,c){if(!l||l.nodeType!==t)throw new Error(`Cannot linkify ${l} - Invalid DOM Node type`);if("A"===l.tagName||a.ignoreTags.indexOf(l.tagName)>=0)return l;let s=l.firstChild;for(;s;){let d,u,f;switch(s.nodeType){case t:o(s,a,c);break;case n:if(d=s.nodeValue,u=e.tokenize(d),0===u.length||1===u.length&&"text"===u[0].t)break;f=i(u,a,c),r(l,s,f),s=f[f.length-1]}s=s.nextSibling}return l}function l(e){return t=>{let{tagName:n,attributes:r,content:i,eventListeners:o}=t;const l=e.createElement(n);for(const e in r)l.setAttribute(e,r[e]);if(o&&l.addEventListener)for(const e in o)l.addEventListener(e,o[e]);return l.appendChild(e.createTextNode(i)),l}}function a(t,n,r){void 0===n&&(n=null),void 0===r&&(r=null);try{r=r||document||window&&window.document||global&&global.document}catch(e){}if(!r)throw new Error("Cannot find document implementation. If you are in a non-browser environment like Node.js, pass the document implementation as the third argument to linkifyElement.");return o(t,new e.Options(n,l(r)),r)}return a.helper=o,a.getDefaultRender=l,a.normalize=(t,n)=>new e.Options(t,l(n)),a}(linkify);
File diff suppressed because one or more lines are too long
+116
View File
@@ -0,0 +1,116 @@
<html>
<head>
<link rel="stylesheet" href="./global.css" />
<script src="./libs/darkreader.js"></script>
<script src="./libs/linkify.min.js"></script>
<script src="./libs/linkify-element.min.js"></script>
<style>
body {
padding-left: 12px;
padding-right: 12px;
padding-top: 8px;
padding-bottom: 8px;
margin: 0px;
border-radius: 8px;
}
#readerDiv {
font-family: Arial, Helvetica, sans-serif;
background-color: transparent !important;
}
a.wino-plain-link {
color: inherit !important;
text-decoration: underline dotted !important;
}
</style>
</head>
<body>
<meta name="color-scheme" content="dark light" />
<script>
var _htmlString = "";
var _shouldLinkifyText = true;
// Called when rendering a new email for the first time
function RenderHTML(htmlString, shouldLinkifyText = true) {
// Reset scroll to top
window.scroll(0, 0);
// Clear any existing selection
window.getSelection().removeAllRanges();
_htmlString = htmlString;
_shouldLinkifyText = shouldLinkifyText;
internalRenderHTML(htmlString);
}
// Called to render or refresh the email
function internalRenderHTML(htmlString) {
var containerDiv = document.getElementById("readerDiv");
try {
containerDiv.innerHTML = htmlString;
// Linkify plain text links if enabled
if (_shouldLinkifyText) {
linkifyElement(
containerDiv,
{ className: "wino-plain-link" },
document
);
}
// Remove !important from inline styles if dark mode is enabled
if (
document.documentElement.getAttribute("data-theme") ===
"dark"
) {
removeImportantFromInlineStyles();
}
} catch (e) {
containerDiv.innerHTML = htmlString;
}
}
function ChangeFontFamily(fontFamily) {
var containerDiv = document.getElementById("readerDiv");
containerDiv.style.fontFamily = fontFamily;
}
function ChangeFontSize(size) {
var containerDiv = document.getElementById("readerDiv");
containerDiv.style.fontSize = size;
}
function SetLightEditor() {
document.documentElement.setAttribute("data-theme", "light");
DarkReader.disable();
internalRenderHTML(_htmlString);
}
function SetDarkEditor() {
document.documentElement.setAttribute("data-theme", "dark");
DarkReader.enable();
internalRenderHTML(_htmlString);
}
// Helper functions
function removeImportantFromInlineStyles() {
var allElements = document.querySelectorAll("*");
allElements.forEach(function (element) {
var style = element.getAttribute("style");
if (style) {
var newStyle = style.replace(/!important/g, "");
element.setAttribute("style", newStyle);
}
});
}
</script>
<div id="readerDiv"></div>
</body>
</html>