Skip to content

Commit 22ba580

Browse files
authored
Initial Find/Replace Implementation (#103)
* Initial Find/Replace Implementation * Add Rest and Search Types * Add Form and Tooltips * Add Local Storage * Cleanup HTML * Add Toast and Fixes * Tweak * Add Flex to Inputs * Cleanup * Add Disable to Reset * Update Collapse * Cleanup
1 parent 23ed010 commit 22ba580

2 files changed

Lines changed: 192 additions & 1 deletion

File tree

src/html/links.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,72 @@ <h2 id="links">Links <span class="badge bg-success-subtle"><span id="links-count
5858
</div>
5959
</div>
6060
</div> <!-- links-buttons -->
61+
62+
<div class="my-2">
63+
<a class="link-body-emphasis" data-bs-toggle="collapse" href="#findCollapse" aria-expanded="false" aria-controls="findCollapse">
64+
<i class="fa-solid fa-magnifying-glass pe-2"></i>Find and Replace</a>
65+
<i class="fa-solid fa-flask text-warning-emphasis ms-2" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Experimental Feature"></i>
66+
<a href="https://link-extractor.cssnr.com/docs/#find-replace" class="link-body-emphasis text-decoration-none" target="_blank" rel="noopener">
67+
<i class="fa-regular fa-circle-question ms-2" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="View Documentation for Feature"></i></a>
68+
<div id="findCollapse" class="collapse">
69+
<form id="findReplace" name="findReplace" class="my-2">
70+
<div class="mb-1">
71+
<div class="form-check form-check-inline">
72+
<input class="form-check-input" type="radio" name="reType" id="reNormal" value="normal" checked>
73+
<label class="form-check-label me-1" for="reNormal">Normal</label>
74+
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
75+
data-bs-title="Normal Text Find and Replace"></i>
76+
</div>
77+
<div class="form-check form-check-inline">
78+
<input class="form-check-input" type="radio" name="reType" id="reRegex" value="regex">
79+
<label class="form-check-label me-1" for="reRegex">Normal w/ Regex</label>
80+
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
81+
data-bs-title="Normal Regex Find and Replace"></i>
82+
</div>
83+
<div class="form-check form-check-inline">
84+
<input class="form-check-input" type="radio" name="reType" id="reGroups" value="groups">
85+
<label class="form-check-label me-1" for="reGroups">Regex w/ Match Groups</label>
86+
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
87+
data-bs-title="Regex Find and Replace w/ Match Groups: $1, $2, etc."></i>
88+
</div>
89+
</div>
90+
91+
<div class="d-flex flex-column flex-sm-row gap-1">
92+
<input id="reFind" name="reFind" type="text" class="form-control" placeholder="Find" aria-label="Find">
93+
<!-- <div class="input-group">-->
94+
<!-- <input id="reFind" name="reFind" type="text" class="form-control" placeholder="Find" aria-label="Find">-->
95+
<!-- <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"></button>-->
96+
<!-- <ul class="dropdown-menu dropdown-menu-end">-->
97+
<!-- <li><a class="dropdown-item small" role="button">Item 1</a></li>-->
98+
<!-- <li><a class="dropdown-item small" role="button">Item 2</a></li>-->
99+
<!-- <li><hr class="dropdown-divider my-1"></li>-->
100+
<!-- <li><a class="dropdown-item small" href="#">Manage Saved Values</a></li>-->
101+
<!-- </ul>-->
102+
<!-- </div>-->
103+
104+
<input id="reReplace" name="reReplace" type="text" class="form-control" placeholder="Replace" aria-label="Replace">
105+
<!-- <div class="input-group">-->
106+
<!-- <input id="reReplace" name="reReplace" type="text" class="form-control" placeholder="Replace" aria-label="Replace">-->
107+
<!-- <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"></button>-->
108+
<!-- <ul class="dropdown-menu dropdown-menu-end">-->
109+
<!-- <li><a class="dropdown-item small" role="button">Item 1</a></li>-->
110+
<!-- <li><a class="dropdown-item small" role="button">Item 2</a></li>-->
111+
<!-- <li><hr class="dropdown-divider my-1"></li>-->
112+
<!-- <li><a class="dropdown-item small" href="#">Manage Saved Values</a></li>-->
113+
<!-- </ul>-->
114+
<!-- </div>-->
115+
116+
<button class="btn btn-outline-success" type="submit">Execute</button>
117+
<button id="reReset" class="btn btn-outline-danger disabled" type="button">Reset</button>
118+
</div>
119+
</form>
120+
<div class="small">
121+
Note: Updates links do not yet work with Datatables (Copy Table, CSV Export, Filter);
122+
however, do work with Copy Links, Download and Open buttons at the top.
123+
</div>
124+
</div>
125+
</div>
126+
61127
<div class="table-wrapper">
62128
<table id="links-table" class="table table-sm table-striped table-hover small w-100" data-counter="links-count">
63129
<thead class="">

src/js/links.js

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import { openURL, textFileDownload } from './exports.js'
44

55
window.addEventListener('keydown', handleKeyboard)
66
document.addEventListener('DOMContentLoaded', initLinks)
7-
7+
document.getElementById('findReplace').addEventListener('submit', findReplace)
8+
document.getElementById('reReset').addEventListener('click', reResetClick)
9+
document
10+
.getElementsByName('reType')
11+
.forEach((el) => el.addEventListener('change', reTypeChange))
812
document
913
.querySelectorAll('.copy-links')
1014
.forEach((el) => el.addEventListener('click', copyLinksClick))
@@ -14,6 +18,19 @@ document
1418
document
1519
.querySelectorAll('.open-in-tabs')
1620
.forEach((el) => el.addEventListener('click', openLinksClick))
21+
document
22+
.querySelectorAll('[data-bs-toggle="tooltip"]')
23+
.forEach((el) => new bootstrap.Tooltip(el))
24+
25+
const findCollapse = document.getElementById('findCollapse')
26+
findCollapse.addEventListener('show.bs.collapse', () => {
27+
console.debug('Show Collapse')
28+
localStorage.setItem('findCollapse', 'shown')
29+
})
30+
findCollapse.addEventListener('hide.bs.collapse', () => {
31+
console.debug('Hide Collapse')
32+
localStorage.setItem('findCollapse', 'hidden')
33+
})
1734

1835
const urlParams = new URLSearchParams(window.location.search)
1936

@@ -109,6 +126,7 @@ function genUrl(url) {
109126
link.text = url
110127
link.href = url
111128
link.title = url
129+
link.dataset.original = url
112130
link.target = '_blank'
113131
link.rel = 'noopener'
114132
return link
@@ -155,6 +173,21 @@ async function initLinks() {
155173
window.close()
156174
}
157175

176+
const collapse = localStorage.getItem('findCollapse')
177+
console.debug('collapse:', collapse)
178+
if (collapse === 'shown') {
179+
// const bsCollapse = new bootstrap.Collapse(findCollapse, {
180+
// toggle: false,
181+
// })
182+
// bsCollapse.show()
183+
findCollapse.classList.add('show')
184+
}
185+
const type = localStorage.getItem('reType')
186+
console.debug('type:', type)
187+
if (type) {
188+
document.getElementById(type).checked = true
189+
}
190+
158191
const { patterns } = await chrome.storage.sync.get(['patterns'])
159192
if (patterns.length) {
160193
const datalist = document.createElement('datalist')
@@ -307,6 +340,98 @@ function dtVisibility(e, settings, column, state) {
307340
linksTable.rows().invalidate().draw()
308341
}
309342

343+
/**
344+
* Find and Replace Submit Callback
345+
* @function findReplace
346+
* @param {SubmitEvent} event
347+
*/
348+
async function findReplace(event) {
349+
console.debug('findReplace:', event)
350+
event.preventDefault()
351+
const find = event.target.elements.reFind.value
352+
const replace = event.target.elements.reReplace.value
353+
console.debug('find:', find)
354+
console.debug('replace:', replace)
355+
if (!find) {
356+
showToast('You must enter a find value.', 'danger')
357+
return
358+
}
359+
const re = new RegExp(find, 'gm')
360+
console.debug('re:', re)
361+
// const type = document.querySelector('input[name="reType"]:checked').value
362+
const type = event.target.elements.reType.value
363+
console.debug('type:', type)
364+
const links = document.getElementById('links-body').querySelectorAll('a')
365+
let count = 0
366+
for (const link of links) {
367+
const before = link.href
368+
console.debug('before:', before)
369+
if (type === 'normal') {
370+
const result = link.href.replace(find, replace)
371+
console.debug('result:', result)
372+
link.href = result
373+
link.textContent = result
374+
} else if (type === 'regex') {
375+
const result = link.href.replace(re, replace)
376+
console.debug('result:', result)
377+
link.href = result
378+
link.textContent = result
379+
} else if (type === 'groups') {
380+
const matches = link.href.match(re)
381+
console.debug('matches:', matches)
382+
if (matches) {
383+
matches.forEach((match, i) => {
384+
console.debug(`match ${i}:`, match)
385+
const result = replace.replace(`$${i + 1}`, match)
386+
console.debug('result:', result)
387+
link.href = result
388+
link.textContent = result
389+
})
390+
}
391+
}
392+
const after = link.getAttribute('href')
393+
console.debug('after:', after)
394+
if (after !== before) {
395+
count++
396+
}
397+
}
398+
const status = count ? 'success' : 'warning'
399+
showToast(`Updated ${count} Links.`, status)
400+
if (count) {
401+
document.getElementById('reReset').classList.remove('disabled')
402+
}
403+
}
404+
405+
/**
406+
* Reset Regex Click Callback
407+
* @function reResetClick
408+
* @param {MouseEvent} event
409+
*/
410+
async function reResetClick(event) {
411+
console.debug('reResetClick:', event)
412+
event.currentTarget.classList.add('disabled')
413+
document
414+
.getElementById('links-body')
415+
.querySelectorAll('a')
416+
.forEach((el) => {
417+
console.debug('el.dataset.original:', el.dataset.original)
418+
el.href = el.dataset.original
419+
el.textContent = el.dataset.original
420+
})
421+
showToast('Links reset to original values.')
422+
}
423+
424+
/**
425+
* Regex Type Change Callback
426+
* @function reTypeChange
427+
* @param {InputEvent} event
428+
*/
429+
async function reTypeChange(event) {
430+
// console.debug('reTypeChange:', event)
431+
console.debug('reTypeChange id:', event.target.id)
432+
localStorage.setItem('reType', event.target.id)
433+
}
434+
310435
/**
311436
* Copy links Button Click Callback
312437
* @function copyLinksClick

0 commit comments

Comments
 (0)