feat: MutationObserver for dynamic element suppression
This commit is contained in:
@@ -89,6 +89,15 @@
|
|||||||
applySettingsToDOM(settings);
|
applySettingsToDOM(settings);
|
||||||
injectThemeCSS(settings.theme);
|
injectThemeCSS(settings.theme);
|
||||||
|
|
||||||
|
// Start the MutationObserver
|
||||||
|
OR.Observer.start(settings);
|
||||||
|
|
||||||
|
// Apply behavior patches
|
||||||
|
OR.Behavior.start(settings);
|
||||||
|
|
||||||
|
// Start DOM injector (quick actions)
|
||||||
|
OR.Injector.start(settings);
|
||||||
|
|
||||||
// Listen for setting changes from popup
|
// Listen for setting changes from popup
|
||||||
chrome.storage.onChanged.addListener((changes, area) => {
|
chrome.storage.onChanged.addListener((changes, area) => {
|
||||||
if (area !== 'sync') return;
|
if (area !== 'sync') return;
|
||||||
@@ -97,6 +106,15 @@
|
|||||||
OR.loadSettings().then((updated) => {
|
OR.loadSettings().then((updated) => {
|
||||||
applySettingsToDOM(updated);
|
applySettingsToDOM(updated);
|
||||||
|
|
||||||
|
// Update observer with new settings
|
||||||
|
OR.Observer.updateSettings(updated);
|
||||||
|
|
||||||
|
// Update behavior patches
|
||||||
|
OR.Behavior.updateSettings(updated);
|
||||||
|
|
||||||
|
// Update injector
|
||||||
|
OR.Injector.updateSettings(updated);
|
||||||
|
|
||||||
// Swap theme CSS if theme changed
|
// Swap theme CSS if theme changed
|
||||||
if (changes.theme) {
|
if (changes.theme) {
|
||||||
injectThemeCSS(changes.theme.newValue);
|
injectThemeCSS(changes.theme.newValue);
|
||||||
|
|||||||
@@ -1 +1,126 @@
|
|||||||
// Outlook Relook — observer.js (stub, implemented in later task)
|
// Outlook Relook — MutationObserver
|
||||||
|
// Watches OWA's DOM and removes dynamically injected elements
|
||||||
|
// based on active settings.
|
||||||
|
|
||||||
|
window.OutlookRelook = window.OutlookRelook || {};
|
||||||
|
|
||||||
|
window.OutlookRelook.Observer = (function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let observer = null;
|
||||||
|
let currentSettings = {};
|
||||||
|
|
||||||
|
// Map setting keys to selector registry names
|
||||||
|
// Each setting can suppress one or more logical elements
|
||||||
|
const SETTING_TO_SELECTORS = {
|
||||||
|
hideCopilot: ['copilot-button', 'copilot-pane', 'copilot-compose-suggestions'],
|
||||||
|
hideSuggestedReplies: ['suggested-replies'],
|
||||||
|
hidePromoBanners: ['promo-banners'],
|
||||||
|
hideFocusedOtherTabs: ['focused-other-tabs'],
|
||||||
|
hideSidebarAppIcons: ['sidebar-app-icons'],
|
||||||
|
hideGroupsSection: ['groups-section'],
|
||||||
|
hideMyDayButtons: ['my-day-buttons'],
|
||||||
|
hideSenderAvatars: ['sender-avatars'],
|
||||||
|
hideFeatureDiscovery: ['feature-discovery'],
|
||||||
|
hideVivaInsights: ['viva-insights'],
|
||||||
|
hideUnreadOtherBanner: ['unread-other-banner'],
|
||||||
|
hideActivityFeed: ['activity-feed'],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Text content patterns to match elements by their inner text.
|
||||||
|
// Used when aria/data selectors don't catch dynamically injected content.
|
||||||
|
const TEXT_PATTERNS = {
|
||||||
|
hidePromoBanners: [
|
||||||
|
/try the new outlook/i,
|
||||||
|
/upgrade to premium/i,
|
||||||
|
/get the outlook app/i,
|
||||||
|
/switch to the new/i,
|
||||||
|
],
|
||||||
|
hideFeatureDiscovery: [
|
||||||
|
/what's new/i,
|
||||||
|
/new feature/i,
|
||||||
|
/did you know/i,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
function suppressElements() {
|
||||||
|
for (const [settingKey, selectorNames] of Object.entries(SETTING_TO_SELECTORS)) {
|
||||||
|
if (!currentSettings[settingKey]) continue;
|
||||||
|
|
||||||
|
for (const name of selectorNames) {
|
||||||
|
const elements = window.OutlookRelook.resolveSelector(name);
|
||||||
|
for (const el of elements) {
|
||||||
|
if (el.style.display !== 'none') {
|
||||||
|
el.style.display = 'none';
|
||||||
|
console.log('[Outlook Relook] Suppressed: ' + name, el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text-based suppression for elements missed by selectors
|
||||||
|
for (const [settingKey, patterns] of Object.entries(TEXT_PATTERNS)) {
|
||||||
|
if (!currentSettings[settingKey]) continue;
|
||||||
|
|
||||||
|
for (const pattern of patterns) {
|
||||||
|
// Check buttons, banners, and generic containers
|
||||||
|
const candidates = document.querySelectorAll(
|
||||||
|
'[role="alert"], [role="banner"], [role="dialog"], [role="status"], button, a'
|
||||||
|
);
|
||||||
|
for (const el of candidates) {
|
||||||
|
if (el.style.display === 'none') continue;
|
||||||
|
var text = el.textContent || '';
|
||||||
|
if (pattern.test(text) && text.length < 200) {
|
||||||
|
el.style.display = 'none';
|
||||||
|
console.log('[Outlook Relook] Suppressed by text: "' + text.trim().substring(0, 50) + '"', el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function start(settings) {
|
||||||
|
currentSettings = settings;
|
||||||
|
|
||||||
|
// Initial pass
|
||||||
|
suppressElements();
|
||||||
|
|
||||||
|
// Watch for DOM mutations
|
||||||
|
observer = new MutationObserver(function (mutations) {
|
||||||
|
// Debounce: only process if nodes were actually added
|
||||||
|
var hasAddedNodes = false;
|
||||||
|
for (var i = 0; i < mutations.length; i++) {
|
||||||
|
if (mutations[i].addedNodes.length > 0) {
|
||||||
|
hasAddedNodes = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasAddedNodes) {
|
||||||
|
suppressElements();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[Outlook Relook] Observer started');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSettings(settings) {
|
||||||
|
currentSettings = settings;
|
||||||
|
// Re-run suppression with new settings
|
||||||
|
suppressElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect();
|
||||||
|
observer = null;
|
||||||
|
console.log('[Outlook Relook] Observer stopped');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { start: start, updateSettings: updateSettings, stop: stop };
|
||||||
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user