Skip to content

Commit

Permalink
Updates (#30)
Browse files Browse the repository at this point in the history
* Fix undefined text variable

* Update hidden to bs visually-hidden

* Update Copy Links & Add Copy/Jump Top Container

* Add/Update Quick Jump And Copy Buttons

* Add Open Links and
Add Open Links and Domains in Tabs

* Add Counts

* Add Option to Disable Default Link Filtering
  • Loading branch information
smashedr authored Nov 15, 2023
1 parent 25d25e8 commit 5d67259
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 59 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Easily extract, parse, or open all links/domains from a site or text with optional filters.",
"homepage_url": "https://link-extractor.cssnr.com/",
"author": "Shane",
"version": "0.1.5",
"version": "0.1.6",
"manifest_version": 3,
"commands": {
"_execute_action": {
Expand Down
6 changes: 6 additions & 0 deletions src/css/links.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
a:visited {
color: #bf40bf;
}

#top-container {
margin-top: 10px;
margin-right: 10px;
width: 160px;
}
65 changes: 51 additions & 14 deletions src/html/links.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,66 @@
</head>
<body>

<div id="top-container" class="position-fixed top-0 end-0 user-select-none visually-hidden links domains">
<div class="row g-1">
<div class="col">
<a href="#links"><span class="badge text-bg-success visually-hidden w-100 links">Links</span></a>
</div>
<div class="col">
<a role="button" class="clip" data-clipboard-target="#links-clip">
<span class="badge text-bg-success visually-hidden w-100 links">Copy</span></a>
</div>
</div>
<div class="row g-1">
<div class="col">
<a href="#domains"><span class="badge text-bg-primary visually-hidden w-100 domains">Domains</span></a>
</div>
<div class="col">
<a role="button" class="clip" data-clipboard-target="#domains-clip">
<span class="badge text-bg-primary visually-hidden w-100 domains">Copy</span></a>
</div>
</div>
</div>

<div class="container-fluid p-3">
<h2 id="message">Loading...</h2>
<div class="links" style="display: none">
<h2 id="loading-message" class="user-select-none">Loading...</h2>
<div class="visually-hidden links">
<input id="links-clip" class="visually-hidden" type="hidden" value="">
<div class="user-select-none">
<h2>Links</h2>
<a id="links-clip" class="clip btn btn-sm btn-outline-success mb-2" role="button" data-clipboard-text="">
Copy Links</a> Press <kbd>C</kbd> or <kbd>L</kbd> to Copy Links.
<h2 id="links">Links <span id="links-count" class="badge bg-success-subtle"></span></h2>
<a id="copy-links" class="btn btn-sm btn-success me-1 clip" role="button" data-clipboard-target="#links-clip">
Copy Links</a>
<!-- <a id="open-links" class="btn btn-sm btn-outline-warning open-in-tabs" role="button" data-target="#links-clip">-->
<!-- Open ALL</a>-->
<button type="button" id="open-links" class="btn btn-sm btn-outline-warning open-in-tabs position-relative me-3" data-target="#links-clip">
Open Links
<span id="open-links-count" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger visually-hidden"></span>
</button>
Press <kbd>C</kbd> or <kbd>L</kbd> to Copy Links.
</div>
<table id="links" class="table table-sm table-striped table-hover">
<caption class="visually-hidden">Links</caption>
<table id="links-table" class="table table-sm table-striped table-hover">
<caption class="visually-hidden user-select-none">Links</caption>
<thead><tr><th></th></tr></thead>
<tbody></tbody>
</table>
</div>

<div class="domains" style="display: none">
<div class="visually-hidden domains">
<input id="domains-clip" class="visually-hidden" type="hidden" value="">
<div class="user-select-none">
<h2>Domains</h2>
<a id="domains-clip" class="clip btn btn-sm btn-outline-primary mb-2" role="button" data-clipboard-text="">
Copy Domains</a> Press <kbd>D</kbd> or <kbd>M</kbd> to Copy Domains.
<h2 id="domains">Domains <span id="domains-count" class="badge bg-primary-subtle"></span></h2>
<a id="copy-domains" class="btn btn-sm btn-primary me-1 clip" role="button" data-clipboard-target="#domains-clip">
Copy Domains</a>
<!-- <a id="open-domains" class="btn btn-sm btn-outline-warning open-in-tabs" role="button" data-target="#domains-clip">-->
<!-- Open Domains</a>-->
<button type="button" id="open-domains" class="btn btn-sm btn-outline-warning open-in-tabs position-relative me-3" data-target="#domains-clip">
Open Domains
<span id="open-domains-count" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger visually-hidden"></span>
</button>
Press <kbd>D</kbd> or <kbd>M</kbd> to Copy Domains.
</div>
<table id="domains" class="table table-sm table-striped table-hover">
<caption class="visually-hidden">Domains</caption>
<table id="domains-table" class="table table-sm table-striped table-hover">
<caption class="visually-hidden user-select-none">Domains</caption>
<thead><tr><th></th></tr></thead>
<tbody></tbody>
</table>
Expand Down Expand Up @@ -68,7 +105,7 @@ <h5 class="modal-title">Keyboard Shortcuts</h5>
<script type="text/javascript" src="../dist/bootstrap/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="../dist/clipboard/clipboard.min.js"></script>
<script type="text/javascript" src="../js/main.js"></script>
<script type="text/javascript" src="../js/links.js"></script>
<script type="module" src="../js/links.js"></script>

</body>
</html>
14 changes: 12 additions & 2 deletions src/html/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,21 @@ <h1 class="align-middle">Link Extractor</h1>
<input class="form-check-input" type="checkbox" role="switch" id="contextMenu">
<label class="form-check-label" for="contextMenu" aria-describedby="contextMenuHelp">Enable Right Click Menu</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="defaultFilter">
<label class="form-check-label" for="defaultFilter" aria-describedby="defaultFilterHelp">
Use Default Link Filtering
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle-fill" viewBox="0 0 16 16" data-bs-toggle="tooltip"
data-bs-placement="bottom" data-bs-title="Filter Out Links Without ://">
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
</svg>
</label>
</div>
<hr>
<span id="add-input" class="badge text-bg-primary" role="button">Add Filter</span>
<div id="filters-inputs" class="my-2"></div>
<div class="d-md-none">
<button type="submit" class="btn btn-outline-success w-100">Save Options</button>
<button type="submit" class="btn btn-success w-100">Save Options</button>
</div>
</form>
</div>
Expand All @@ -77,7 +87,7 @@ <h1 class="align-middle">Link Extractor</h1>
<div id="bottom-container" class="position-fixed bottom-0 end-0">
<div id="toast-container" class=""></div>
<div class="d-flex justify-content-end mt-4 d-none d-md-flex">
<button type="submit" form="filters-form" class="btn btn-outline-success text-end">Save Options</button>
<button type="submit" form="filters-form" class="btn btn-success text-end">Save Options</button>
</div>
</div>

Expand Down
15 changes: 14 additions & 1 deletion src/html/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<body>

<div class="container-fluid p-3">
<div class="d-grid g-2 gap-3">
<div class="d-grid g-2 gap-2">
<div class="btn-group btn-group-sm" role="group" aria-label="Button group with nested dropdown">
<button id="btn-all" class="btn btn-success btn-sm popup-click" type="button">
All Links</button>
Expand Down Expand Up @@ -46,6 +46,19 @@
data-bs-placement="bottom" data-bs-title="Open Each Line" data-text="Open">Open</button>
</div>

<div class="form-check form-switch form-check-inline d-flex justify-content-center align-items-center">
<input class="form-check-input me-2" type="checkbox" role="switch" id="defaultFilter">
<!-- <label class="form-check-label" for="defaultFilter" aria-describedby="defaultFilterHelp">No Internal Filtering for-->
<!-- <span class="badge bg-secondary ">://</span></label>-->
<label class="form-check-label" for="defaultFilter" aria-describedby="defaultFilterHelp">
Use Default Link Filtering
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-info-circle-fill" viewBox="0 0 16 16" data-bs-toggle="tooltip"
data-bs-placement="bottom" data-bs-title="Filter Out Links Without ://">
<path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
</svg>
</label>
</div>

<button class="btn btn-outline-info btn-sm popup-click" type="button" data-href="html/options.html">Options</button>
<p class="mb-0 text-center small">
<a id="btn-about" class="link-offset-2 link-underline link-underline-opacity-0 link-underline-opacity-75-hover popup-click" type="button" rel="noopener"
Expand Down
13 changes: 13 additions & 0 deletions src/js/exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,16 @@ export async function injectTab(filter, domains, selection) {
console.log(`url: ${url.toString()}`)
await chrome.tabs.create({ active: true, url: url.toString() })
}

/**
* Open Links in Tabs
* @function openLinksInTabs
* @param {Array} links
* @param {Boolean} active
*/
export function openLinksInTabs(links, active = true) {
console.log('openLinksInTabs:', links)
links.forEach(function (url) {
chrome.tabs.create({ active, url }).then()
})
}
4 changes: 3 additions & 1 deletion src/js/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ function extractLinks() {
console.log('extractLinks')
const links = []
for (const element of document.links) {
links.push(decodeURI(element.href))
if (element.href) {
links.push(decodeURI(element.href))
}
}
console.log(links)
return links
Expand Down
79 changes: 57 additions & 22 deletions src/js/links.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// JS for links.html

import { openLinksInTabs } from './exports.js'

document.addEventListener('DOMContentLoaded', initLinks)

const urlParams = new URLSearchParams(window.location.search)
Expand All @@ -14,6 +16,9 @@ document.addEventListener('keyup', (event) => {
delete keysPressed[event.key]
})

const openLinksBtns = document.querySelectorAll('.open-in-tabs')
openLinksBtns.forEach((el) => el.addEventListener('click', openLinksClick))

/**
* Links Init
* TODO: Review this function
Expand Down Expand Up @@ -52,25 +57,27 @@ async function processLinks(links) {
const onlyDomains = urlParams.has('domains')
console.log(`urlFilter: ${urlFilter}`)
console.log(`onlyDomains: ${onlyDomains}`)
const openWarnCount = 30
const { options } = await chrome.storage.sync.get(['options'])
console.log('options:', options)

if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError)
window.close()
return
}

// Filter bad links like: javascript:void(0)
const filteredLinks = links.filter(
(link) => link.lastIndexOf('://', 10) > 0
)
// Filter links by :// if not disabled by user
if (options.defaultFilter) {
links = links.filter((link) => link.lastIndexOf('://', 10) > 0)
}

// Remove duplicate and sort links
let items = [...new Set(filteredLinks)].sort()
let items = [...new Set(links)].sort()

// Filter links based on pattern
if (urlFilter) {
const { options } = await chrome.storage.sync.get(['options'])
const flags = options !== undefined ? options.flags : 'ig'
const flags = options?.flags !== undefined ? options.flags : 'ig'
const re = new RegExp(urlFilter, flags)
console.log(`Filtering Links with re: ${re}`)
items = items.filter((item) => item.match(re))
Expand All @@ -85,27 +92,40 @@ async function processLinks(links) {

// Update links if onlyDomains is not set
if (!onlyDomains) {
document
.getElementById('links-clip')
.setAttribute('data-clipboard-text', items.join('\n'))
document.getElementById('links-count').textContent =
items.length.toString()
if (items.length >= openWarnCount) {
const openCount = document.getElementById('open-links-count')
openCount.classList.remove('visually-hidden')
openCount.textContent = items.length.toString()
}
document.getElementById('links-clip').value = items.join('\n')
const linksElements = document.querySelectorAll('.links')
linksElements.forEach((el) => (el.style.display = 'block'))
updateTable(items, 'links')
linksElements.forEach((el) => el.classList.remove('visually-hidden'))
updateTable(items, 'links-table')
}

// Extract domains from items and sort
const domains = [...new Set(items.map((link) => getBaseURL(link)))].sort()
document
.getElementById('domains-clip')
.setAttribute('data-clipboard-text', domains.join('\n'))
// Extract domains from items, sort, and remove null
let domains = [...new Set(items.map((link) => getBaseURL(link)))].sort()
domains = domains.filter(function (el) {
return el != null
})
document.getElementById('domains-count').textContent =
domains.length.toString()
if (domains.length >= openWarnCount) {
const openCount = document.getElementById('open-domains-count')
openCount.classList.remove('visually-hidden')
openCount.textContent = domains.length.toString()
}
document.getElementById('domains-clip').value = domains.join('\n')
if (domains.length) {
const domainsElements = document.querySelectorAll('.domains')
domainsElements.forEach((el) => (el.style.display = 'block'))
updateTable(domains, 'domains')
domainsElements.forEach((el) => el.classList.remove('visually-hidden'))
updateTable(domains, 'domains-table')
}

// Hide Loading message
document.getElementById('message').style.display = 'none'
document.getElementById('loading-message').classList.add('visually-hidden')
}

/**
Expand Down Expand Up @@ -156,9 +176,9 @@ function handleKeybinds(event) {
if (!formElements.includes(event.target.tagName)) {
keysPressed[event.key] = true
if (checkKey(event, ['KeyC', 'KeyL'])) {
document.getElementById('links-clip').click()
document.getElementById('copy-links').click()
} else if (checkKey(event, ['KeyD', 'KeyM'])) {
document.getElementById('domains-clip').click()
document.getElementById('copy-domains').click()
} else if (checkKey(event, ['KeyT', 'KeyO'])) {
const url = chrome.runtime.getURL('../html/options.html')
chrome.tabs.create({ active: true, url: url }).then()
Expand Down Expand Up @@ -188,3 +208,18 @@ function checkKey(event, keys) {
}
return !!keys.includes(event.code)
}

/**
* Open links Button Click Callback
* @function openLinksClick
* @param {KeyboardEvent} event
*/
function openLinksClick(event) {
console.log('openLinksBtn:', event)
console.log(`openLinksBtn: ${event.target.dataset.target}`)
const input = document.querySelector(event.target.dataset.target)
console.log('input:', input)
const links = input.value.toString().split('\n')
console.log('links:', links)
openLinksInTabs(links)
}
10 changes: 10 additions & 0 deletions src/js/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ document.getElementById('reset-default').addEventListener('click', resetForm)
})
})

const tooltipTriggerList = document.querySelectorAll(
'[data-bs-toggle="tooltip"]'
)
const tooltipList = [...tooltipTriggerList].map(
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl)
)

/**
* Options Page Init
* @function initOptions
Expand All @@ -25,9 +32,11 @@ async function initOptions() {
'options',
'patterns',
])
console.log('options:', options)
document.getElementById('reFlags').value =
options !== undefined ? options.flags : 'ig'
document.getElementById('contextMenu').checked = options.contextMenu
document.getElementById('defaultFilter').checked = options.defaultFilter
if (patterns?.length) {
console.log(patterns)
patterns.forEach(function (value, i) {
Expand Down Expand Up @@ -139,6 +148,7 @@ async function saveOptions(event) {
chrome.contextMenus.removeAll()
}
console.log(options)
options.defaultFilter = document.getElementById('defaultFilter').checked

await chrome.storage.sync.set({ options, patterns })
showToast('Options Saved')
Expand Down
Loading

0 comments on commit 5d67259

Please sign in to comment.