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 }