fix: use OWA's actual button selectors for keyboard actions, add flag/pin shortcuts
This commit is contained in:
@@ -168,6 +168,29 @@ window.OutlookRelook.Keyboard = (function () {
|
||||
|
||||
// --- Actions ---
|
||||
|
||||
// --- Find a button by aria-label, searching within a target element first,
|
||||
// then the global toolbar, then the whole document ---
|
||||
function findButton(target, label) {
|
||||
// 1. Look for inline button within/near the message row
|
||||
// OWA renders Delete/Archive/Flag buttons on each row on hover
|
||||
var btn = target.querySelector('button[aria-label="' + label + '"]');
|
||||
if (btn) return btn;
|
||||
|
||||
// 2. Check the parent (some buttons are siblings of the row)
|
||||
if (target.parentElement) {
|
||||
btn = target.parentElement.querySelector('button[aria-label="' + label + '"]');
|
||||
if (btn) return btn;
|
||||
}
|
||||
|
||||
// 3. Look in the global toolbar area
|
||||
btn = document.querySelector('[role="toolbar"] button[aria-label="' + label + '"], .fui-Toolbar button[aria-label="' + label + '"]');
|
||||
if (btn) return btn;
|
||||
|
||||
// 4. Anywhere in the document
|
||||
btn = document.querySelector('button[aria-label="' + label + '"]');
|
||||
return btn;
|
||||
}
|
||||
|
||||
function performAction(targets, actionFn) {
|
||||
if (targets.length === 0) return;
|
||||
var i = 0;
|
||||
@@ -178,99 +201,102 @@ window.OutlookRelook.Keyboard = (function () {
|
||||
}
|
||||
var target = targets[i];
|
||||
i++;
|
||||
// Click to select in OWA, then perform action
|
||||
target.click();
|
||||
setTimeout(function () {
|
||||
actionFn(target);
|
||||
setTimeout(processNext, 150);
|
||||
}, 100);
|
||||
setTimeout(processNext, 200);
|
||||
}, 150);
|
||||
}
|
||||
processNext();
|
||||
}
|
||||
|
||||
function actionDelete(targets) {
|
||||
performAction(targets, function () {
|
||||
var deleteBtn = document.querySelector(
|
||||
'[aria-label*="Delete" i][role="button"], [aria-label*="delete" i][role="menuitem"]'
|
||||
);
|
||||
if (deleteBtn) {
|
||||
deleteBtn.click();
|
||||
performAction(targets, function (target) {
|
||||
var btn = findButton(target, 'Delete');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
var deleteEvent = new KeyboardEvent('keydown', {
|
||||
key: 'Delete', code: 'Delete', bubbles: true, cancelable: true
|
||||
});
|
||||
document.activeElement.dispatchEvent(deleteEvent);
|
||||
console.warn('[Outlook Relook] Delete button not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function actionArchive(targets) {
|
||||
performAction(targets, function () {
|
||||
var archiveBtn = document.querySelector(
|
||||
'[aria-label*="Archive" i][role="button"], [aria-label*="archive" i][role="menuitem"]'
|
||||
);
|
||||
if (archiveBtn) {
|
||||
archiveBtn.click();
|
||||
performAction(targets, function (target) {
|
||||
var btn = findButton(target, 'Archive');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
console.warn('[Outlook Relook] Archive button not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function actionMarkRead(targets) {
|
||||
performAction(targets, function () {
|
||||
var readBtn = document.querySelector(
|
||||
'[aria-label*="Mark as read" i][role="button"], [aria-label*="Mark as read" i][role="menuitem"]'
|
||||
);
|
||||
if (readBtn) {
|
||||
readBtn.click();
|
||||
function actionMarkReadUnread(targets) {
|
||||
// OWA uses a single toggle button "Read / Unread"
|
||||
performAction(targets, function (target) {
|
||||
var btn = findButton(target, 'Read / Unread');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
triggerContextMenuAction(/mark as read/i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function actionMarkUnread(targets) {
|
||||
performAction(targets, function () {
|
||||
var unreadBtn = document.querySelector(
|
||||
'[aria-label*="Mark as unread" i][role="button"], [aria-label*="Mark as unread" i][role="menuitem"]'
|
||||
);
|
||||
if (unreadBtn) {
|
||||
unreadBtn.click();
|
||||
} else {
|
||||
triggerContextMenuAction(/mark as unread/i);
|
||||
// Try context menu fallback
|
||||
triggerContextMenuAction(target, /mark as read|mark as unread|read \/ unread/i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function actionMove(targets) {
|
||||
if (targets.length > 0) {
|
||||
// Select first target, then open move dialog
|
||||
targets[0].click();
|
||||
setTimeout(function () {
|
||||
var moveBtn = document.querySelector(
|
||||
'[aria-label*="Move to" i][role="button"], [aria-label*="Move" i][role="menuitem"]'
|
||||
);
|
||||
if (moveBtn) {
|
||||
moveBtn.click();
|
||||
var btn = findButton(targets[0], 'Move to');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
triggerContextMenuAction(/move to/i);
|
||||
triggerContextMenuAction(targets[0], /move to/i);
|
||||
}
|
||||
}, 100);
|
||||
}, 150);
|
||||
}
|
||||
}
|
||||
|
||||
function triggerContextMenuAction(pattern) {
|
||||
var focused = document.querySelector('.or-kb-focused');
|
||||
if (!focused) return;
|
||||
var rect = focused.getBoundingClientRect();
|
||||
function actionFlag(targets) {
|
||||
performAction(targets, function (target) {
|
||||
var btn = findButton(target, 'Flag this message')
|
||||
|| findButton(target, 'Flag / Unflag');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
console.warn('[Outlook Relook] Flag button not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function actionPin(targets) {
|
||||
performAction(targets, function (target) {
|
||||
var btn = findButton(target, 'Pin / Unpin');
|
||||
if (btn) {
|
||||
btn.click();
|
||||
} else {
|
||||
console.warn('[Outlook Relook] Pin button not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function triggerContextMenuAction(target, pattern) {
|
||||
var el = target || document.querySelector('.or-kb-focused');
|
||||
if (!el) return;
|
||||
var rect = el.getBoundingClientRect();
|
||||
var contextEvent = new MouseEvent('contextmenu', {
|
||||
bubbles: true, cancelable: true,
|
||||
clientX: rect.x + 10, clientY: rect.y + 10,
|
||||
});
|
||||
focused.dispatchEvent(contextEvent);
|
||||
el.dispatchEvent(contextEvent);
|
||||
setTimeout(function () {
|
||||
var menuItems = document.querySelectorAll('[role="menuitem"]');
|
||||
for (var j = 0; j < menuItems.length; j++) {
|
||||
if (pattern.test(menuItems[j].textContent)) {
|
||||
if (pattern.test(menuItems[j].textContent || menuItems[j].getAttribute('aria-label') || '')) {
|
||||
menuItems[j].click();
|
||||
return;
|
||||
}
|
||||
@@ -360,18 +386,11 @@ window.OutlookRelook.Keyboard = (function () {
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
if (shift) {
|
||||
targets = getActionTargets(items);
|
||||
actionMarkRead(targets);
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
// Shift+i or Shift+u — OWA uses a single "Read / Unread" toggle
|
||||
if (shift) {
|
||||
targets = getActionTargets(items);
|
||||
actionMarkUnread(targets);
|
||||
actionMarkReadUnread(targets);
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
@@ -382,6 +401,18 @@ window.OutlookRelook.Keyboard = (function () {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user