Warning, /office/klevernotes/src/contents/ui/textEditor/TextDisplay.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2023 Louis Schul <schul9louis@gmail.com> 0002 // SPDX-License-Identifier: GPL-3.0-or-later 0003 0004 // ORIGINALLY BASED ON : https://github.com/CrazyCxl/markdown-editor 0005 // SPDX-FileCopyrightText: 2019 CrazyCxl <chenxiaolong0001@gmail.com> 0006 0007 import QtQuick 2.2 0008 import QtQuick.Controls 2.2 0009 import QtWebChannel 1.0 0010 import QtWebEngine 1.10 0011 import QtQuick.Layouts 1.15 0012 import Qt.labs.platform 1.1 0013 0014 import org.kde.kirigami 2.19 as Kirigami 0015 0016 import org.kde.Klever 1.0 0017 0018 RowLayout { 0019 id: root 0020 0021 required property string path 0022 required property string text 0023 0024 // Syntax highlight 0025 readonly property bool highlightEnabled: Config.codeSynthaxHighlightEnabled // give us acces to a "Changed" signal 0026 readonly property string highlighterStyle: Config.codeSynthaxHighlighterStyle // This will also be triggered when the highlighter itself is changed 0027 // NoteMapper 0028 readonly property bool noteMapEnabled: Config.noteMapEnabled // give us acces to a "Changed" signal 0029 readonly property NoteMapper noteMapper: applicationWindow().noteMapper 0030 // Emoji 0031 readonly property bool emojiEnabled: Config.quickEmojiEnabled 0032 readonly property string emojiTone: Config.emojiTone 0033 // PlantUML 0034 readonly property bool pumlEnabled: Config.pumlEnabled 0035 readonly property bool pumlDark: Config.pumlDark 0036 0037 readonly property Parser parser: parser 0038 readonly property string stylePath: Config.stylePath 0039 readonly property var codeFontInfo: KleverUtility.fontInfo(Config.codeFont) 0040 readonly property var viewFontInfo: KleverUtility.fontInfo(Config.viewFont) 0041 readonly property string previewLocation: StandardPaths.writableLocation(StandardPaths.TempLocation)+"/pdf-preview.pdf" 0042 readonly property string emptyPreview: (StandardPaths.writableLocation(StandardPaths.TempLocation)+"/empty.pdf").substring(7) 0043 readonly property var defaultCSS: { 0044 '--bodyColor': Config.viewBodyColor !== "None" ? Config.viewBodyColor : Kirigami.Theme.backgroundColor, 0045 '--font': viewFontInfo.family, 0046 '--fontSize': viewFontInfo.pointSize + "px", 0047 '--textColor': Config.viewTextColor !== "None" ? Config.viewTextColor : Kirigami.Theme.textColor, 0048 '--titleColor': Config.viewTitleColor !== "None" ? Config.viewTitleColor : Kirigami.Theme.disabledTextColor, 0049 '--linkColor': Config.viewLinkColor !== "None" ? Config.viewLinkColor : Kirigami.Theme.linkColor, 0050 '--visitedLinkColor': Config.viewVisitedLinkColor !== "None" ? Config.viewVisitedLinkColor : Kirigami.Theme.visitedLinkColor, 0051 '--codeColor': Config.viewCodeColor !== "None" ? Config.viewCodeColor : Kirigami.Theme.alternateBackgroundColor, 0052 '--highlightColor': Config.viewHighlightColor !== "None" ? Config.viewHighlightColor : Kirigami.Theme.highlightColor, 0053 '--codeFont': codeFontInfo.family, 0054 '--codeFontSize': codeFontInfo.pointSize + "px", 0055 } 0056 0057 property string defaultHtml 0058 property string parsedHtml 0059 property string cssStyle 0060 property string completCss 0061 property bool printBackground: true 0062 property bool isInit: false 0063 0064 spacing: 0 0065 0066 Kirigami.Theme.colorSet: Kirigami.Theme.View 0067 Kirigami.Theme.inherit: false 0068 0069 onPathChanged: { 0070 parser.notePath = path 0071 } 0072 onTextChanged: { 0073 root.parseText() 0074 } 0075 onHighlightEnabledChanged: { 0076 root.parseText() 0077 } 0078 onHighlighterStyleChanged: { 0079 parser.newHighlightStyle() 0080 root.parseText() 0081 } 0082 onNoteMapEnabledChanged: { 0083 root.parseText() 0084 } 0085 onEmojiEnabledChanged: { 0086 root.parseText() 0087 } 0088 onEmojiToneChanged: { 0089 root.parseText() 0090 } 0091 onPumlEnabledChanged: { 0092 root.parseText() 0093 } 0094 onPumlDarkChanged: { 0095 parser.pumlDarkChanged() 0096 root.parseText() 0097 } 0098 onDefaultCSSChanged: if (web_view.loadProgress === 100) { 0099 changeStyle({}) 0100 } 0101 onStylePathChanged: if (web_view.loadProgress === 100) { 0102 loadStyle() 0103 } 0104 0105 Kirigami.Card { 0106 id: background 0107 0108 Layout.fillWidth: true 0109 Layout.fillHeight: true 0110 0111 WebEngineView { 0112 id: web_view 0113 0114 x: 2 0115 y: 2 0116 width: background.width - 4 0117 height: background.height - 4 0118 0119 settings { 0120 showScrollBars: false 0121 localContentCanAccessFileUrls: true 0122 localContentCanAccessRemoteUrls: true 0123 } 0124 focus: true 0125 backgroundColor: "transparent" 0126 0127 onJavaScriptConsoleMessage: function (level, message, lineNumber, sourceID) { 0128 console.error('WEB:', message, lineNumber, sourceID) 0129 } 0130 onPdfPrintingFinished: { 0131 const printingPage = applicationWindow().pageStack.currentItem 0132 0133 printingPage.displayPdf() 0134 } 0135 onLoadProgressChanged: if (loadProgress === 100) { 0136 if (!root.isInit) { 0137 loadStyle() 0138 root.isInit = true 0139 updateHtml() 0140 } 0141 0142 scrollToHeader() 0143 } 0144 onScrollPositionChanged: if (!vbar.active) { 0145 vbar.position = scrollPosition.y / contentsSize.height 0146 } 0147 onNavigationRequested: function(request) { 0148 const url = request.url.toString() 0149 if (url.startsWith("http")) { 0150 Qt.openUrlExternally(request.url) 0151 request.action = WebEngineNavigationRequest.IgnoreRequest 0152 return 0153 } 0154 if (url.startsWith("file:///")) { 0155 let notePath = url.substring(7) 0156 const delimiterIndex = notePath.lastIndexOf("@HEADER@") 0157 const header = notePath.substring(delimiterIndex + 8) 0158 0159 notePath = notePath.substring(0, delimiterIndex) 0160 0161 const headerInfo = applicationWindow().noteMapper.getCleanedHeaderAndLevel(header) 0162 const sidebar = applicationWindow().globalDrawer 0163 const noteModelIndex = sidebar.treeModel.getNoteModelIndex(notePath) 0164 0165 if (noteModelIndex.row !== -1) { 0166 if (header[1] !== 0) parser.headerInfo = headerInfo 0167 0168 sidebar.askForFocus(noteModelIndex) 0169 } 0170 else { 0171 notePath = notePath.replace(".BaseCategory", Config.categoryDisplayName).replace(".BaseGroup/", "") 0172 showPassiveNotification(i18nc("@notification, error message %1 is a path", "%1 doesn't exists", notePath)) 0173 } 0174 request.action = WebEngineNavigationRequest.IgnoreRequest 0175 return 0176 } 0177 } 0178 } 0179 } 0180 0181 ScrollBar { 0182 id: vbar 0183 0184 size: background.height / web_view.contentsSize.height 0185 active: hovered || pressed 0186 snapMode: ScrollBar.SnapAlways 0187 orientation: Qt.Vertical 0188 hoverEnabled: true 0189 0190 Layout.row :0 0191 Layout.column: 1 0192 Layout.fillHeight: true 0193 0194 onPositionChanged: { 0195 if (active) { 0196 let scrollY = web_view.contentsSize.height * vbar.position 0197 web_view.runJavaScript("window.scrollTo(0," + scrollY + ")") 0198 } 0199 } 0200 } 0201 0202 function updateHtml() { 0203 if (!root.defaultHtml) root.defaultHtml = DocumentHandler.readFile(":/index.html") 0204 0205 let customHtml = '<style>\n' 0206 + root.completCss 0207 + '</style>\n' 0208 + parsedHtml 0209 0210 let defaultHtml = root.defaultHtml 0211 const finishedHtml = defaultHtml.replace("INSERT HTML HERE", customHtml) 0212 0213 web_view.loadHtml(finishedHtml, "file:/") 0214 } 0215 0216 Parser { 0217 id: parser 0218 0219 onNewLinkedNotesInfos: function(linkedNotesInfos) { 0220 noteMapper.addLinkedNotesInfos(linkedNotesInfos) 0221 } 0222 onNoteHeadersSent: function(notePath, noteHeaders) { 0223 noteMapper.updatePathInfo(notePath, noteHeaders) 0224 } 0225 } 0226 0227 function parseText() { 0228 parsedHtml = parser.parse(text) 0229 updateHtml() 0230 } 0231 0232 function changeStyle(styleDict) { 0233 if (!styleDict) return 0234 const emptyDict = Object.keys(styleDict).length === 0; 0235 styleDict = emptyDict ? defaultCSS : styleDict 0236 0237 let varStartIndex 0238 let varEndIndex 0239 let newCssVar = "" 0240 let noBg 0241 let style = root.cssStyle 0242 0243 for (const [cssVar, value] of Object.entries(styleDict)) { 0244 noBg = cssVar === "--bodyColor" && !root.printBackground 0245 0246 varStartIndex = style.indexOf(cssVar) 0247 if (-1 < varStartIndex) { 0248 varEndIndex = style.indexOf(";", varStartIndex) 0249 0250 newCssVar = noBg 0251 ? cssVar + ": " + "undefined" + ";\n" 0252 : cssVar + ": " + value + ";\n" 0253 0254 style = style.substring(0, varStartIndex) + newCssVar + style.substring(varEndIndex) 0255 } 0256 } 0257 0258 root.completCss = style 0259 updateHtml() 0260 } 0261 0262 function loadStyle() { 0263 root.cssStyle = DocumentHandler.getCssStyle(root.stylePath) 0264 changeStyle({}) 0265 } 0266 0267 function makePdf() { 0268 web_view.printToPdf(root.previewLocation.replace("file://","")) 0269 } 0270 0271 function scrollToHeader() { 0272 if (parser.headerLevel !== "0") { 0273 web_view.runJavaScript("document.getElementById('noteMapperScrollTo')",function(result) { 0274 if (result) { // Seems redundant but it's mandatory due to the way the wayview handle loadProgress 0275 web_view.runJavaScript("document.getElementById('noteMapperScrollTo').scrollIntoView()") 0276 parser.headerInfo = ["", "0"] 0277 } 0278 }) 0279 } 0280 } 0281 }