Skip to content

Commit 5ef4793

Browse files
authored
Merge pull request #6 from vernonthedev/develop
refactor: migrated project structure and added tests
2 parents c4b127d + da6ace7 commit 5ef4793

77 files changed

Lines changed: 26786 additions & 1648 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.babelrc.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"presets": [
3+
[
4+
"@babel/preset-env",
5+
{
6+
"targets": {
7+
"node": "current"
8+
}
9+
}
10+
]
11+
]
12+
}

content.js renamed to assets/content.js.backup

Lines changed: 159 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,40 @@ class GitHubGitLabTheme {
4343
this.setupNavigationListener();
4444
}
4545

46+
isRepositoryPage() {
47+
const pathname = window.location.pathname;
48+
49+
// Check for user profile repositories page
50+
if (pathname.match(/^\/[^\/]+$/)) {
51+
const pageHeader = document.querySelector('h1');
52+
if (pageHeader && pageHeader.textContent.includes('Repositories')) {
53+
return true;
54+
}
55+
}
56+
57+
// Check for user repositories tab
58+
if (pathname.includes('?tab=repositories')) {
59+
return true;
60+
}
61+
62+
// Check for organization repositories page
63+
if (pathname.includes('/orgs/') &&
64+
(pathname.includes('/repositories') ||
65+
document.querySelector('[data-test-selector="org-repositories-list"]'))) {
66+
return true;
67+
}
68+
69+
// Check for repository list containers
70+
const repoContainers = [
71+
'#user-repositories-list',
72+
'#org-repositories-list',
73+
'[data-testid="repository-list-container"]',
74+
'div[data-test-selector="org-repositories-list"]'
75+
];
76+
77+
return repoContainers.some(selector => document.querySelector(selector));
78+
}
79+
4680
setupNavigationListener() {
4781
// Listen for URL changes (GitHub is an SPA)
4882
let currentUrl = window.location.href;
@@ -55,7 +89,7 @@ class GitHubGitLabTheme {
5589
this.run();
5690
}, 500);
5791
}
58-
}).observe(document, { subtree: true, childList: true });
92+
}).observe(document.body, { subtree: true, childList: true });
5993
}
6094

6195
applyDarkTheme() {
@@ -182,10 +216,25 @@ class GitHubGitLabTheme {
182216
await this.saveSetting('customGroups', Array.from(this.customGroups));
183217
}
184218

185-
run() {
219+
run() {
220+
// Only run on repository-related pages
221+
if (!this.isRepositoryPage()) {
222+
console.log('[GitLab Theme] Not a repository page, skipping processing');
223+
return;
224+
}
225+
186226
// Apply dark theme first
187227
this.applyDarkTheme();
188228

229+
// Check if we're on an organization page for debugging
230+
const isOrgPage = window.location.pathname.includes('/orgs/') ||
231+
window.location.pathname.match(/^\/[^\/]+$/) &&
232+
document.querySelector('[data-test-selector="org-header"]');
233+
234+
if (isOrgPage) {
235+
console.log('[GitLab Theme] Organization page detected');
236+
}
237+
189238
// Setup observer for dynamic content
190239
this.setupMutationObserver();
191240

@@ -194,7 +243,7 @@ class GitHubGitLabTheme {
194243
this.processRepositories();
195244
}
196245

197-
setupMutationObserver() {
246+
setupMutationObserver() {
198247
if (this.observer) this.observer.disconnect();
199248

200249
this.observer = new MutationObserver((mutations) => {
@@ -211,36 +260,56 @@ class GitHubGitLabTheme {
211260
if (shouldProcess) {
212261
if (this.debounceTimer) clearTimeout(this.debounceTimer);
213262
this.debounceTimer = setTimeout(() => {
214-
this.addGroupControls();
215-
this.processRepositories();
263+
// Only process if we're still on a repository page
264+
if (this.isRepositoryPage()) {
265+
this.addGroupControls();
266+
this.processRepositories();
267+
}
216268
}, 300);
217269
}
218270
});
219271

220-
this.observer.observe(document.body, {
221-
childList: true,
222-
subtree: true
272+
// Only observe specific containers, not the entire body
273+
const targetSelectors = [
274+
'#user-repositories-list',
275+
'#org-repositories-list',
276+
'[data-testid="repository-list-container"]',
277+
'div[data-test-selector="org-repositories-list"]',
278+
'main[role="main"]'
279+
];
280+
281+
targetSelectors.forEach(selector => {
282+
const element = document.querySelector(selector);
283+
if (element) {
284+
this.observer.observe(element, {
285+
childList: true,
286+
subtree: true
287+
});
288+
}
223289
});
224290
}
225291

226-
findRepositoryContainers() {
292+
findRepositoryContainers() {
227293
const selectors = [
228294
'#user-repositories-list',
229295
'#org-repositories-list',
230296
'[data-testid="repository-list-container"]',
231-
'.repo-list',
232297
'[data-filterable-for="your-repos-filter"]',
298+
'[data-filterable-for="org-repos-filter"]',
233299
'.js-repo-list',
234300
'ul[data-test-selector="profile-repository-list"]',
235-
'div[aria-label="Repositories"]'
301+
'div[aria-label="Repositories"]',
302+
// Org page specific selectors
303+
'div[data-test-selector="org-repositories-list"]',
304+
'[data-test-selector="org-repo-list"]'
236305
];
237306

238307
const containers = [];
239308
selectors.forEach(selector => {
240309
try {
241310
const elements = document.querySelectorAll(selector);
242311
elements.forEach(el => {
243-
if (el && !this.processedContainers.has(el)) {
312+
if (el && !this.processedContainers.has(el) && this.isValidRepositoryContainer(el)) {
244313
containers.push(el);
245314
this.processedContainers.add(el);
246315
}
@@ -250,9 +319,16 @@ class GitHubGitLabTheme {
250319
}
251320
});
252321

322+
console.log(`[GitLab Theme] Found ${containers.length} repository containers`);
253323
return containers;
254324
}
255325

326+
isValidRepositoryContainer(container) {
327+
// Check if container has repository items
328+
const repoItems = this.findRepositoryItems(container);
329+
return repoItems.length > 0;
330+
}
331+
256332
findRepositoryItems(container) {
257333
const itemSelectors = [
258334
'[itemprop="owns"]',
@@ -264,15 +340,21 @@ class GitHubGitLabTheme {
264340
'.fork',
265341
'.archived',
266342
'li[itemprop="owns"]',
267-
'div[data-testid="repository-item"]'
343+
'div[data-testid="repository-item"]',
344+
// Org page specific selectors
345+
'li[data-test-selector="repository-list-item"]',
346+
'div[data-test-selector="repository-list-item"]',
347+
'.Box-row', // GitHub uses Box-row for repo items on org pages
348+
'li[itemprop="codeRepository"]',
349+
'div[itemprop="codeRepository"]'
268350
];
269351

270352
let items = [];
271353
itemSelectors.forEach(selector => {
272354
try {
273355
const found = container.querySelectorAll(selector);
274356
found.forEach(item => {
275-
const nameElement = item.querySelector('h3 a, a[itemprop="name codeRepository"], .wb-break-all a, [data-testid="repository-name"]');
357+
const nameElement = item.querySelector('h3 a, a[itemprop="name codeRepository"], .wb-break-all a, [data-testid="repository-name"], [itemprop="name"], .Link--primary');
276358
if (nameElement && !items.includes(item)) {
277359
items.push(item);
278360
}
@@ -285,7 +367,7 @@ class GitHubGitLabTheme {
285367
return items;
286368
}
287369

288-
processRepositories() {
370+
processRepositories() {
289371
if (this.isProcessing) return;
290372
this.isProcessing = true;
291373

@@ -299,12 +381,15 @@ class GitHubGitLabTheme {
299381
const items = this.findRepositoryItems(container);
300382

301383
if (items.length > 0) {
302-
if (this.groupingEnabled) {
303-
this.createGroupCards(container, items);
304-
} else {
305-
this.displayAllRepos(container, items);
384+
// Only process if container hasn't been processed already
385+
if (!container.dataset.gitlabProcessed) {
386+
if (this.groupingEnabled) {
387+
this.createGroupCards(container, items);
388+
} else {
389+
this.displayAllRepos(container, items);
390+
}
391+
container.dataset.gitlabProcessed = 'true';
306392
}
307-
container.dataset.gitlabProcessed = 'true';
308393
}
309394
});
310395

@@ -315,46 +400,56 @@ class GitHubGitLabTheme {
315400
}
316401
}
317402

318-
createGroupCards(container, items) {
403+
createGroupCards(container, items) {
319404
const groups = this.extractGroups(items);
320405

321406
if (groups.size <= 1) {
322407
this.displayAllRepos(container, items);
323408
return;
324409
}
325410

326-
// Clear existing content
327-
container.innerHTML = '';
328-
container.classList.add('gitlab-grouped-repositories');
329-
330-
const fragment = document.createDocumentFragment();
411+
// Store original content and clear container safely
412+
const originalContent = container.innerHTML;
413+
const originalClasses = container.className;
331414

332-
// Create group cards section
333-
const groupCardsSection = this.createGroupCardsSection(groups, container);
334-
fragment.appendChild(groupCardsSection);
415+
try {
416+
container.innerHTML = '';
417+
container.classList.add('gitlab-grouped-repositories');
335418

336-
// Create hidden repo containers for each group
337-
const repoContainersSection = this.createRepoContainers(groups, container);
338-
fragment.appendChild(repoContainersSection);
419+
const fragment = document.createDocumentFragment();
420+
421+
// Create group cards section
422+
const groupCardsSection = this.createGroupCardsSection(groups, container);
423+
fragment.appendChild(groupCardsSection);
339424

340-
container.appendChild(fragment);
425+
// Create hidden repo containers for each group
426+
const repoContainersSection = this.createRepoContainers(groups, container);
427+
fragment.appendChild(repoContainersSection);
341428

342-
// Show the first group by default
343-
const firstGroup = Array.from(groups.keys())[0];
344-
console.log(`[GitLab Theme] Auto-showing first group: ${firstGroup}`);
345-
346-
// Wait a bit for DOM to settle, then simulate first group click
347-
setTimeout(() => {
348-
console.log(`[GitLab Theme] Attempting to show first group...`);
349-
const firstCard = container.querySelector(`.gitlab-group-card[data-group-id="${firstGroup}"]`);
350-
if (firstCard) {
351-
console.log(`[GitLab Theme] Found first group card, simulating click`);
352-
firstCard.click();
353-
} else {
354-
console.error(`[GitLab Theme] Could not find first group card: ${firstGroup}`);
355-
console.log(`[GitLab Theme] Available cards:`, container.querySelectorAll('.gitlab-group-card'));
356-
}
357-
}, 200);
429+
container.appendChild(fragment);
430+
431+
// Show the first group by default
432+
const firstGroup = Array.from(groups.keys())[0];
433+
console.log(`[GitLab Theme] Auto-showing first group: ${firstGroup}`);
434+
435+
// Wait a bit for DOM to settle, then simulate first group click
436+
setTimeout(() => {
437+
console.log(`[GitLab Theme] Attempting to show first group...`);
438+
const firstCard = container.querySelector(`.gitlab-group-card[data-group-id="${firstGroup}"]`);
439+
if (firstCard) {
440+
console.log(`[GitLab Theme] Found first group card, simulating click`);
441+
firstCard.click();
442+
} else {
443+
console.error(`[GitLab Theme] Could not find first group card: ${firstGroup}`);
444+
console.log(`[GitLab Theme] Available cards:`, container.querySelectorAll('.gitlab-group-card'));
445+
}
446+
}, 200);
447+
} catch (error) {
448+
console.error('[GitLab Theme] Error creating group cards, reverting to original content:', error);
449+
container.innerHTML = originalContent;
450+
container.className = originalClasses;
451+
this.displayAllRepos(container, items);
452+
}
358453
}
359454

360455
extractGroups(items) {
@@ -568,7 +663,12 @@ class GitHubGitLabTheme {
568663
reposSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
569664
}
570665

571-
displayAllRepos(container, items) {
666+
displayAllRepos(container, items) {
667+
// Only modify if we haven't already processed this container
668+
if (container.dataset.gitlabProcessed === 'true') {
669+
return;
670+
}
671+
572672
const fragment = document.createDocumentFragment();
573673

574674
items.forEach(item => {
@@ -593,12 +693,15 @@ class GitHubGitLabTheme {
593693
'h3 a',
594694
'a[itemprop="name codeRepository"]',
595695
'.wb-break-all a',
596-
'[data-testid="repository-name"]'
696+
'[data-testid="repository-name"]',
697+
'[itemprop="name"]',
698+
'.Link--primary',
699+
'a[href*="/"][title]'
597700
];
598701

599702
for (const selector of nameSelectors) {
600703
const element = item.querySelector(selector);
601-
if (element) {
704+
if (element && element.textContent.trim()) {
602705
return element.textContent.trim();
603706
}
604707
}
@@ -635,7 +738,10 @@ class GitHubGitLabTheme {
635738
const repoSections = [
636739
'#user-repositories-list',
637740
'#org-repositories-list',
638-
'[data-testid="repository-list-container"]'
741+
'[data-testid="repository-list-container"]',
742+
'div[data-test-selector="org-repositories-list"]',
743+
'.org-repos',
744+
'#org-repositories'
639745
];
640746

641747
for (const selector of repoSections) {

0 commit comments

Comments
 (0)