Add popup options link, results preview, and context menu for archive.org download pages
This commit is contained in:
		
					parent
					
						
							
								a7966ebebe
							
						
					
				
			
			
				commit
				
					
						3fdd76d631
					
				
			
		
					 5 changed files with 62 additions and 3 deletions
				
			
		| 
						 | 
					@ -14,7 +14,8 @@
 | 
				
			||||||
  "permissions": [
 | 
					  "permissions": [
 | 
				
			||||||
    "storage",
 | 
					    "storage",
 | 
				
			||||||
    "clipboardWrite",
 | 
					    "clipboardWrite",
 | 
				
			||||||
    "activeTab"
 | 
					    "activeTab",
 | 
				
			||||||
 | 
					    "contextMenus"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "host_permissions": [
 | 
					  "host_permissions": [
 | 
				
			||||||
    "https://archive.org/*",
 | 
					    "https://archive.org/*",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,3 +17,33 @@ browser.runtime.onMessage.addListener(async (msg, sender) => {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Context menu to collect links on archive.org /download/* pages
 | 
				
			||||||
 | 
					browser.runtime.onInstalled.addListener(() => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    browser.contextMenus.create({
 | 
				
			||||||
 | 
					      id: 'aolg-collect',
 | 
				
			||||||
 | 
					      title: 'Collect archive.org links',
 | 
				
			||||||
 | 
					      contexts: ['page'],
 | 
				
			||||||
 | 
					      documentUrlPatterns: ['https://archive.org/download/*']
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  } catch (e) {
 | 
				
			||||||
 | 
					    // ignore if already exists or not supported
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					browser.contextMenus.onClicked.addListener(async (info, tab) => {
 | 
				
			||||||
 | 
					  if (info.menuItemId !== 'aolg-collect' || !tab?.id) return;
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const items = await browser.tabs.sendMessage(tab.id, { type: 'collectLinks' });
 | 
				
			||||||
 | 
					    const count = (items || []).length;
 | 
				
			||||||
 | 
					    await browser.storage.local.set({
 | 
				
			||||||
 | 
					      lastCollected: { tabId: tab.id, url: tab.url, time: Date.now(), count },
 | 
				
			||||||
 | 
					      lastItems: items
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    try { await browser.action.setBadgeBackgroundColor({ color: '#3b82f6', tabId: tab.id }); } catch (e) {}
 | 
				
			||||||
 | 
					    try { await browser.action.setBadgeText({ text: count ? String(count) : '', tabId: tab.id }); } catch (e) {}
 | 
				
			||||||
 | 
					    try { if (browser.action.openPopup) await browser.action.openPopup(); } catch (e) {}
 | 
				
			||||||
 | 
					  } catch (e) {
 | 
				
			||||||
 | 
					    // Swallow errors; context menu is best-effort
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,9 +32,15 @@
 | 
				
			||||||
      <div class="row actions">
 | 
					      <div class="row actions">
 | 
				
			||||||
        <button id="btn-refresh">Load Links</button>
 | 
					        <button id="btn-refresh">Load Links</button>
 | 
				
			||||||
        <span id="count">0</span> matches
 | 
					        <span id="count">0</span> matches
 | 
				
			||||||
 | 
					        <a href="#" id="open-options" class="link">Options</a>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </section>
 | 
					    </section>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <section class="preview">
 | 
				
			||||||
 | 
					      <h2>Preview</h2>
 | 
				
			||||||
 | 
					      <ul id="preview"></ul>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <section class="aria2">
 | 
					    <section class="aria2">
 | 
				
			||||||
      <h2>aria2 RPC</h2>
 | 
					      <h2>aria2 RPC</h2>
 | 
				
			||||||
      <div class="row">
 | 
					      <div class="row">
 | 
				
			||||||
| 
						 | 
					@ -55,4 +61,3 @@
 | 
				
			||||||
    <script type="module" src="index.js"></script>
 | 
					    <script type="module" src="index.js"></script>
 | 
				
			||||||
  </body>
 | 
					  </body>
 | 
				
			||||||
  </html>
 | 
					  </html>
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,8 @@ const els = {
 | 
				
			||||||
  rpcSecret: document.getElementById('rpc-secret'),
 | 
					  rpcSecret: document.getElementById('rpc-secret'),
 | 
				
			||||||
  count: document.getElementById('count'),
 | 
					  count: document.getElementById('count'),
 | 
				
			||||||
  status: document.getElementById('status'),
 | 
					  status: document.getElementById('status'),
 | 
				
			||||||
 | 
					  openOptions: document.getElementById('open-options'),
 | 
				
			||||||
 | 
					  preview: document.getElementById('preview'),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let allItems = [];
 | 
					let allItems = [];
 | 
				
			||||||
| 
						 | 
					@ -59,6 +61,7 @@ function filtered() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function updateCount() {
 | 
					function updateCount() {
 | 
				
			||||||
  els.count.textContent = String(filtered().length);
 | 
					  els.count.textContent = String(filtered().length);
 | 
				
			||||||
 | 
					  renderPreview();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function copyLinks() {
 | 
					async function copyLinks() {
 | 
				
			||||||
| 
						 | 
					@ -103,6 +106,7 @@ function wire() {
 | 
				
			||||||
  els.btnRefresh.addEventListener('click', refresh);
 | 
					  els.btnRefresh.addEventListener('click', refresh);
 | 
				
			||||||
  els.btnCopy.addEventListener('click', copyLinks);
 | 
					  els.btnCopy.addEventListener('click', copyLinks);
 | 
				
			||||||
  els.btnSend.addEventListener('click', sendToAria2);
 | 
					  els.btnSend.addEventListener('click', sendToAria2);
 | 
				
			||||||
 | 
					  els.openOptions.addEventListener('click', (e) => { e.preventDefault(); browser.runtime.openOptionsPage(); });
 | 
				
			||||||
  [
 | 
					  [
 | 
				
			||||||
    els.fType, els.fTypeRe, els.fName, els.fNameRe, els.fSizeMin, els.fSizeMax,
 | 
					    els.fType, els.fTypeRe, els.fName, els.fNameRe, els.fSizeMin, els.fSizeMax,
 | 
				
			||||||
    els.fDateFrom, els.fDateTo, els.fCase
 | 
					    els.fDateFrom, els.fDateTo, els.fCase
 | 
				
			||||||
| 
						 | 
					@ -115,3 +119,19 @@ document.addEventListener('DOMContentLoaded', async () => {
 | 
				
			||||||
  await refresh();
 | 
					  await refresh();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function renderPreview() {
 | 
				
			||||||
 | 
					  if (!els.preview) return;
 | 
				
			||||||
 | 
					  const items = filtered();
 | 
				
			||||||
 | 
					  const max = 50;
 | 
				
			||||||
 | 
					  els.preview.innerHTML = '';
 | 
				
			||||||
 | 
					  for (const it of items.slice(0, max)) {
 | 
				
			||||||
 | 
					    const li = document.createElement('li');
 | 
				
			||||||
 | 
					    li.textContent = it.name || it.url;
 | 
				
			||||||
 | 
					    els.preview.appendChild(li);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (items.length > max) {
 | 
				
			||||||
 | 
					    const li = document.createElement('li');
 | 
				
			||||||
 | 
					    li.textContent = `…and ${items.length - max} more`;
 | 
				
			||||||
 | 
					    els.preview.appendChild(li);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,4 +8,7 @@ label input { margin-left: 6px; }
 | 
				
			||||||
button { font-size: 12px; padding: 4px 10px; }
 | 
					button { font-size: 12px; padding: 4px 10px; }
 | 
				
			||||||
#count { font-weight: bold; margin: 0 4px; }
 | 
					#count { font-weight: bold; margin: 0 4px; }
 | 
				
			||||||
#status { font-size: 12px; white-space: pre-wrap; }
 | 
					#status { font-size: 12px; white-space: pre-wrap; }
 | 
				
			||||||
 | 
					.link { font-size: 12px; margin-left: auto; text-decoration: underline; cursor: pointer; }
 | 
				
			||||||
 | 
					.preview ul, #preview { list-style: none; padding: 0; margin: 6px 0; max-height: 160px; overflow: auto; border: 1px solid #ddd; border-radius: 4px; }
 | 
				
			||||||
 | 
					#preview li { font-size: 12px; padding: 4px 6px; border-bottom: 1px solid #eee; }
 | 
				
			||||||
 | 
					#preview li:last-child { border-bottom: 0; }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue