Skip to content

Commit

Permalink
fix: fatal issue 382 (#396)
Browse files Browse the repository at this point in the history
* fix: unwanted duplication when going forward/backward in browser history

* refactor: trigger perceptor.run() after tab url changes

* fix: fluent UI will not lost its style sheets after page navigation

* refactor: perfect way to trigger mainInject()

* docs: add some comments

* chore: remove "tabs" permission since it is not needed in the new strategy
  • Loading branch information
tyn1998 authored Jul 12, 2022
1 parent 1771cc7 commit 31688ff
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 42 deletions.
8 changes: 6 additions & 2 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@
],
"web_accessible_resources": [
{
"resources": ["content.styles.css", "main.png"],
"matches": []
"resources": [
"content.styles.css",
"main.png",
"injectedScript.bundle.js"
],
"matches": ["<all_urls>"]
}
],
"permissions": ["storage", "notifications", "alarms", "cookies"],
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ chrome.notifications.onClicked.addListener(async function (notificationId) {
chrome.notifications.clear(notificationId);
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const type = request.task_type;
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const type = message.task_type;
if (type === 'get_username_from_cookie') {
chrome.cookies.get(
{
Expand Down
34 changes: 25 additions & 9 deletions src/pages/ContentScripts/DeveloperActiInflTrend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,35 @@ class DeveloperActiInflTrend extends PerceptorBase {
}

public async run(): Promise<void> {
const profileArea = $('.js-profile-editable-area').parent();
const newContainer = document.createElement('div');
newContainer.id = 'developer-acti-infl-trend';
newContainer.style.width = '100%';
this._currentDeveloper = $('.p-nickname.vcard-username.d-block')
.text()
.trim();

render(
<DeveloperActiInflTrendView currentDeveloper={this._currentDeveloper} />,
newContainer
);
profileArea.after(newContainer);
let profileArea = null;
let newContainer = null;

// if exists (when going backword or forward in browser history)
if (document.getElementById('developer-acti-infl-trend') != null) {
render(
<DeveloperActiInflTrendView
currentDeveloper={this._currentDeveloper}
/>,
document.getElementById('developer-acti-infl-trend')
);
} else {
profileArea = $('.js-profile-editable-area').parent();
newContainer = document.createElement('div');
newContainer.id = 'developer-acti-infl-trend';
newContainer.style.width = '100%';

render(
<DeveloperActiInflTrendView
currentDeveloper={this._currentDeveloper}
/>,
newContainer
);
profileArea.after(newContainer);
}
}
}

Expand Down
40 changes: 28 additions & 12 deletions src/pages/ContentScripts/DeveloperNetwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,22 +366,38 @@ class DeveloperNetwork extends PerceptorBase {
}

public async run(): Promise<void> {
const profileArea = $('.js-profile-editable-area').parent();
const DeveloperNetworkDiv = document.createElement('div');
DeveloperNetworkDiv.id = 'developer-network';
DeveloperNetworkDiv.style.width = '100%';
this._currentDeveloper = $('.p-nickname.vcard-username.d-block')
.text()
.trim();

let profileArea = null;
let DeveloperNetworkDiv = null;

const settings = await loadSettings();
render(
<DeveloperNetworkView
currentDeveloper={this._currentDeveloper}
graphType={settings.graphType}
/>,
DeveloperNetworkDiv
);
profileArea.after(DeveloperNetworkDiv);

// if exists (when going backword or forward in browser history)
if (document.getElementById('developer-network') != null) {
render(
<DeveloperNetworkView
currentDeveloper={this._currentDeveloper}
graphType={settings.graphType}
/>,
document.getElementById('developer-network')
);
} else {
profileArea = $('.js-profile-editable-area').parent();
DeveloperNetworkDiv = document.createElement('div');
DeveloperNetworkDiv.id = 'developer-network';
DeveloperNetworkDiv.style.width = '100%';
render(
<DeveloperNetworkView
currentDeveloper={this._currentDeveloper}
graphType={settings.graphType}
/>,
DeveloperNetworkDiv
);
profileArea.after(DeveloperNetworkDiv);
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions src/pages/ContentScripts/PerceptorLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ const PerceptorLayoutView: React.FC = () => {
class PerceptorLayout extends PerceptorBase {
public async run(): Promise<void> {
// remove the original container
const parentContainer = $('#repo-content-pjax-container').children(
'div.clearfix.container-xl'
);
const parentContainer = $('div.clearfix.container-xl:first');
parentContainer.children('div.Layout').remove();

// create the new one : percepter container
Expand Down
40 changes: 28 additions & 12 deletions src/pages/ContentScripts/ProjectNetwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,36 @@ class ProjectNetwork extends PerceptorBase {
this._currentRepo = '';
}
public async run(): Promise<void> {
const perceptorContainer = $('#perceptor-layout').children();
const ProjectNetworkDiv = document.createElement('div');
ProjectNetworkDiv.id = 'project-network';
ProjectNetworkDiv.style.width = '100%';
this._currentRepo = utils.getRepositoryInfo(window.location)!.nameWithOwner;

let perceptorContainer = null;
let ProjectNetworkDiv = null;

const settings = await loadSettings();
render(
<ProjectNetworkView
currentRepo={this._currentRepo}
graphType={settings.graphType}
/>,
ProjectNetworkDiv
);
perceptorContainer.prepend(ProjectNetworkDiv);

// if exists (when going backword or forward in browser history)
if (document.getElementById('project-network') != null) {
render(
<ProjectNetworkView
currentRepo={this._currentRepo}
graphType={settings.graphType}
/>,
document.getElementById('project-network')
);
} else {
perceptorContainer = $('#perceptor-layout').children();
ProjectNetworkDiv = document.createElement('div');
ProjectNetworkDiv.id = 'project-network';
ProjectNetworkDiv.style.width = '100%';
render(
<ProjectNetworkView
currentRepo={this._currentRepo}
graphType={settings.graphType}
/>,
ProjectNetworkDiv
);
perceptorContainer.prepend(ProjectNetworkDiv);
}
}
}

Expand Down
23 changes: 22 additions & 1 deletion src/pages/ContentScripts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
// content script lives in an isolated world, which means it
// cannot access to host page's javascript context such as
// adding an extra event handler to a registered event in host
// page. However, we can use injected scripts to run some code
// that can access to host page's context.
const injected = document.createElement('script');
injected.src = chrome.runtime.getURL('injectedScript.bundle.js');
console.log(injected);
injected.onload = function () {
injected.remove(); // after the script run, it can be removed
};
(document.head || document.documentElement).appendChild(injected);

// initializeIcons() should only be called once per app and must be called before rendering any components.
import { initializeIcons } from '@fluentui/react/lib/Icons';
initializeIcons();
Expand All @@ -15,6 +28,7 @@ import Hypertrons from './Hypertrons';

import './content.styles.css';

// inject to Perceptor's static variable
inject2Perceptor(DeveloperActiInflTrend);
inject2Perceptor(RepoActiInflTrend);
inject2Perceptor(PerceptorTab);
Expand All @@ -31,4 +45,11 @@ async function mainInject() {
}
}

mainInject();
// if receive "turbo:load" from injected script, run mainInject()
window.addEventListener('message', function (event) {
// Only accept messages from the same frame
if (event.source !== window) return;
if (event.data === 'turbo:load') {
mainInject();
}
});
36 changes: 36 additions & 0 deletions src/pages/InjectedScripts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This is an injected script, which shares same js context with the host page.

// I infer that GitHub uses hotwired/turbo to speedup its SPA.
// Fortunately there are some events to hook our code in GitHub
// life cycle. See: https://turbo.hotwired.dev/reference/events

// FluentUI is a css-in-js UI library, all styles are dynamicly
// computed and injected to several style tags, like:
//
// <head>
// <style data-merge-styles="true"></style>
// <style data-merge-styles="true"></style>
// <style data-merge-styles="true"></style>
// </head>
//
// Thease tags are only computed once for each component. But the
// style tags are regarded as "provisional elements" by turbo and
// most of them will be removed after each trubo:visit, leading to
// style crash.
//
// After reading the source code of turbo, I figure out a workaround.
// By adding an id to all <style data-merge-styles="true"></style>
// to make their outerHtml not be same, turbo will not regard them
// as provisional elements and will keep them in headers.

document.addEventListener('turbo:before-visit', () => {
[...document.getElementsByTagName('style')].forEach((element, index) => {
if (element.hasAttribute('data-merge-styles')) {
element.setAttribute('data-id', index + '');
}
});
});

document.addEventListener('turbo:load', () => {
window.postMessage('turbo:load', '*');
});
9 changes: 8 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@ let options = {
'ContentScripts',
'index.ts'
),
injectedScript: path.join(
__dirname,
'src',
'pages',
'InjectedScripts',
'index.ts'
),
},
// "custom" is not a standard key of webpack options
// it will be consumed by utils/server.js and must be deleted before webpack(config)
custom: {
notHMR: ['background', 'contentScript'],
notHMR: ['background', 'contentScript', 'injectedScript'],
enableBackgroundAutoReload: true, // always true when "enableContentScriptsAutoReload" is set true
enableContentScriptsAutoReload: true,
},
Expand Down

0 comments on commit 31688ff

Please sign in to comment.