From 4f120b68f5ecd9c3a482f164207476168f987f96 Mon Sep 17 00:00:00 2001 From: Gergo Dulai Date: Tue, 23 Sep 2025 00:29:33 +0200 Subject: [PATCH] Initial commit --- .vscode/launch.json | 7 +++ README.md | 11 ++++ background.js | 126 ++++++++++++++++++++++++++++++++++++++++++++ content.js | 12 +++++ icons/icon.jpg | Bin 0 -> 29429 bytes icons/icon128.png | 0 icons/icon16.png | 0 icons/icon48.png | 0 manifest.json | 41 ++++++++++++++ options.html | 19 +++++++ options.js | 15 ++++++ popup.css | 97 ++++++++++++++++++++++++++++++++++ popup.html | 28 ++++++++++ popup.js | 38 +++++++++++++ 14 files changed, 394 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 README.md create mode 100644 background.js create mode 100644 content.js create mode 100644 icons/icon.jpg create mode 100644 icons/icon128.png create mode 100644 icons/icon16.png create mode 100644 icons/icon48.png create mode 100644 manifest.json create mode 100644 options.html create mode 100644 options.js create mode 100644 popup.css create mode 100644 popup.html create mode 100644 popup.js diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4da7a98 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Starter Chrome Extension + +A minimal Chrome extension starter (Manifest V3) with a popup, options page, content script and background service worker. + +## How to run locally + +1. Save the project files to a folder (e.g. `chrome-extension-starter`). +2. Open Chrome and go to `chrome://extensions`. +3. Toggle **Developer mode** on (top-right). +4. Click **Load unpacked** and pick the extension folder. +5. The extension should appear in the toolbar (pin it for convenience). diff --git a/background.js b/background.js new file mode 100644 index 0000000..8b3a970 --- /dev/null +++ b/background.js @@ -0,0 +1,126 @@ +function saveRevision(source) { + console.log('Syncing started from: ' + source); + + chrome.bookmarks.getTree(async (tree) => { + const apiUrl = await chrome.storage.sync.get('apiUrl'); + const syncToken = await chrome.storage.sync.get("syncToken"); + if (!apiUrl || !syncToken) + return; + + + const savedRev = await chrome.storage.sync.get('revId'); + + const url = apiUrl.apiUrl + '/saveRevision'; + const options = { + headers: { + 'content-type': 'application/json', + 'syncToken': syncToken.syncToken + }, + method: 'POST', + body: JSON.stringify({ + 'revId': savedRev.revId, + 'bookmarks': tree + }) + }; + + try { + const response = await fetch(url, options); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + const data = await response.json(); // Convert to JSON + chrome.storage.sync.set({ revId: data.revId }); + + } catch (e) { + // TODO GD: Indicate error + } + }); +} + +async function getRevision() { + const apiUrl = await chrome.storage.sync.get('apiUrl'); + const syncToken = await chrome.storage.sync.get("syncToken"); + + if (!apiUrl || !syncToken) + return; + + const url = apiUrl.apiUrl + '/getRevision'; + const options = { + headers: { + 'content-type': 'application/json', + 'syncToken': syncToken.syncToken + }, + method: 'GET' + }; + + try { + const response = await fetch(url, options); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); // Convert to JSON + const savedRev = await chrome.storage.sync.get('revId'); + if (data.revId === savedRev.revId) + return; + + chrome.storage.sync.set({ revId: data.revId }); + + removeAllChildren("1", () => createBookmarkTree(data.bookmarks, "1")); + removeAllChildren("2", () => createBookmarkTree(data.bookmarks, "2")); + } catch (e) { + // TODO GD: Indicate error + } +} + +// Recursively delete all children +function removeAllChildren(parentId, callback) { + chrome.bookmarks.getChildren(parentId, (children) => { + if (!children || children.length === 0) return callback?.(); + let count = children.length; + children.forEach((child) => { + if (child.url) { + chrome.bookmarks.remove(child.id, () => { + if (--count === 0) callback?.(); + }); + } else { + removeAllChildren(child.id, () => { + chrome.bookmarks.remove(child.id, () => { + if (--count === 0) callback?.(); + }); + }); + } + }); + }); +} + +// Sync events + +chrome.bookmarks.onCreated.addListener((id, bookmark) => { + saveRevision('onCreated'); +}); + +chrome.bookmarks.onRemoved.addListener((id, removeInfo) => { + saveRevision('onRemoved'); +}); + +chrome.bookmarks.onChanged.addListener((id, changeInfo) => { + saveRevision('onChanged'); +}); + +chrome.bookmarks.onMoved.addListener((id, moveInfo) => { + saveRevision('onMoved'); +}); + +chrome.bookmarks.onChildrenReordered.addListener((id, reorderInfo) => { + saveRevision('onChildrenReordered'); +}); + +chrome.bookmarks.onImportEnded.addListener(() => { + saveRevision('onImportEnded'); +}); + + +getRevision(); + +setInterval(getRevision, 5000); \ No newline at end of file diff --git a/content.js b/content.js new file mode 100644 index 0000000..cefe8f5 --- /dev/null +++ b/content.js @@ -0,0 +1,12 @@ +function onLoad() { + console.log('Starter extension content script loaded on', location.href); +} + +window.addEventListener('DOMContentLoaded', onLoad); + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message?.type === 'GET_NUM_LINKS') { + const count = document.querySelectorAll('a').length; + sendResponse({ count }); + } +}); \ No newline at end of file diff --git a/icons/icon.jpg b/icons/icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4d2600cab5b72d6df15b0d572d0860e1b787e6e GIT binary patch literal 29429 zcmb@u1y~--vM&7L4#9)FI|R4j?(XjH4ha(6-QC?Cf&_OB1W0fvxXb-WvesVv+Hed}{~Lrc zHgPfns+jLg18qVB%4lZ4Wy)9C@VCtKD!Vz`I|Fs(Uu8#SMIoSU43sI&{vjLw zLpHK^eASNt>hRcDyS!fO^?1EIcoSO{C13~*{NVze0Ez%HfZ*%>1LMHME)M|UxB>vc zV*Z60rUC%XK>)zp<$qzMIRF4sAOO%b`7i8Wbz*PeXz;5za3BXYH3b09iva)x4FCXj z3IKrB`jrM`|BY>gz$9FtU3S3J3}6i~0T2Qt0JZ=l06kD*1~3Ac0BkSc073w8FtAqw z2Lp!y2Zw-!g@Obg2r#hFut*4R-XI|$AtIx`MMFlxL_tJC$3@4)!otD9d4q;WfQL=+ z78?iqwGa?+2na|BNO&kHcx+@OWbFU-@zM)Gh6ZT^^#B7Q27n@ifFXmt^aF1I1ON*5 z>WF_IAW#sH(BPn8z*KA?4ov+!2`GSpgMdOnzAOXafjHyGY!a#>EQNW)3i zsfriTFW;M>CG-46US$5&#x*K?HHm-IB?e08Z;Itxez8 zmWiNA45KOhi-*>VIRBv_$J!tlHmtBSgFkd`O{6OmNb}_r&DUDOYVtl7o$)}!&Tx3O zYz(HfINrIo%}03^>?;lgs)cz0AM)7C2npR6vx$<2d4KrF2gS)RI3#i z?&q#ciSJSS4P88wns-VYrO-n2K2fL_Tlre1D^H835&p^y4(#m!kc&$i9@(>ek7zM{ z=WL>@@9c%dSRX+3e`z4HUEK35?tM)?LUfzGOTD|ltA&uc_2TiBo2R9|?roLQze~

gVa_UnTxx2(H~VG%o<& zwHsF?0#_uG%4@=m->KlAH|^Mq$9*HiGe7Tk@}~$_^hM7%Cu(6|_e#B$A_!JnHLZ+* z^i&)`8H`w9FVy0C_Eqdh832I7{8c(g)#AhR$6c?rwcgFO-mR;ye$)@Y)1YuXI{Bn13bNINim>Jp zb!fx8&c=c79Y1d(uD$o$Be}ipb}sL#XZ9WtJ8Je;Vk18Qpv8q>>lHeV6gn2>4ax`a z=sXxua+pv6AvtLMZdUMaIBOlR-O!Um)eArnOCW}n5&lDp0SSk%UOA%W43|>c@qCS^ zP~80lmHY1a{)I;M^fjJ`!E`GL4glzvASlShq<~NWAUfRnIKYV_fz7d|H!MEUWXQIt=n0NBMWE`luDg`2BElBy=1g*deoE4!V-vXA-)8Hcy!_|3|# ziypo_d)Q61M7TAu-!t1NGAkCYF8!FBXNy*bW_{D6Oz>EFhWd&&Q^jOjW1P1x-t2#` z(r1}N9qlVIOBT5iL=j6l)RjCGFWj62_5?%3s9LLXjL6RepMM*M1cUp1ckXCGZ0*7| ztGnHpqP-8{ zRdVVLR@X;~xy*2KVl9%yW;*^AV0->>WT_G(Y5U>G<1(}b? zBRMFsuZgRnqCbrE0RRC)008jVT5Vf+^#0+t))V&yFw26v_jm_Gk}|k=d3=(#Q?}*8 zj1R5cjC#TGZ7Jb1X}I^~Tz28I>!H*NS4Vd%ZO=u49qjDvMeU)l)6^wI{(z5w=m}27 z{R<%bdZ2t!MW?c;2R8?J82|v=j?o2*;cIoup{(Sgv{|(GS~hD47gv8ZEf+hfk^ZX+ z0D8VD%J91k_eDnJffnNW#npbt48=}Ao!xlh*?o6$zwL_eL~8dcH?PM*XSkyfIoN1J zZQ4({PMpJ`7T@s-vM~Sa!Kg1@LL`byIwzQ&^pOk`jr9(fHuDdrrTA{su5PPFM$@ei zo7C7*>TRR!Ulu>whXChkm=7=?z+|_dvv=Uo&z~%YeJmo*egeC7EwHv+wu42tBCLN8 zPlPkAp9ZQbRWv+(!dEx=q6Wz-cBoIx#4Zv?Kc7755JB+^jvIc?Yk)X zwv^M=baS@MPVX2tTdn21uUC8W%^{-S`zssN#aT!7l>|1fo5S6MAmADSI33FDAm(g8 zpkLsb4f~i+;@@@hS^U^LL}{<3{M}_^gg=0zZeA^pIaRL{RNiYn`)&T5zjK>hV6br> zBlYpnlWDzNXsws;!nOq#2U4Jlvu|=CJ6oY%ePOQh4M{9ppPZKfB+t$-)8arT-R4@c z`R?FBM~6HM2cvB-n|qJ;qvEew5v1q>O5X7)?9R7gYodO@{RZef>H+x`lIMN-j-qV9 zriu}ujDgN)kTs9vh2#CW>Y35mh`Rr{wU1M&H@;_dlZpKTxajhqL8towG-TmghAPVV zPEIg^oi6PKz*oL>qtU7;f8bOEfY&i;v|MxRJUkr1%;m(>|D+E{0f5H<-ks8?*{EKIw-E6YOx9=`dFM!nzuc3B%a9KpEcXIDc9;=J@ z=yorjIBz}za{$`{=n=rSV0~>19jkv>FpBuw0-%mBL3c#YLKhKHxHLI~c~c ze^pz0;i;L}sN|b*5^dVCmZtX0SfzN5Zp`kKtfc)I2Ha*ZH)Kc8vxtJ(2XVb|`n zZ>L(aaAC;%-rGxAIXSDv$0$8TpRSXSOyjckN1YbG*8Gbo&)qq1D#(X2S1QUKL+^Kiu<&dM$

bjTzvhT&)xo>&Dlp~ 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 z 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 literal 0 HcmV?d00001 diff --git a/icons/icon128.png b/icons/icon128.png new file mode 100644 index 0000000..e69de29 diff --git a/icons/icon16.png b/icons/icon16.png new file mode 100644 index 0000000..e69de29 diff --git a/icons/icon48.png b/icons/icon48.png new file mode 100644 index 0000000..e69de29 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..ba3393b --- /dev/null +++ b/manifest.json @@ -0,0 +1,41 @@ +{ + "manifest_version": 3, + "name": "Simple Sync", + "description": "A simple extension", + "version": "1.0.0", + "icons": { + "16": "icons/icon.jpg", + "48": "icons/icon.jpg", + "128": "icons/icon.jpg" + }, + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon.jpg", + "48": "icons/icon.jpg" + } + }, + "options_page": "options.html", + "background": { + "service_worker": "background.js" + }, + "permissions": [ + "storage", + "scripting", + "activeTab", + "bookmarks" + ], + "host_permissions": [ + "" + ], + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "content.js" + ] + } + ] +} \ No newline at end of file diff --git a/options.html b/options.html new file mode 100644 index 0000000..be60dd2 --- /dev/null +++ b/options.html @@ -0,0 +1,19 @@ + + + + + + Extension Options + + + +

Options

+ + +
+ + + \ No newline at end of file diff --git a/options.js b/options.js new file mode 100644 index 0000000..e55d102 --- /dev/null +++ b/options.js @@ -0,0 +1,15 @@ +const favInput = document.getElementById('favcolor'); +const saveBtn = document.getElementById('save'); +const msg = document.getElementById('msg'); + +chrome.storage.sync.get(['favcolor']).then(data => { + favInput.value = data.favcolor || ''; +}); + +saveBtn.addEventListener('click', () => { + const val = favInput.value || ''; + chrome.storage.sync.set({ favcolor: val }).then(() => { + msg.textContent = 'Saved.'; + setTimeout(() => (msg.textContent = ''), 1500); + }); +}); \ No newline at end of file diff --git a/popup.css b/popup.css new file mode 100644 index 0000000..4027559 --- /dev/null +++ b/popup.css @@ -0,0 +1,97 @@ +body { + font-family: system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial; + margin: 0; + padding: 12px; + width: 240px; +} + +.container { + display: flex; + flex-direction: column; + gap: 8px; +} + +.header { + display: grid; + grid-template-columns: 4fr 1fr; +} + +button { + padding: 8px 10px; + border-radius: 6px; + border: 1px solid rgba(0, 0, 0, 0.08); + background: white; + cursor: pointer; +} + +button:hover { + filter: brightness(0.98); +} + +h1 { + font-size: 18px; + margin: 0 0 6px 0 +} + +#status { + font-size: 12px; + color: #444 +} + +.switch { + position: relative; + display: inline-block; + width: 40px; + height: 25px; + margin-top: 10px; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + transition: .3s; + border-radius: 20px; +} + +.slider:before { + position: absolute; + content: ""; + height: 15px; + width: 15px; + left: 3px; + margin-top: 5px; + background-color: white; + transition: .3s; + border-radius: 50%; +} + +input:checked+.slider { + background-color: #4caf50; +} + +input:checked+.slider:before { + transform: translateX(18px); +} + +input[readonly], +textarea[readonly] { + background-color: #fafafa; + /* subtle gray background */ + color: #555; + /* dim text color */ + border: 1px solid #ddd; + /* lighter border */ + cursor: default; + /* no text cursor change */ +} \ No newline at end of file diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..1935733 --- /dev/null +++ b/popup.html @@ -0,0 +1,28 @@ + + + + + + + Starter Popup + + + + +
+
+

Simple Sync

+ +
+ + + + +
+ + + + \ No newline at end of file diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..a87127c --- /dev/null +++ b/popup.js @@ -0,0 +1,38 @@ +const editToggle = document.getElementById('editToggle'); +const revIdLabel = document.getElementById('revId'); +const apiUrl = document.getElementById('apiUrl'); +const syncToken = document.getElementById('syncToken'); + +document.addEventListener('DOMContentLoaded', () => { + chrome.storage.sync.get('revId', (savedRev) => { + revIdLabel.textContent = savedRev.revId || "No value stored"; + }); + + chrome.storage.sync.get('apiUrl', (savedUrl) => { + apiUrl.value = savedUrl.apiUrl || "No value stored"; + }); + + chrome.storage.sync.get('syncToken', (savedToken) => { + syncToken.value = savedToken.syncToken || "No value stored"; + }); +}); + +editToggle.addEventListener('change', () => { + if (editToggle.checked) { + apiUrl.readOnly = false; + syncToken.readOnly = false; + } + else { + apiUrl.readOnly = true; + syncToken.readOnly = true; + } + +}); + +apiUrl.addEventListener('input', () => { + chrome.storage.sync.set({ apiUrl: apiUrl.value }); +}); + +syncToken.addEventListener('input', () => { + chrome.storage.sync.set({ syncToken: syncToken.value }); +}); \ No newline at end of file