Skip to content

Commit 7b60460

Browse files
committed
Update content.js
1 parent 4640407 commit 7b60460

1 file changed

Lines changed: 206 additions & 171 deletions

File tree

extension/content.js

Lines changed: 206 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,184 +1,219 @@
11
(() => {
2-
const n = "GitFolderDownloader-modal";
3-
4-
function e(e) {
5-
const linkPadding = e === "repo" ? "revert-layer" : "0";
6-
7-
// Determine context (Repo, Folder, or File)
8-
const o = (function () {
9-
const n = location.pathname.split("/").filter(Boolean);
10-
return 2 === n.length
11-
? { type: "repo", name: `${n[0]}-${n[1]}` }
12-
: n.includes("tree")
13-
? { type: "folder", name: n[n.length - 1] }
14-
: n.includes("blob")
15-
? { type: "file", name: n[n.length - 1] }
16-
: { type: "unknown", name: "github-download" };
17-
})(),
18-
t = document.createElement("li");
19-
20-
var r;
21-
return (
22-
(t.className = "prc-ActionList-ActionListItem-So4vC"),
23-
(t.innerHTML = `<a class="prc-ActionList-ActionListContent-KBb8- prc-Link-Link-9ZwDx" role="menuitem" tabindex="-1" data-GitFolderDownloader="${e}" style="padding:${linkPadding};">
2+
const MODAL_ID = "GitFolderDownloader-modal";
3+
4+
let __dg_prevOverflow = null;
5+
6+
function lockBodyScroll() {
7+
__dg_prevOverflow = document.body.style.overflow;
8+
document.body.style.overflow = "hidden";
9+
}
10+
11+
function unlockBodyScroll() {
12+
document.body.style.overflow = __dg_prevOverflow || "";
13+
}
14+
15+
function createMenuItem(kind) {
16+
const linkPadding = kind === "repo" ? "revert-layer" : "0";
17+
18+
const ctx = (function () {
19+
const parts = location.pathname.split("/").filter(Boolean);
20+
return 2 === parts.length
21+
? { type: "repo", name: `${parts[0]}-${parts[1]}` }
22+
: parts.includes("tree")
23+
? { type: "folder", name: parts[parts.length - 1] }
24+
: parts.includes("blob")
25+
? { type: "file", name: parts[parts.length - 1] }
26+
: { type: "unknown", name: "github-download" };
27+
})();
28+
29+
const li = document.createElement("li");
30+
li.className = "prc-ActionList-ActionListItem-So4vC";
31+
li.innerHTML = `<a class="prc-ActionList-ActionListContent-KBb8- prc-Link-Link-9ZwDx" role="menuitem" tabindex="-1" data-GitFolderDownloader="${kind}" style="padding:${linkPadding};">
2432
<span class="prc-ActionList-Spacer-4tR2m"></span>
2533
<span class="prc-ActionList-LeadingVisual-NBr28 prc-ActionList-VisualWrap-bdCsS">
26-
${
27-
((r = e),
28-
"repo" === r
29-
? '<svg aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg>'
30-
: "folder" === r
31-
? '<svg style="width: 0;height: 0;"></svg>'
32-
: '<svg style="width: 0;height: 0;"></svg>')
34+
${kind === "repo"
35+
? '<svg aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg>'
36+
: '<svg style="width: 0;height: 0;"></svg>'
3337
}
34-
</span>
38+
</span>
3539
<span class="prc-ActionList-ActionListSubContent-gKsFp" data-component="ActionList.Item--DividerContainer">
3640
<span class="prc-ActionList-ItemLabel-81ohH">
37-
${
38-
((r = e),
39-
"repo" === r
40-
? "Download Repo"
41-
: "folder" === r
41+
${kind === "repo"
42+
? "Download Repo"
43+
: kind === "folder"
4244
? "Download Folder"
43-
: "Download")
45+
: "Download"
4446
}
45-
</span></span></a>`),
46-
(t.onclick = () => {
47-
// Modal Logic
48-
!(function (defaultName, callback) {
49-
if (document.getElementById(n)) return;
50-
document.documentElement.dataset.colorMode;
51-
const t = document.createElement("div");
52-
(t.id = n),
53-
(t.innerHTML = `
54-
<style>
55-
#${n} {position: fixed; inset: 0; z-index: 99999; display: flex; align-items: center; justify-content: center;}
56-
.modal-overlay {display: block; position: fixed; width: -webkit-fill-available; height: -webkit-fill-available;}
57-
.dg-box {
58-
background:var(--overlay-bgColor,var(--color-canvas-overlay));
59-
color: var(--fgColor-default);
60-
width: 340px; padding: 16px;
61-
border-radius: 12px; border: 1px solid var(--color-border-default);
62-
box-shadow:var(--shadow-floating-small,var(--color-overlay-shadow));
63-
font-family: system-ui;
64-
animation:prc-Overlay-overlay-appear-JpFey .2s cubic-bezier(.33,1,.68,1); z-index:10001;
65-
}
66-
.dg-box h3 {
67-
text-align: center; background-color: initial;
68-
color: var(--fgColor-default,var(--color-fg-default));
69-
font-size: 18px; font-weight: 700; margin: 0 auto 10px;
70-
}
71-
.dg-label {
72-
font-size: 12px; font-weight: 600; margin-top: 8px; display: block;
73-
color: var(--fgColor-default, var(--color-fg-default));
74-
}
75-
.dg-box input {
76-
width: 100%; padding: 8px; margin-top: 4px;
77-
border-radius: 8px; background: var(--bgColor-disabled);
78-
border: 1px solid var(--control-borderColor-rest, var(--color-border-default));
79-
outline: none; color: var(--fgColor-default, var(--color-fg-default));
80-
}
81-
.dg-box input:focus { outline: 2px solid var(--color-accent-fg); }
82-
.dg-row { display: flex; gap: 10px; }
83-
.dg-col { flex: 1; }
84-
.dg-actions {
85-
margin-top: 20px; font-weight: 800; display: flex; justify-content: space-around;
86-
}
87-
.dg-actions button {
88-
padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; font-size: 13px;
89-
}
90-
.dg-cancel { background: var(--button-default-bgColor-rest); }
91-
.dg-cancel:hover { background: var(--button-default-bgColor-hover); }
92-
.dg-confirm {
93-
background: var(--button-primary-bgColor-rest);
94-
color:var(--button-primary-fgColor-rest,var(--color-btn-primary-text));
95-
}
96-
.dg-confirm:hover { background: var(--button-primary-bgColor-hover); }
97-
</style>
98-
<div class="modal-overlay"></div>
99-
<div class="dg-box">
100-
<h3>Download Options</h3>
101-
102-
<label class="dg-label">Name</label>
103-
<input id="dg-name" value="${defaultName}" placeholder="File name"/>
104-
105-
<div class="dg-row">
106-
<div class="dg-col">
107-
<label class="dg-label">st (Start)</label>
108-
<input id="dg-st" type="number" placeholder="0" />
109-
</div>
110-
<div class="dg-col">
111-
<label class="dg-label">mx (Max)</label>
112-
<input id="dg-mx" type="number" placeholder="0" />
113-
</div>
114-
</div>
115-
116-
<div class="dg-actions">
117-
<button class="dg-cancel">Cancel</button>
118-
<button class="dg-confirm">Download</button>
119-
</div>
120-
</div>
121-
`),
122-
document.body.appendChild(t),
123-
t.querySelector(".modal-overlay").addEventListener("click", () => {
124-
t.remove();
125-
}),
126-
t.querySelector(".dg-cancel").addEventListener("click", () => {
127-
t.remove();
128-
}),
129-
t.querySelector(".dg-confirm").addEventListener("click", () => {
130-
// Retrieve values
131-
const nameVal = t.querySelector("#dg-name").value.trim() || defaultName;
132-
const stVal = t.querySelector("#dg-st").value.trim();
133-
const mxVal = t.querySelector("#dg-mx").value.trim();
134-
135-
t.remove();
136-
callback(nameVal, stVal, mxVal);
137-
}),
138-
document.addEventListener(
139-
"keydown",
140-
(n) => {
141-
"Escape" === n.key && t.remove();
142-
},
143-
{ once: !0 }
144-
);
145-
})(o.name, (name, st, mx) => {
146-
// Construct URL
147-
let finalUrl = `https://GitFolderDownloader.github.io/api/?url=${encodeURIComponent(location.href)}&name=${encodeURIComponent(name)}`;
148-
149-
if(st) finalUrl += `&st=${encodeURIComponent(st)}`;
150-
if(mx) finalUrl += `&mx=${encodeURIComponent(mx)}`;
151-
152-
window.open(finalUrl, "_blank");
153-
});
154-
}),
155-
t
156-
);
47+
</span></span></a>`;
48+
49+
const anchor = li.querySelector("a");
50+
anchor.addEventListener("pointerdown", (evt) => {
51+
if (evt.button !== 0) return;
52+
53+
evt.preventDefault();
54+
evt.stopPropagation();
55+
showModalAndOpen(ctx.name, ctx.type);
56+
});
57+
58+
59+
return li;
15760
}
15861

159-
function o() {
160-
document
161-
.querySelectorAll("ul.prc-ActionList-ActionList-rPFF2")
162-
.forEach((n) => {
163-
const o = (function (n) {
164-
const e = n.innerText;
165-
return e.includes("Download ZIP")
166-
? "repo"
167-
: e.includes("Copy path") && !e.includes("Raw file")
62+
function showModalAndOpen(defaultName, type = "repo") {
63+
if (document.getElementById(MODAL_ID)) return;
64+
65+
const t = document.createElement("div");
66+
t.id = MODAL_ID;
67+
t.innerHTML = `
68+
<style>
69+
#${MODAL_ID} {position: fixed; inset: 0; z-index: 99999; display: flex; align-items: center; justify-content: center;}
70+
.modal-overlay {display: block; position: fixed; width: -webkit-fill-available; height: -webkit-fill-available;}
71+
.dg-box {
72+
background:var(--overlay-bgColor,var(--color-canvas-overlay));
73+
color: var(--fgColor-default);
74+
width: 340px; padding: 16px;
75+
border-radius: 12px; border: 1px solid var(--color-border-default);
76+
box-shadow:var(--shadow-floating-small,var(--color-overlay-shadow));
77+
font-family: system-ui;
78+
animation:prc-Overlay-overlay-appear-JpFey .2s cubic-bezier(.33,1,.68,1); z-index:10001;
79+
}
80+
.dg-box h3 {
81+
text-align: center; background-color: initial;
82+
color: var(--fgColor-default,var(--color-fg-default));
83+
font-size: 18px; font-weight: 700; margin: 0 auto 10px;
84+
}
85+
.dg-label {
86+
font-size: 12px; font-weight: 600; margin-top: 8px; display: block;
87+
color: var(--fgColor-default, var(--color-fg-default));
88+
}
89+
.dg-box input {
90+
width: 100%; padding: 8px; margin-top: 4px;
91+
border-radius: 8px; background: var(--bgColor-disabled);
92+
border: 1px solid var(--control-borderColor-rest, var(--color-border-default));
93+
outline: none; color: var(--fgColor-default, var(--color-fg-default));
94+
}
95+
.dg-box input:focus { outline: 2px solid var(--color-accent-fg); }
96+
.dg-row { display: flex; gap: 10px; }
97+
.dg-col { flex: 1; }
98+
.dg-actions {
99+
margin-top: 20px; font-weight: 800; display: flex; justify-content: space-around;
100+
}
101+
.dg-actions button {
102+
padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; font-size: 13px;
103+
}
104+
.dg-cancel { background: var(--button-default-bgColor-rest); }
105+
.dg-cancel:hover { background: var(--button-default-bgColor-hover); }
106+
.dg-confirm {
107+
background: var(--button-primary-bgColor-rest);
108+
color:var(--button-primary-fgColor-rest,var(--color-btn-primary-text));
109+
}
110+
.dg-confirm:hover { background: var(--button-primary-bgColor-hover); }
111+
</style>
112+
<div class="modal-overlay"></div>
113+
<div class="dg-box">
114+
<h3>Download Options</h3>
115+
<label class="dg-label">Set Name</label>
116+
<input id="dg-name" value="${defaultName}" placeholder="File name"/>
117+
118+
119+
${type !== "file"
120+
? `
121+
<h5 style="margin: 10px auto 0;">Set files range</h5>
122+
<div class="dg-row">
123+
<div class="dg-col">
124+
<label class="dg-label">From</label>
125+
<input id="dg-st" min="0" type="number" placeholder="from 0" />
126+
</div>
127+
<div class="dg-col">
128+
<label class="dg-label">To</label>
129+
<input id="dg-mx" min="0" type="number" placeholder="to all" />
130+
</div>
131+
</div>
132+
`
133+
: ""
134+
}
135+
136+
<div class="dg-actions">
137+
<button class="dg-cancel">Cancel</button>
138+
<button class="dg-confirm">Download</button>
139+
</div>
140+
</div>
141+
142+
`;
143+
144+
document.body.appendChild(t);
145+
lockBodyScroll();
146+
147+
//const removeModal = () => t.remove();
148+
const removeModal = () => {
149+
unlockBodyScroll();
150+
t.remove();
151+
};
152+
153+
154+
t.querySelector(".modal-overlay").addEventListener("click", removeModal);
155+
t.querySelector(".dg-cancel").addEventListener("click", removeModal);
156+
t.querySelector(".dg-confirm").addEventListener("click", () => {
157+
const nameVal = t.querySelector("#dg-name").value.trim() || defaultName;
158+
const stVal = type !== "file" ? t.querySelector("#dg-st")?.value.trim() : "";
159+
const mxVal = type !== "file" ? t.querySelector("#dg-mx")?.value.trim() : "";
160+
161+
removeModal();
162+
163+
let finalUrl = `https://GitFolderDownloader.github.io/api/?url=${encodeURIComponent(location.href)}&name=${encodeURIComponent(nameVal)}`;
164+
if (stVal) finalUrl += `&st=${encodeURIComponent(stVal)}`;
165+
if (mxVal) finalUrl += `&mx=${encodeURIComponent(mxVal)}`;
166+
window.open(finalUrl, "_blank");
167+
});
168+
169+
document.addEventListener("keydown", (ev) => {
170+
if (ev.key === "Escape") removeModal();
171+
}, { once: true });
172+
}
173+
174+
function injectButtonsIntoMenus() {
175+
document.querySelectorAll("ul.prc-ActionList-ActionList-rPFF2").forEach((menu) => {
176+
const kind = (function (menuEl) {
177+
const text = menuEl.innerText;
178+
return text.includes("Download ZIP")
179+
? "repo"
180+
: text.includes("Copy path") && !text.includes("Raw file")
168181
? "folder"
169-
: e.includes("Raw file content")
170-
? "file"
171-
: null;
172-
})(n);
173-
o &&
174-
(n.querySelector(`[data-GitFolderDownloader="${o}"]`) ||
175-
n.insertBefore(e(o), n.firstElementChild));
176-
});
182+
: text.includes("Raw file content")
183+
? "file"
184+
: null;
185+
})(menu);
186+
187+
if (!kind) return;
188+
189+
if (menu.querySelector(`[data-GitFolderDownloader="${kind}"]`)) return;
190+
191+
const item = createMenuItem(kind);
192+
menu.insertBefore(item, menu.firstElementChild);
193+
});
177194
}
178195

179-
new MutationObserver(o).observe(document.body, {
180-
childList: !0,
181-
subtree: !0,
182-
}),
183-
o();
184-
})();
196+
document.addEventListener("keydown", (e) => {
197+
if (!(e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "d")) return;
198+
if (/input|textarea/i.test(document.activeElement?.tagName)) return;
199+
200+
const path = location.pathname.split("/").filter(Boolean);
201+
202+
const isFolder = path.includes("tree");
203+
const isFile = path.includes("blob");
204+
205+
if (!isFolder && !isFile) return;
206+
207+
e.preventDefault();
208+
e.stopPropagation();
209+
210+
const name = path[path.length - 1];
211+
showModalAndOpen(name, isFile ? "file" : "folder");
212+
});
213+
214+
new MutationObserver(injectButtonsIntoMenus).observe(document.body, {
215+
childList: true,
216+
subtree: true,
217+
});
218+
injectButtonsIntoMenus();
219+
})();

0 commit comments

Comments
 (0)