Skip to content

Commit 9aae6f9

Browse files
PoC handle navigation centrally
1 parent ee0ba65 commit 9aae6f9

File tree

6 files changed

+61
-26
lines changed

6 files changed

+61
-26
lines changed

injected/src/config-feature.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ export default class ConfigFeature {
2929
}
3030
}
3131

32+
/**
33+
* @param {Site} site
34+
*/
35+
urlChanged(site) {
36+
this.#args.site = site;
37+
}
38+
3239
get args() {
3340
return this.#args;
3441
}

injected/src/content-feature.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default class ContentFeature extends ConfigFeature {
3030
#messaging;
3131
/** @type {boolean} */
3232
#isDebugFlagSet = false;
33+
listenForUrlChanges = false;
3334

3435
/** @type {ImportMeta} */
3536
#importConfig;

injected/src/content-scope-features.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { initStringExemptionLists, isFeatureBroken, isGloballyDisabled, platform
22
import { platformSupport } from './features';
33
import { PerformanceMonitor } from './performance';
44
import platformFeatures from 'ddg:platformFeatures';
5+
import { registerForURLChanges } from './url-change';
56

67
let initArgs = null;
78
const updates = [];
@@ -74,6 +75,9 @@ export async function init(args) {
7475
resolvedFeatures.forEach(({ featureInstance, featureName }) => {
7576
if (!isFeatureBroken(args, featureName) || alwaysInitExtensionFeatures(args, featureName)) {
7677
featureInstance.callInit(args);
78+
if (featureInstance.listenForUrlChanges) {
79+
registerForURLChanges((args) => featureInstance.urlChanged(args));
80+
}
7781
}
7882
});
7983
// Fire off updates that came in faster than the init

injected/src/features/autofill-password-import.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const DELAY_BEFORE_ANIMATION = 300;
3434
* 3. Animate the element, or tap it if it should be autotapped.
3535
*/
3636
export default class AutofillPasswordImport extends ContentFeature {
37+
listenForUrlChanges = true;
3738
#exportButtonSettings;
3839

3940
#settingsButtonSettings;
@@ -490,23 +491,15 @@ export default class AutofillPasswordImport extends ContentFeature {
490491
this.#settingsButtonSettings = this.getFeatureSetting('settingsButton');
491492
}
492493

494+
urlChanged(site) {
495+
this.handlePath();
496+
super.urlChanged(site)
497+
}
498+
493499
init() {
494500
this.setButtonSettings();
495501

496502
const handlePath = this.handlePath.bind(this);
497-
const historyMethodProxy = new DDGProxy(this, History.prototype, 'pushState', {
498-
async apply(target, thisArg, args) {
499-
const path = args[1] === '' ? args[2].split('?')[0] : args[1];
500-
await handlePath(path);
501-
return DDGReflect.apply(target, thisArg, args);
502-
},
503-
});
504-
historyMethodProxy.overload();
505-
// listen for popstate events in order to run on back/forward navigations
506-
window.addEventListener('popstate', async () => {
507-
const path = window.location.pathname;
508-
await handlePath(path);
509-
});
510503

511504
this.#domLoaded = new Promise((resolve) => {
512505
if (document.readyState !== 'loading') {

injected/src/features/element-hiding.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ function forgivingSelector(selector) {
302302
}
303303

304304
export default class ElementHiding extends ContentFeature {
305+
listenForUrlChanges = true;
305306
init() {
306307
// eslint-disable-next-line @typescript-eslint/no-this-alias
307308
featureInstance = this;
@@ -360,19 +361,12 @@ export default class ElementHiding extends ContentFeature {
360361
} else {
361362
applyRules(activeRules);
362363
}
363-
// single page applications don't have a DOMContentLoaded event on navigations, so
364-
// we use proxy/reflect on history.pushState to call applyRules on page navigations
365-
const historyMethodProxy = new DDGProxy(this, History.prototype, 'pushState', {
366-
apply(target, thisArg, args) {
367-
applyRules(activeRules);
368-
return DDGReflect.apply(target, thisArg, args);
369-
},
370-
});
371-
historyMethodProxy.overload();
372-
// listen for popstate events in order to run on back/forward navigations
373-
window.addEventListener('popstate', () => {
374-
applyRules(activeRules);
375-
});
364+
this.activeRules = activeRules;
365+
}
366+
367+
urlChanged(site) {
368+
this.applyRules(this.activeRules);
369+
super.urlChanged(site)
376370
}
377371

378372
/**

injected/src/url-change.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { DDGProxy, DDGReflect, computeLimitedSiteObject } from './utils.js';
2+
3+
const urlChangeListeners = new Set();
4+
/**
5+
* Register a listener to be called when the URL changes.
6+
* @param {function} listener
7+
*/
8+
export function registerForURLChanges(listener) {
9+
if (urlChangeListeners.size === 0) {
10+
listenForURLChanges();
11+
}
12+
urlChangeListeners.add(listener);
13+
}
14+
15+
function handleURLChange() {
16+
const site = computeLimitedSiteObject();
17+
for (const listener of urlChangeListeners) {
18+
listener.urlChanged(site);
19+
}
20+
}
21+
22+
function listenForURLChanges() {
23+
// single page applications don't have a DOMContentLoaded event on navigations, so
24+
// we use proxy/reflect on history.pushState to call applyRules on page navigations
25+
const historyMethodProxy = new DDGProxy(this, History.prototype, 'pushState', {
26+
apply(target, thisArg, args) {
27+
handleURLChange();
28+
return DDGReflect.apply(target, thisArg, args);
29+
},
30+
});
31+
historyMethodProxy.overload();
32+
// listen for popstate events in order to run on back/forward navigations
33+
window.addEventListener('popstate', () => {
34+
handleURLChange();
35+
});
36+
}

0 commit comments

Comments
 (0)