20import QtQuick.Controls.Suru 2.2
21import Lomiri.Components 1.3
22import Lomiri.Components.Popups 1.3
23import Dekko.Components 1.0
25import Dekko.Mail.API 1.0
26import Dekko.Mail.Stores.Composer 1.0
27import Dekko.Markdown 1.0
28import Dekko.Lomiri.Constants 1.0
32 property bool pendingHtmlToPlainConversion: false
33 property bool wasSwitchedToPlain: false
35 function plainTextToHtml(text) {
36 return '<p>
' + (text || "")
37 .replace(/&/g, '&
')
38 .replace(/</g, '<
')
39 .replace(/>/g, '>
')
40 .replace(/"/g, '"
')
41 .replace(/'/g,
''')
42 .replace(/\n/g,
'<br>') +
'</p>'
45 function hasValidHtmlContent(content) {
46 if (!content || content.trim().length === 0) {
49 return content !==
"<br>" && content !==
"<p><br></p>" && content !==
"<br/>"
54 color: Suru.backgroundColor
59 property:
"bodyDocument"
60 value: me.textDocument
63 Component.onCompleted: {
64 if (ComposerStore.composeMode ===
"html") {
66 if (hasValidHtmlContent(ComposerStore.htmlContent)) {
67 htmlEditorContainer.setHtmlDocument(ComposerStore.htmlContent)
69 const plainText = me.text ||
""
70 if (plainText.trim()) {
71 const wrappedHtml = plainTextToHtml(plainText)
72 htmlEditorContainer.setHtmlDocument(wrappedHtml)
73 ComposerStore.htmlContent = wrappedHtml
79 Component.onDestruction: {
80 pendingHtmlToPlainConversion =
false
81 if (htmlEditorContainer) {
82 htmlEditorContainer.isEditorLoaded =
false
87 target: ComposerStore.sendInProgress ? null : ComposerStore
88 onComposeModeChanged: {
89 if (ComposerStore.sendInProgress) {
92 if (ComposerStore.composeMode ===
"html") {
94 pendingHtmlToPlainConversion =
false
96 if (wasSwitchedToPlain) {
97 const plainText = me.text ||
""
98 const wrappedHtml = plainTextToHtml(plainText)
99 htmlEditorContainer.setHtmlDocument(wrappedHtml)
100 ComposerStore.htmlContent = wrappedHtml
101 wasSwitchedToPlain =
false
102 }
else if (hasValidHtmlContent(ComposerStore.htmlContent)) {
103 htmlEditorContainer.setHtmlDocument(ComposerStore.htmlContent);
105 const plainText = me.text ||
""
106 if (plainText.trim()) {
107 const wrappedHtml = plainTextToHtml(plainText)
108 htmlEditorContainer.setHtmlDocument(wrappedHtml)
109 ComposerStore.htmlContent = wrappedHtml
114 wasSwitchedToPlain =
true
115 if (hasValidHtmlContent(ComposerStore.htmlContent)) {
116 me.text = ComposerStore.builder.htmlToPlainText(ComposerStore.htmlContent)
118 if (htmlEditorContainer.editor) {
119 pendingHtmlToPlainConversion =
true
120 htmlEditorContainer.editor.requestPlainText()
122 pendingHtmlToPlainConversion =
false
127 onHtmlContentChanged: {
128 if (ComposerStore.sendInProgress) {
131 if (ComposerStore.composeMode ===
"html" && htmlEditorContainer.visible) {
132 if (hasValidHtmlContent(ComposerStore.htmlContent)) {
134 if (!htmlEditorContainer.isInternallyUpdating && ComposerStore.htmlContent !== htmlEditorContainer.currentDocument) {
135 htmlEditorContainer.setHtmlDocument(ComposerStore.htmlContent)
143 target: htmlEditorContainer.editor
144 onPlainTextReady: function(text) {
145 if (pendingHtmlToPlainConversion && ComposerStore.composeMode ===
"plain") {
146 const plain = (text ||
"").trim()
147 if (plain.length > 0 || !hasValidHtmlContent(ComposerStore.htmlContent)) {
150 pendingHtmlToPlainConversion =
false
171 recipientType: RecipientType.To
172 recipientModel: ComposerStore.recipients.to
180 visible: ComposerStore.showCC || ComposerStore.recipients.cc.count
181 recipientType: RecipientType.Cc
182 recipientModel: ComposerStore.recipients.cc
190 visible: ComposerStore.showBCC || ComposerStore.recipients.bcc.count
191 recipientType: RecipientType.Bcc
192 recipientModel: ComposerStore.recipients.bcc
210 height: parent.height - composerHeader.height
215 frameSpacing: units.gu(2)
217 visible: ComposerStore.composeMode ===
"plain"
222 id: htmlEditorContainer
224 visible: ComposerStore.composeMode ===
"html"