xi-conversations

Minimal clone of thunderbird conversations
git clone https://git.ce9e.org/xi-conversations.git

commit
58ae872ac0e04aeca5e97710175cb6a9c4c421b0
parent
5df8c1cf870e46a96f81b9754a426c78fc2e290c
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-05-11 14:18
include list links in message menu

Diffstat

M _locales/en/messages.json 5 ++++-
M content/js/main.js 7 ++++++-
M content/js/message.js 27 ++++++++++++++++++++++++++-
M content/material-icons.svg 3 +++
M content/style.css 2 ++
M scripts/get-material-icons.sh 2 +-

6 files changed, 42 insertions, 4 deletions


diff --git a/_locales/en/messages.json b/_locales/en/messages.json

@@ -16,5 +16,8 @@
   16    16 	"toggleSig": {"message": "-- toggle signature --"},
   17    17 	"encrypted": {"message": "encrypted message"},
   18    18 	"emptyBody": {"message": "(empty)"},
   19    -1 	"encryptedBody": {"message": "(encrypted)"}
   -1    19 	"encryptedBody": {"message": "(encrypted)"},
   -1    20 	"listHelp": {"message": "list info"},
   -1    21 	"listArchive": {"message": "list archive"},
   -1    22 	"listUnsubscribe": {"message": "unsubscribe"}
   20    23 }

diff --git a/content/js/main.js b/content/js/main.js

@@ -23,7 +23,12 @@ var getMessageForId = function(id) {
   23    23 
   24    24 browser.xi.getConversation(initialIDs).catch(() => {
   25    25 	return Promise.all(initialIDs.map(getMessageForId));
   26    -1 }).then(function(conversation) {
   -1    26 }).then(conversation => Promise.all(conversation.map(msg => {
   -1    27 	return browser.messages.getFull(msg.id).then(full => {
   -1    28 		msg.full = full;
   -1    29 		return msg;
   -1    30 	});
   -1    31 }))).then(function(conversation) {
   27    32 	var subject = conversation[0].subject || '(no subject)';
   28    33 	document.querySelector('.conversation__subject').textContent = subject;
   29    34 	document.title = subject;

diff --git a/content/js/message.js b/content/js/message.js

@@ -50,6 +50,18 @@ var toggleDropdown = function(msg, button) {
   50    50 	}
   51    51 };
   52    52 
   -1    53 var getListUrl = function(msg, key, prefix) {
   -1    54 	// see https://www.rfc-editor.org/rfc/rfc2369
   -1    55 	for (let header of msg.full.headers[key] || []) {
   -1    56 		for (let item of header.split(', ')) {
   -1    57 			var url = item.slice(item.indexOf('<') + 1, -1);
   -1    58 			if (url.startsWith(prefix)) {
   -1    59 				return url;
   -1    60 			}
   -1    61 		}
   -1    62 	}
   -1    63 }
   -1    64 
   53    65 var template = function(msg) {
   54    66 	var h = util.h;
   55    67 	var _ = browser.i18n.getMessage;
@@ -66,6 +78,15 @@ var template = function(msg) {
   66    78 		return button;
   67    79 	};
   68    80 
   -1    81 	var createLink = function(attrs, href, icon, label, labelVisible) {
   -1    82 		var content = labelVisible ? [util.createIcon(icon), ' ', label] : [util.createIcon(icon, label)];
   -1    83 		return h('a', Object.assign({'href': href}, attrs), content);
   -1    84 	};
   -1    85 
   -1    86 	var listHelp = getListUrl(msg, 'list-help', 'http');
   -1    87 	var listArchive = getListUrl(msg, 'list-archive', 'http');
   -1    88 	var listUnsubscribe = getListUrl(msg, 'list-unsubscribe', 'http') || getListUrl(msg, 'list-unsubscribe', '');
   -1    89 
   69    90 	return h('article', {'class': 'message', 'id': `msg-${msg.id}`, 'tabindex': -1}, [
   70    91 		h('header', {'class': 'message__header'}, [
   71    92 			createButton({'class': 'star', 'aria-pressed': msg.flagged}, actions.toggleFlagged, 'star', _('star')),
@@ -100,6 +121,10 @@ var template = function(msg) {
  100   121 					createButton({'class': 'dropdown-item'}, actions.editAsNew, 'create', _('edit'), true),
  101   122 					createButton({'class': 'dropdown-item'}, actions.viewClassic, 'open_in_new', _('viewClassic'), true),
  102   123 					createButton({'class': 'dropdown-item'}, actions.viewSource, 'code', _('viewSource'), true),
   -1   124 
   -1   125 					listHelp ? createLink({'class': 'dropdown-item'}, listHelp, 'info', _('listHelp'), true): null,
   -1   126 					listArchive ? createLink({'class': 'dropdown-item'}, listArchive, 'inventory_2', _('listArchive'), true): null,
   -1   127 					listUnsubscribe ? createLink({'class': 'dropdown-item'}, listUnsubscribe, 'unsubscribe', _('listUnsubscribe'), true): null,
  103   128 				]),
  104   129 			]),
  105   130 		]),
@@ -126,7 +151,7 @@ export default function(msg, expanded) {
  126   151 	// header events
  127   152 	var header = e.querySelector('.message__header');
  128   153 	header.addEventListener('click', event => {
  129    -1 		if (!event.defaultPrevented) {
   -1   154 		if (!event.defaultPrevented && !event.target.closest('a[href]')) {
  130   155 			event.preventDefault();
  131   156 			e.classList.toggle('is-expanded');
  132   157 			lazyLoadBody();

diff --git a/content/material-icons.svg b/content/material-icons.svg

@@ -12,4 +12,7 @@
   12    12     <path id="list" d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7zm-4 6h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/>
   13    13     <path id="forward" d="M14 8.83 17.17 12 14 15.17V14H6v-4h8V8.83M12 4v4H4v8h8v4l8-8-8-8z"/>
   14    14     <path id="create" d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM5.92 19H5v-.92l9.06-9.06.92.92L5.92 19zM20.71 5.63l-2.34-2.34c-.2-.2-.45-.29-.71-.29s-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83a.996.996 0 0 0 0-1.41z"/>
   -1    15     <path id="info" d="M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
   -1    16     <path id="inventory_2" d="M20 2H4c-1 0-2 .9-2 2v3.01c0 .72.43 1.34 1 1.69V20c0 1.1 1.1 2 2 2h14c.9 0 2-.9 2-2V8.7c.57-.35 1-.97 1-1.69V4c0-1.1-1-2-2-2zm-1 18H5V9h14v11zm1-13H4V4h16v3z"/><path d="M9 12h6v2H9z"/>
   -1    17     <path id="unsubscribe" d="M20.99 14.04V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h10.05c.28 1.92 2.1 3.35 4.18 2.93 1.34-.27 2.43-1.37 2.7-2.71.25-1.24-.16-2.39-.94-3.18zm-2-9.04L12 8.5 5 5h13.99zm-3.64 10H5V7l7 3.5L19 7v6.05c-.16-.02-.33-.05-.5-.05-1.39 0-2.59.82-3.15 2zm5.15 2h-4v-1h4v1z"/>
   15    18 </svg>

diff --git a/content/style.css b/content/style.css

@@ -111,6 +111,7 @@ body {
  111   111 	display: block;
  112   112 }
  113   113 .dropdown-item {
   -1   114 	display: block;
  114   115 	border: 0;
  115   116 	background: none;
  116   117 	color: inherit;
@@ -122,6 +123,7 @@ body {
  122   123 	padding-inline: 0.3em;
  123   124 	white-space: nowrap;
  124   125 	cursor: pointer;
   -1   126 	text-decoration: none;
  125   127 }
  126   128 .dropdown-item:nth-child(2n) {
  127   129 	background-color: var(--odd);

diff --git a/scripts/get-material-icons.sh b/scripts/get-material-icons.sh

@@ -2,7 +2,7 @@
    2     2 
    3     3 echo '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">'
    4     4 echo '    <!-- Material icons are published under Apache License Version 2.0. https://material.io/icons/ -->'
    5    -1 for icon in attachment code open_in_new star lock reply reply_all refresh menu list forward create mode_heat; do
   -1     5 for icon in attachment code open_in_new star lock reply reply_all refresh menu list forward create mode_heat info inventory_2 unsubscribe; do
    6     6     wget -q "https://unpkg.com/@material-design-icons/svg@0.14.13/outlined/${icon}.svg" -O - \
    7     7         | grep -o '<path.*/>' \
    8     8         | sed "s/<path/    <path id=\"${icon}\"/"