rename: Outlook Relook → Outcut, add keyboard presets, remove design UI from popup

- Rename extension to "Outcut" throughout all source files and console logs
- Add KEY_PRESETS object (gmail/outlook) and matchesAction() helper to keyboard.js
- Rewrite handleKeydown to use preset-based dispatch instead of hardcoded switch
- Update updateSettings to re-init when keyboardPreset changes
- Add keyboardPreset: 'gmail' default to settings-defaults.js
- Replace popup Design Tweaks UI with preset dropdown + dynamic help text
- Keep all design tweak content script logic intact (activatable via storage)
- Update manifest: version 1.0.0, remove activeTab, add homepage_url
This commit is contained in:
Joel Brock
2026-04-27 14:11:45 -07:00
parent 93a5888d83
commit 3de2db7d89
10 changed files with 199 additions and 523 deletions

View File

@@ -1,4 +1,4 @@
// Outlook Relook — Gmail-Style Keyboard Navigation & Multi-Select
// Outcut — Keyboard Navigation & Multi-Select
// Adds keyboard focus cursor and multi-select to OWA's message list.
// Gated by the keyboardMultiSelect setting.
//
@@ -7,6 +7,53 @@
window.OutlookRelook = window.OutlookRelook || {};
// Keyboard shortcut presets
var KEY_PRESETS = {
gmail: {
nextMessage: [{key: 'j'}, {key: 'ArrowDown'}],
prevMessage: [{key: 'k'}, {key: 'ArrowUp'}],
selectExtendDown: [{key: 'j', shift: true}, {key: 'ArrowDown', shift: true}],
selectExtendUp: [{key: 'k', shift: true}, {key: 'ArrowUp', shift: true}],
toggleSelect: [{key: 'x'}, {key: ' '}],
delete: [{key: '#'}],
archive: [{key: 'e'}],
readUnread: [{key: 'I', shift: true}, {key: 'U', shift: true}],
move: [{key: 'v'}],
flag: [{key: 'f'}],
pin: [{key: 'p'}],
deselect: [{key: 'Escape'}],
open: [{key: 'Enter'}, {key: 'o'}],
label: 'Gmail-style: j/k nav, x select, # del, e archive'
},
outlook: {
nextMessage: [{key: 'ArrowDown'}, {key: 'j'}],
prevMessage: [{key: 'ArrowUp'}, {key: 'k'}],
selectExtendDown: [{key: 'ArrowDown', shift: true}],
selectExtendUp: [{key: 'ArrowUp', shift: true}],
toggleSelect: [{key: ' '}],
delete: [{key: 'Delete'}, {key: 'Backspace'}],
archive: [{key: 'e'}],
readUnread: [{key: 'q'}, {key: 'I', shift: true}],
move: [{key: 'v'}],
flag: [{key: 'Insert'}, {key: 'f'}],
pin: [{key: 'p'}],
deselect: [{key: 'Escape'}],
open: [{key: 'Enter'}],
label: 'Outlook-style: arrows nav, Space select, Del delete'
}
};
function matchesAction(e, actionBindings) {
if (!actionBindings) return false;
for (var i = 0; i < actionBindings.length; i++) {
var b = actionBindings[i];
if (e.key === b.key && !!e.shiftKey === !!b.shift && !!e.ctrlKey === !!b.ctrl) {
return true;
}
}
return false;
}
window.OutlookRelook.Keyboard = (function () {
'use strict';
@@ -246,7 +293,7 @@ window.OutlookRelook.Keyboard = (function () {
performAction(targets, function (target) {
var btn = findButton(target, 'Delete');
if (btn) { btn.click(); return true; }
console.warn('[Outlook Relook] Delete button not found');
console.warn('[Outcut] Delete button not found');
return false;
});
}
@@ -255,7 +302,7 @@ window.OutlookRelook.Keyboard = (function () {
performAction(targets, function (target) {
var btn = findButton(target, 'Archive');
if (btn) { btn.click(); return true; }
console.warn('[Outlook Relook] Archive button not found');
console.warn('[Outcut] Archive button not found');
return false;
});
}
@@ -288,7 +335,7 @@ window.OutlookRelook.Keyboard = (function () {
var btn = findButton(target, 'Flag this message')
|| findButton(target, 'Flag / Unflag');
if (btn) { btn.click(); return true; }
console.warn('[Outlook Relook] Flag button not found');
console.warn('[Outcut] Flag button not found');
return false;
});
}
@@ -297,7 +344,7 @@ window.OutlookRelook.Keyboard = (function () {
performAction(targets, function (target) {
var btn = findButton(target, 'Pin / Unpin');
if (btn) { btn.click(); return true; }
console.warn('[Outlook Relook] Pin button not found');
console.warn('[Outcut] Pin button not found');
return false;
});
}
@@ -332,8 +379,8 @@ window.OutlookRelook.Keyboard = (function () {
var items = getMessageItems();
if (items.length === 0) return;
var key = e.key;
var shift = e.shiftKey;
var presetName = currentSettings.keyboardPreset || 'gmail';
var preset = KEY_PRESETS[presetName] || KEY_PRESETS.gmail;
// Initialize focus if not set
var currentIdx = getFocusedIndex(items);
@@ -356,101 +403,54 @@ window.OutlookRelook.Keyboard = (function () {
var handled = true;
var targets;
switch (key) {
case 'j':
case 'ArrowDown':
if (shift) {
toggleSelect(items, currentIdx);
if (currentIdx < items.length - 1) {
setFocus(items, currentIdx + 1);
toggleSelect(items, currentIdx + 1);
}
} else {
if (currentIdx < items.length - 1) {
setFocus(items, currentIdx + 1);
}
}
break;
case 'k':
case 'ArrowUp':
if (shift) {
toggleSelect(items, currentIdx);
if (currentIdx > 0) {
setFocus(items, currentIdx - 1);
toggleSelect(items, currentIdx - 1);
}
} else {
if (currentIdx > 0) {
setFocus(items, currentIdx - 1);
}
}
break;
case 'x':
case ' ':
e.preventDefault();
toggleSelect(items, currentIdx);
break;
case '#':
targets = getActionTargets(items);
actionDelete(targets);
break;
case 'e':
targets = getActionTargets(items);
actionArchive(targets);
break;
case 'I':
case 'U':
// Shift+i or Shift+u — OWA uses a single "Read / Unread" toggle
if (shift) {
targets = getActionTargets(items);
actionMarkReadUnread(targets);
} else {
handled = false;
}
break;
case 'v':
targets = getActionTargets(items);
actionMove(targets);
break;
case 'f':
// Flag/unflag
targets = getActionTargets(items);
actionFlag(targets);
break;
case 'p':
// Pin/unpin
targets = getActionTargets(items);
actionPin(targets);
break;
case 'Escape':
clearSelection();
break;
case 'Enter':
case 'o':
if (currentIdx >= 0 && currentIdx < items.length) {
items[currentIdx].click();
}
break;
default:
handled = false;
if (matchesAction(e, preset.selectExtendDown)) {
toggleSelect(items, currentIdx);
if (currentIdx < items.length - 1) {
setFocus(items, currentIdx + 1);
toggleSelect(items, currentIdx + 1);
}
} else if (matchesAction(e, preset.selectExtendUp)) {
toggleSelect(items, currentIdx);
if (currentIdx > 0) {
setFocus(items, currentIdx - 1);
toggleSelect(items, currentIdx - 1);
}
} else if (matchesAction(e, preset.nextMessage)) {
if (currentIdx < items.length - 1) setFocus(items, currentIdx + 1);
} else if (matchesAction(e, preset.prevMessage)) {
if (currentIdx > 0) setFocus(items, currentIdx - 1);
} else if (matchesAction(e, preset.toggleSelect)) {
e.preventDefault();
toggleSelect(items, currentIdx);
} else if (matchesAction(e, preset.delete)) {
targets = getActionTargets(items);
actionDelete(targets);
} else if (matchesAction(e, preset.archive)) {
targets = getActionTargets(items);
actionArchive(targets);
} else if (matchesAction(e, preset.readUnread)) {
targets = getActionTargets(items);
actionMarkReadUnread(targets);
} else if (matchesAction(e, preset.move)) {
targets = getActionTargets(items);
actionMove(targets);
} else if (matchesAction(e, preset.flag)) {
targets = getActionTargets(items);
actionFlag(targets);
} else if (matchesAction(e, preset.pin)) {
targets = getActionTargets(items);
actionPin(targets);
} else if (matchesAction(e, preset.deselect)) {
clearSelection();
} else if (matchesAction(e, preset.open)) {
if (currentIdx >= 0 && currentIdx < items.length) items[currentIdx].click();
} else {
handled = false;
}
if (handled) {
e.stopPropagation();
if (key !== 'Enter' && key !== 'o') {
e.preventDefault();
}
if (e.key !== 'Enter') e.preventDefault();
}
}
@@ -497,7 +497,7 @@ window.OutlookRelook.Keyboard = (function () {
document.addEventListener('keydown', handleKeydown, true);
setupListObserver();
console.log('[Outlook Relook] Keyboard navigation started');
console.log('[Outcut] Keyboard navigation started');
cleanupFns.push(function () {
document.removeEventListener('keydown', handleKeydown, true);
});
@@ -506,9 +506,11 @@ window.OutlookRelook.Keyboard = (function () {
function updateSettings(settings) {
var wasEnabled = currentSettings.keyboardMultiSelect;
var isEnabled = settings.keyboardMultiSelect;
var oldPreset = currentSettings.keyboardPreset;
var newPreset = settings.keyboardPreset;
currentSettings = settings;
if (wasEnabled !== isEnabled) {
if (wasEnabled !== isEnabled || oldPreset !== newPreset) {
stop();
start(settings);
}