This commit is contained in:
the-djmaze 2023-05-09 12:07:07 +02:00
parent 216b5964d7
commit 13abe74a31
41 changed files with 219 additions and 116 deletions

View file

@ -19,6 +19,14 @@
height: 100%;
}
.tabs {
height: 100%;
}
.tabs > label > * + * {
margin-left: 0.5em;
}
.textAreaParent, .attachmentAreaParent {
height: 100%;
min-height: 200px;

View file

@ -317,7 +317,7 @@ export class ComposePopupView extends AbstractViewPopup {
attachmentsInProcess: () => this.attachments.filter(item => item && !item.complete()),
attachmentsInError: () => this.attachments.filter(item => item?.error()),
attachmentsCount: () => this.attachments.length,
attachmentsCount: () => this.attachments().length,
attachmentsInErrorCount: () => this.attachmentsInError.length,
attachmentsInProcessCount: () => this.attachmentsInProcess.length,
isDraftFolderMessage: () => this.draftsFolder() && this.draftUid(),
@ -390,6 +390,41 @@ export class ComposePopupView extends AbstractViewPopup {
if (this.attachmentsInProcessError() && arrayLength(value)) {
this.attachmentsInProcessError(false);
}
},
viewArea: value => {
if (!this.mailvelope && 'mailvelope' == value) {
/**
* Creates an iframe with an editor for a new encrypted mail.
* The iframe will be injected into the container identified by selector.
* https://mailvelope.github.io/mailvelope/Editor.html
*/
let text = this.oEditor.getData(),
encrypted = PgpUserStore.isEncrypted(text),
size = SettingsGet('phpUploadSizes')['post_max_size'],
quota = pInt(size);
switch (size.slice(-1)) {
case 'G': quota *= 1024; // fallthrough
case 'M': quota *= 1024; // fallthrough
case 'K': quota *= 1024;
}
// Issue: can't select signing key
// this.pgpSign(this.pgpSign() || confirm('Sign this message?'));
mailvelope.createEditorContainer('#mailvelope-editor', PgpUserStore.mailvelopeKeyring, {
// https://mailvelope.github.io/mailvelope/global.html#EditorContainerOptions
quota: Math.max(2048, (quota / 1024)) - 48, // (text + attachments) limit in kilobytes
armoredDraft: encrypted ? text : '', // Ascii Armored PGP Text Block
predefinedText: encrypted ? '' : (this.oEditor.isHtml() ? htmlToPlain(text) : text),
/*
quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted
quotedMailIndent: true, // if true the quoted mail will be indented (default: true)
quotedMailHeader: '', // header to be added before the quoted mail
keepAttachments: false, // add attachments of quotedMail to editor (default: false)
// Issue: can't select signing key
signMsg: this.pgpSign()
*/
}).then(editor => this.mailvelope = editor);
}
}
});
@ -1276,41 +1311,6 @@ export class ComposePopupView extends AbstractViewPopup {
this.dropMailvelope();
}
mailvelopeArea() {
if (!this.mailvelope) {
/**
* Creates an iframe with an editor for a new encrypted mail.
* The iframe will be injected into the container identified by selector.
* https://mailvelope.github.io/mailvelope/Editor.html
*/
let text = this.oEditor.getData(),
encrypted = PgpUserStore.isEncrypted(text),
size = SettingsGet('phpUploadSizes')['post_max_size'],
quota = pInt(size);
switch (size.slice(-1)) {
case 'G': quota *= 1024; // fallthrough
case 'M': quota *= 1024; // fallthrough
case 'K': quota *= 1024;
}
// Issue: can't select signing key
// this.pgpSign(this.pgpSign() || confirm('Sign this message?'));
mailvelope.createEditorContainer('#mailvelope-editor', PgpUserStore.mailvelopeKeyring, {
// https://mailvelope.github.io/mailvelope/global.html#EditorContainerOptions
quota: Math.max(2048, (quota / 1024)) - 48, // (text + attachments) limit in kilobytes
armoredDraft: encrypted ? text : '', // Ascii Armored PGP Text Block
predefinedText: encrypted ? '' : (this.oEditor.isHtml() ? htmlToPlain(text) : text),
/*
quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted
quotedMailIndent: true, // if true the quoted mail will be indented (default: true)
quotedMailHeader: '', // header to be added before the quoted mail
keepAttachments: false, // add attachments of quotedMail to editor (default: false)
// Issue: can't select signing key
signMsg: this.pgpSign()
*/
}).then(editor => this.mailvelope = editor);
}
this.viewArea('mailvelope');
}
attachmentsArea() {
this.viewArea('attachments');
}

View file

@ -38,7 +38,9 @@
"NO": "لا",
"INACTIVE": "Inactive",
"DEFAULT": "الافتراضي",
"HELP": "المساعدة"
"HELP": "المساعدة",
"TEXT": "النص",
"ATTACHMENTS": "الملحقات"
},
"LOGIN": {
"LABEL_LOGIN": "تسيجيل الدخول",

View file

@ -38,7 +38,9 @@
"NO": "Не",
"INACTIVE": "Inactive",
"DEFAULT": "по подразбиране",
"HELP": "Помощ"
"HELP": "Помощ",
"TEXT": "Текст",
"ATTACHMENTS": "Прикрепени файлове"
},
"LOGIN": {
"LABEL_LOGIN": "Логин",

View file

@ -38,7 +38,9 @@
"NO": "Ne",
"INACTIVE": "Inactive",
"DEFAULT": "výchozí",
"HELP": "Nápověda"
"HELP": "Nápověda",
"TEXT": "Text",
"ATTACHMENTS": "Přílohy"
},
"LOGIN": {
"LABEL_LOGIN": "Uživatelské jméno",

View file

@ -38,7 +38,9 @@
"NO": "Nej",
"INACTIVE": "Inactive",
"DEFAULT": "standard",
"HELP": "Hjælp"
"HELP": "Hjælp",
"TEXT": "Tekst",
"ATTACHMENTS": "Vedhæftninger"
},
"LOGIN": {
"LABEL_LOGIN": "Brugernavn",

View file

@ -38,7 +38,9 @@
"NO": "Nein",
"INACTIVE": "Inaktiv",
"DEFAULT": "Standard",
"HELP": "Hilfe"
"HELP": "Hilfe",
"TEXT": "Text",
"ATTACHMENTS": "Anhänge"
},
"LOGIN": {
"LABEL_LOGIN": "Anmeldung",

View file

@ -38,7 +38,9 @@
"NO": "Όχι",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Βοήθεια"
"HELP": "Βοήθεια",
"TEXT": "Κείμενο",
"ATTACHMENTS": "Συνημμένα"
},
"LOGIN": {
"LABEL_LOGIN": "Είσοδος",

View file

@ -38,7 +38,9 @@
"NO": "No",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Help"
"HELP": "Help",
"TEXT": "Text",
"ATTACHMENTS": "Attachments"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "No",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Help"
"HELP": "Help",
"TEXT": "Text",
"ATTACHMENTS": "Attachments"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "No",
"INACTIVE": "Inactive",
"DEFAULT": "predeterminado",
"HELP": "Ayuda"
"HELP": "Ayuda",
"TEXT": "Texto",
"ATTACHMENTS": "Adjuntos"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "Ei",
"INACTIVE": "Inactive",
"DEFAULT": "vaikimisi",
"HELP": "Abi"
"HELP": "Abi",
"TEXT": "Tekst",
"ATTACHMENTS": "Manused"
},
"LOGIN": {
"LABEL_LOGIN": "Logi sisse",

View file

@ -38,7 +38,9 @@
"NO": "Ez",
"INACTIVE": "Inaktibo",
"DEFAULT": "lehenetsia",
"HELP": "Laguntza"
"HELP": "Laguntza",
"TEXT": "Testua",
"ATTACHMENTS": "Eranskinak"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "خیر",
"INACTIVE": "Inactive",
"DEFAULT": "پیش‌فرض",
"HELP": "راهنما"
"HELP": "راهنما",
"TEXT": "متن",
"ATTACHMENTS": "پیوست‌ها"
},
"LOGIN": {
"LABEL_LOGIN": "ورود",

View file

@ -38,7 +38,9 @@
"NO": "Ei",
"INACTIVE": "Inactive",
"DEFAULT": "oletus",
"HELP": "Ohje"
"HELP": "Ohje",
"TEXT": "Teksti",
"ATTACHMENTS": "Liite"
},
"LOGIN": {
"LABEL_LOGIN": "Tunnus",

View file

@ -38,7 +38,9 @@
"NO": "Non",
"INACTIVE": "Inactive",
"DEFAULT": "défaut",
"HELP": "Aide"
"HELP": "Aide",
"TEXT": "Texte",
"ATTACHMENTS": "Pièces jointes"
},
"LOGIN": {
"LABEL_LOGIN": "Identifiant",

View file

@ -38,7 +38,9 @@
"NO": "Nem",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Súgó"
"HELP": "Súgó",
"TEXT": "Szöveg",
"ATTACHMENTS": "Mellékletek"
},
"LOGIN": {
"LABEL_LOGIN": "Bejelentkezés",

View file

@ -38,7 +38,9 @@
"NO": "Tidak",
"INACTIVE": "Inactive",
"DEFAULT": "Bawaan",
"HELP": "Bantuan"
"HELP": "Bantuan",
"TEXT": "Teks",
"ATTACHMENTS": "Lampiran"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "Nei",
"INACTIVE": "Inactive",
"DEFAULT": "sjálfgefið",
"HELP": "Hjálp"
"HELP": "Hjálp",
"TEXT": "Texti",
"ATTACHMENTS": "Viðhengi"
},
"LOGIN": {
"LABEL_LOGIN": "Innskráning",

View file

@ -38,7 +38,9 @@
"NO": "No",
"INACTIVE": "Inattivo",
"DEFAULT": "predefinito",
"HELP": "Aiuto"
"HELP": "Aiuto",
"TEXT": "Messaggio",
"ATTACHMENTS": "Allegati"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "いいえ",
"INACTIVE": "Inactive",
"DEFAULT": "デフォルト",
"HELP": "ヘルプ"
"HELP": "ヘルプ",
"TEXT": "キーワード",
"ATTACHMENTS": "添付ファイル"
},
"LOGIN": {
"LABEL_LOGIN": "ログイン",

View file

@ -38,7 +38,9 @@
"NO": "아니요",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "도움말"
"HELP": "도움말",
"TEXT": "본문",
"ATTACHMENTS": "첨부파일"
},
"LOGIN": {
"LABEL_LOGIN": "아이디",

View file

@ -38,7 +38,9 @@
"NO": "Ne",
"INACTIVE": "Inactive",
"DEFAULT": "numatytasis",
"HELP": "Pagalba"
"HELP": "Pagalba",
"TEXT": "Laiško Tekstas",
"ATTACHMENTS": "Priedai"
},
"LOGIN": {
"LABEL_LOGIN": "Prisijungimo vardas",

View file

@ -38,7 +38,9 @@
"NO": "Nē",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Palīdzība"
"HELP": "Palīdzība",
"TEXT": "Teksts",
"ATTACHMENTS": "Pielikumi"
},
"LOGIN": {
"LABEL_LOGIN": "Ielogoties",

View file

@ -38,7 +38,9 @@
"NO": "Nei",
"INACTIVE": "Inactive",
"DEFAULT": "Standard",
"HELP": "Hjelp"
"HELP": "Hjelp",
"TEXT": "Tekst",
"ATTACHMENTS": "Vedlegg"
},
"LOGIN": {
"LABEL_LOGIN": "Logg inn",

View file

@ -38,7 +38,9 @@
"NO": "Nee",
"INACTIVE": "Inactief",
"DEFAULT": "standaard",
"HELP": "Help"
"HELP": "Help",
"TEXT": "Tekst",
"ATTACHMENTS": "Bijlagen"
},
"LOGIN": {
"LABEL_LOGIN": "Inlognaam",

View file

@ -38,7 +38,9 @@
"NO": "Nie",
"INACTIVE": "Inactive",
"DEFAULT": "domyślna",
"HELP": "Pomoc"
"HELP": "Pomoc",
"TEXT": "Tekst",
"ATTACHMENTS": "Załączniki"
},
"LOGIN": {
"LABEL_LOGIN": "Login",

View file

@ -38,7 +38,9 @@
"NO": "Não",
"INACTIVE": "Inactive",
"DEFAULT": "padrão",
"HELP": "Ajuda"
"HELP": "Ajuda",
"TEXT": "Texto",
"ATTACHMENTS": "Anexos"
},
"LOGIN": {
"LABEL_LOGIN": "Usuário",

View file

@ -38,7 +38,9 @@
"NO": "Não",
"INACTIVE": "Inativo",
"DEFAULT": "predefinida",
"HELP": "Ajuda"
"HELP": "Ajuda",
"TEXT": "Texto",
"ATTACHMENTS": "Anexos"
},
"LOGIN": {
"LABEL_LOGIN": "Utilizador",

View file

@ -38,7 +38,9 @@
"NO": "Não",
"INACTIVE": "Inativo",
"DEFAULT": "predefinida",
"HELP": "Ajuda"
"HELP": "Ajuda",
"TEXT": "Texto",
"ATTACHMENTS": "Anexos"
},
"LOGIN": {
"LABEL_LOGIN": "Utilizador",

View file

@ -38,7 +38,9 @@
"NO": "Nu",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Help"
"HELP": "Help",
"TEXT": "Conținut",
"ATTACHMENTS": "Atașament"
},
"LOGIN": {
"LABEL_LOGIN": "Conectare",

View file

@ -38,7 +38,9 @@
"NO": "Нет",
"INACTIVE": "Неактивно",
"DEFAULT": "По умолчанию",
"HELP": "Помощь"
"HELP": "Помощь",
"TEXT": "Текст",
"ATTACHMENTS": "Файлы"
},
"LOGIN": {
"LABEL_LOGIN": "Логин",
@ -393,7 +395,7 @@
"LAYOUT_NO_SPLIT": "Одна панель",
"LAYOUT_VERTICAL_SPLIT": "Вертикальные панели",
"LAYOUT_HORIZONTAL_SPLIT": "Горизонтальные панели",
"SHOW_NEXT_MESSAGE": "Перейти к следующему сообщению после удаления/перемещения текущего",
"SHOW_NEXT_MESSAGE": "Перейти к следующему сообщению после удаления\/перемещения текущего",
"EDITOR": "Редактор текста по умолчанию",
"EDITOR_HTML": "Форматированный",
"EDITOR_PLAIN": "Простой",

View file

@ -38,7 +38,9 @@
"NO": "Nie",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Pomoc"
"HELP": "Pomoc",
"TEXT": "Text",
"ATTACHMENTS": "Prílohy"
},
"LOGIN": {
"LABEL_LOGIN": "Používateľské meno",

View file

@ -38,7 +38,9 @@
"NO": "Ne",
"INACTIVE": "Inactive",
"DEFAULT": "privzeto",
"HELP": "Pomoč"
"HELP": "Pomoč",
"TEXT": "Besedilo",
"ATTACHMENTS": "Priloge"
},
"LOGIN": {
"LABEL_LOGIN": "Prijava",

View file

@ -38,7 +38,9 @@
"NO": "Nej",
"INACTIVE": "Inactive",
"DEFAULT": "standard",
"HELP": "Hjälp"
"HELP": "Hjälp",
"TEXT": "Text",
"ATTACHMENTS": "Bilagor"
},
"LOGIN": {
"LABEL_LOGIN": "Användarnamn",

View file

@ -38,7 +38,9 @@
"NO": "Hayır",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Yardım"
"HELP": "Yardım",
"TEXT": "Metin",
"ATTACHMENTS": "Ekler"
},
"LOGIN": {
"LABEL_LOGIN": "Giriş",

View file

@ -38,7 +38,9 @@
"NO": "Ні",
"INACTIVE": "Inactive",
"DEFAULT": "default",
"HELP": "Допомога"
"HELP": "Допомога",
"TEXT": "Текст",
"ATTACHMENTS": "Файли"
},
"LOGIN": {
"LABEL_LOGIN": "Логін",

View file

@ -38,7 +38,9 @@
"NO": "Không",
"INACTIVE": "Inactive",
"DEFAULT": "mặc định",
"HELP": "Hỗ trợ"
"HELP": "Hỗ trợ",
"TEXT": "Nội dung trong mail",
"ATTACHMENTS": "Phần đính kèm"
},
"LOGIN": {
"LABEL_LOGIN": "Đăng nhập",

View file

@ -38,7 +38,9 @@
"NO": "否",
"INACTIVE": "不生效",
"DEFAULT": "默认",
"HELP": "帮助"
"HELP": "帮助",
"TEXT": "内容",
"ATTACHMENTS": "附件"
},
"LOGIN": {
"LABEL_LOGIN": "登录",

View file

@ -38,7 +38,9 @@
"NO": "否",
"INACTIVE": "閒置中",
"DEFAULT": "預設",
"HELP": "協助"
"HELP": "協助",
"TEXT": "內文",
"ATTACHMENTS": "附件"
},
"LOGIN": {
"LABEL_LOGIN": "登入",

View file

@ -135,24 +135,7 @@
</tr>
</table>
<div style="display:flex">
<div class="btn-group" style="flex-grow:1" id="area-toggle">
<button type="button" class="btn" data-bind="click: bodyArea,
css: { 'active': 'body' == viewArea() }">
<i class="icon-file-text"></i>
</button>
<button type="button" class="btn" data-bind="click: attachmentsArea,
css: { 'btn-danger': attachmentsInErrorCount(), 'active': 'attachments' == viewArea() },
tooltipErrorTip: attachmentsErrorTooltip">
<span data-bind="visible: attachmentsCount()">
<b data-bind="text: attachmentsCount"></b>
&nbsp;&nbsp;
</span>
<i data-bind="css: { 'icon-attachment': !attachmentsInProcessCount(), 'icon-spinner': attachmentsInProcessCount()}"></i>
</button>
<button type="button" class="btn" data-bind="visible: canMailvelope, click: mailvelopeArea, css: { 'active': 'mailvelope' == viewArea() }">
<i class="mailvelope-icon"></i>
</button>
</div>
<div class="btn-group" style="flex-grow:1"></div>
<div class="btn-group">
<a class="btn fontastic" data-bind="click: togglePgpSign, visible: canPgpSign, css: {'btn-success': pgpSign()}" data-i18n="[title]OPENPGP/LABEL_SIGN">
@ -170,28 +153,64 @@
</div>
</div>
<div class="attachmentAreaParent" data-bind="visible: 'attachments' == viewArea()">
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropVisible(), css: {'dragAndDropOver': dragAndDropOver}"
data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></div>
<ul class="attachmentList" data-bind="foreach: attachments">
<li class="attachmentItem" data-bind="attr: { 'title': title }, css: { 'waiting': waiting, 'error': '' !== error() }">
<div class="attachmentIcon">
<i class="iconMain" data-bind="css: iconClass, visible: !uploading() || 0 === progress()"></i>
<div class="iconProgress" data-bind="attr: { 'style': progressStyle }, visible: uploading"></div>
<div class="iconBG" data-bind="text: progressText, visible: uploading"></div>
</div>
<div class="attachmentNameParent">
<a href="#" class="close pull-right" style="margin-top:-4px;" data-bind="click: cancel">×</a>
<div class="attachmentName" data-bind="text: fileName"></div>
<span class="attachmentSize" data-bind="text: friendlySize"></span>
</div>
</li>
</ul>
<div class="no-attachments-desc" data-bind="visible: 0 === attachments().length"
data-i18n="COMPOSE/NO_ATTACHMENTS_HERE_DESC"></div>
<div class="tabs">
<input type="radio" name="tabs" value="body" id="tab-body" data-bind="checked: viewArea">
<label for="tab-body"
role="tab"
aria-selected="true"
aria-controls="panel1"
tabindex="0">
<i class="icon-file-text"></i>
<span data-i18n="GLOBAL/TEXT"></span>
</label>
<div class="tab-content" role="tabpanel" aria-hidden="false" style="grid-column-end:4">
<div class="textAreaParent" data-bind="initDom: editorArea, attr:{spellcheck:allowSpellcheck()?'true':'false'}"></div>
</div>
<input type="radio" name="tabs" value="attachments" id="tab-attachments" data-bind="checked: viewArea">
<label for="tab-attachments"
role="tab"
aria-selected="false"
aria-controls="panel2"
tabindex="0"
data-bind="
css: { 'btn-danger': attachmentsInErrorCount() },
tooltipErrorTip: attachmentsErrorTooltip">
<b data-bind="visible: attachmentsCount, text: attachmentsCount"></b>
<i data-bind="css: { 'icon-attachment': !attachmentsInProcessCount(), 'icon-spinner': attachmentsInProcessCount()}"></i>
<span data-i18n="GLOBAL/ATTACHMENTS"></span>
</label>
<div class="tab-content attachmentAreaParent" role="tabpanel" aria-hidden="true" style="grid-column-end:4">
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropVisible(), css: {'dragAndDropOver': dragAndDropOver}"
data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></div>
<ul class="attachmentList" data-bind="foreach: attachments">
<li class="attachmentItem" data-bind="attr: { 'title': title }, css: { 'waiting': waiting, 'error': '' !== error() }">
<div class="attachmentIcon">
<i class="iconMain" data-bind="css: iconClass, visible: !uploading() || 0 === progress()"></i>
<div class="iconProgress" data-bind="attr: { 'style': progressStyle }, visible: uploading"></div>
<div class="iconBG" data-bind="text: progressText, visible: uploading"></div>
</div>
<div class="attachmentNameParent">
<a href="#" class="close pull-right" style="margin-top:-4px;" data-bind="click: cancel">×</a>
<div class="attachmentName" data-bind="text: fileName"></div>
<span class="attachmentSize" data-bind="text: friendlySize"></span>
</div>
</li>
</ul>
<div class="no-attachments-desc" data-bind="visible: 0 === attachments().length"
data-i18n="COMPOSE/NO_ATTACHMENTS_HERE_DESC"></div>
</div>
<input type="radio" name="tabs" value="mailvelope" id="tab-mailvelope" data-bind="checked: viewArea">
<label for="tab-mailvelope"
role="tab"
aria-selected="false"
aria-controls="panel3"
tabindex="0"
data-bind="visible: canMailvelope">
<i class="mailvelope-icon"></i>
<span>Mailvelope</span>
</label>
<div class="tab-content textAreaParent" id="mailvelope-editor" role="tabpanel" aria-hidden="true" style="grid-column-end:4" data-bind="visible: canMailvelope"></div>
</div>
<div class="textAreaParent" data-bind="visible: 'body' == viewArea(), initDom: editorArea, attr:{spellcheck:allowSpellcheck()?'true':'false'}"></div>
<div class="textAreaParent" id="mailvelope-editor" data-bind="visible: 'mailvelope' == viewArea()"></div>
</div>