@@ -1,4 +1,4 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later
+// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3.0-or-later -*- js-indent-level: 2; -*-
var mumi = (function () {
const possibleTokens = [
{ text: 'is:open' },
@@ -129,12 +129,41 @@ var mumi = (function () {
var init = function () {
initTokenInput ();
};
+
+ // Copy a message Message-ID to the clipboard.
+ var setupMessageIdButtonHandler = function () {
+
+ let messageIdClickHandler = (evt) => {
+ messageIdButton = evt.currentTarget;
+ originalTooltip = messageIdButton.dataset.tooltip;
+ var messageId = messageIdButton.dataset.messageId;
+ if (!window.isSecureContext) {
+ console.log("not in a secure context -- " +
+ "cannot copy message-id to clipboard\n" +
+ "tip: for testing, open via http://localhost:1234");
+ return;
+ }
+ // Update button's tooltip for the next 3 s.
+ messageIdButton.dataset.tooltip = "Copied!";
+ setTimeout(() => { messageIdButton.dataset.tooltip = originalTooltip; },
+ 3000);
+ navigator.clipboard.writeText(messageId);
+ console.log("copied Message-ID " + messageId + " to clipboard");
+ };
+
+ var messageIdButton = document.getElementById("copy-message-id-button");
+ if (messageIdButton === null) { return; }
+ messageIdButton.addEventListener("click", messageIdClickHandler);
+ };
+
return({
'init': init,
'lines': setupLineHandler,
+ 'messageIdButtonHandler': setupMessageIdButtonHandler,
});
})();
window.addEventListener ("load", mumi.init);
window.addEventListener ("DOMContentLoaded", mumi.lines);
+window.addEventListener ("DOMContentLoaded", mumi.messageIdButtonHandler);
// @license-end
@@ -506,11 +506,28 @@ details {
margin-right: 0.2em;
}
-.download-message,
.download-part {
float: right;
- font-size: 0.8em;
- font-style: italic;
+}
+
+.header-buttons {
+ display: flex;
+ flex-direction: row;
+ float: right;
+ justify-content: flex-end;
+ }
+
+.header-buttons > * {
+ margin: 0 0 0 0.5rem;
+ // Custom buttons: undo the Pico CSS default style.
+ background: revert;
+ border: revert;
+ color: revert;
+ padding: revert;
+}
+
+.message-button:hover {
+ transform: scale(0.95);
}
@media (min-width: 768px) {
@@ -1,6 +1,7 @@
;;; mumi -- Mediocre, uh, mail interface
;;; Copyright © 2016, 2017, 2018, 2019, 2020, 2021, 2022 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019, 2023 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -612,6 +613,7 @@ currently disabled."))
(not (bug-archived bug)))
mailer-form
disabled-mailer)))
+
(define (show-message message-number message previous-subject)
`((div
(a (@ (class "message-anchor")
@@ -642,10 +644,20 @@ currently disabled."))
message-number)))
(title ,(date->string (date message))))
,(time->string (date message)))))
- (div (@ (class "download-message"))
- (a (@ (href ,(format #f "/issue/~a/raw/~a"
- id message-number)))
- ,download-icon))
+ (div (@ (class "header-buttons"))
+ (div (@ (id "copy-message-id-button")
+ (class "message-button")
+ (role "button") ;specific to Pico CSS
+ (data-tooltip "Copy Message-ID")
+ (data-message-id ,(message-id message)))
+ ,copy-icon)
+ (div (@ (id "download-raw-message-button")
+ (class "message-button")
+ (role "button")
+ (data-tooltip "Download raw message"))
+ (a (@ (href ,(format #f "/issue/~a/raw/~a"
+ id message-number)))
+ ,download-icon)))
,@(if (string-suffix? previous-subject (subject message))
'()
`((div (@ (class "subject")) ,(subject message))))
@@ -2,6 +2,7 @@
;;; Copyright © 2017, 2018, 2019, 2020 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2018, 2019 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
@@ -35,6 +36,7 @@
#:use-module (web uri)
#:export (prettify
avatar-color
+ copy-icon
download-icon
display-message-body
time->string))
@@ -215,23 +217,31 @@ numbers with the given MESSAGE-NUMBER."
;; https://icons.getbootstrap.com/icons/download/
(define download-icon
'(svg (@ (class "bi bi-download")
- (width "1em")
- (height "1em")
+ (width "1rem")
+ (height "1rem")
+ (viewBox "0 0 16 16")
+ (fill "currentColor")
+ (xmlns "http://www.w3.org/2000/svg"))
+ (path (@ (d "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 \
+1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 \
+1-2-2v-2.5a.5.5 0 0 1 .5-.5")))
+ (path (@ (d "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 \
+0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 \
+1 0-.708.708z")))))
+
+;; https://icons.getbootstrap.com/icons/copy/
+(define copy-icon
+ '(svg (@ (class "bi bi-copy")
+ (width "1rem")
+ (height "1rem")
(viewBox "0 0 16 16")
(fill "currentColor")
(xmlns "http://www.w3.org/2000/svg"))
- (title "Download")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M.5 8a.5.5 0 01.5.5V12a1 1 0 001 1h12a1 1 0 001-1\
-V8.5a.5.5 0 011 0V12a2 2 0 01-2 2H2a2 2 0 01-2-2V8.5A.5.5 0 01.5 8z")) "")
- (path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M5 7.5a.5.5 0 01.707 0L8 9.793 10.293 7.5a.5.5 0 \
-11.707.707l-2.646 2.647a.5.5 0 01-.708 0L5 8.207A.5.5 0 015 7.5z")) "")
(path (@ (fill-rule "evenodd")
- (clip-rule "evenodd")
- (d "M8 1a.5.5 0 01.5.5v8a.5.5 0 01-1 0v-8A.5.5 0 018 1z")) "")))
+ (d "M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 \
+2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 \
+0-1-1zM2 5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1h1v1a2 2 0 0 1-2 \
+2H2a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h1v1z")))))
(define* (display-message-body bug-num message-number message #:optional plain?)
"Convenience procedure to render MESSAGE (part of bug with number
@@ -285,7 +295,9 @@ lines when PLAIN? is #T."
"")))
((string-suffix? ".scm" attachment-name)
`(div (@ (class "multipart scheme"))
- (div (@ (class "download-part"))
+ (div (@ (id "download-scheme-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download Scheme file"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(highlights->sxml (highlight lex-scheme body))))
@@ -294,7 +306,9 @@ lines when PLAIN? is #T."
(list "multipart" (or (and content-type
(content-type->css-class content-type))
"")))))
- (div (@ (class "download-part"))
+ (div (@ (id "download-part-button")
+ (class "download-part message-button")
+ (data-tooltip "Download MIME part"))
(a (@ (href ,(attachment-url)))
,download-icon))
,(cond
* mumi/web/view/html.scm (issue-page) <copy-message-id-button>: New HTML element. * mumi/web/view/utils.scm (download-icon): Update source. Use 'rem' as size unit. (copy-icon): New variable. (display-message-body) <download-part>: Add IDs to buttons. Add to "message-button" class. * assets/mumi.scss: Refactor spacing of message header buttons via a flex display. Add a shrinking animation to message buttons on hover. * assets/js/mumi.js (mumi): Register an event for it that copies the Message-ID to the clipboard. Add js-indent-level prop line. Signed-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com> --- assets/js/mumi.js | 31 ++++++++++++++++++++++++++++- assets/mumi.scss | 23 ++++++++++++++++++--- mumi/web/view/html.scm | 20 +++++++++++++++---- mumi/web/view/utils.scm | 44 +++++++++++++++++++++++++++-------------- 4 files changed, 95 insertions(+), 23 deletions(-)