Skip to content

Commit

Permalink
Initial Find/Replace Implementation (#103)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
smashedr authored Sep 16, 2024
1 parent 23ed010 commit 22ba580
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 1 deletion.
66 changes: 66 additions & 0 deletions src/html/links.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,72 @@ <h2 id="links">Links <span class="badge bg-success-subtle"><span id="links-count
</div>
</div>
</div> <!-- links-buttons -->

<div class="my-2">
<a class="link-body-emphasis" data-bs-toggle="collapse" href="#findCollapse" aria-expanded="false" aria-controls="findCollapse">
<i class="fa-solid fa-magnifying-glass pe-2"></i>Find and Replace</a>
<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>
<a href="https://link-extractor.cssnr.com/docs/#find-replace" class="link-body-emphasis text-decoration-none" target="_blank" rel="noopener">
<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>
<div id="findCollapse" class="collapse">
<form id="findReplace" name="findReplace" class="my-2">
<div class="mb-1">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reType" id="reNormal" value="normal" checked>
<label class="form-check-label me-1" for="reNormal">Normal</label>
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
data-bs-title="Normal Text Find and Replace"></i>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reType" id="reRegex" value="regex">
<label class="form-check-label me-1" for="reRegex">Normal w/ Regex</label>
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
data-bs-title="Normal Regex Find and Replace"></i>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reType" id="reGroups" value="groups">
<label class="form-check-label me-1" for="reGroups">Regex w/ Match Groups</label>
<i class="fa-solid fa-circle-info" data-bs-toggle="tooltip" data-bs-placement="bottom"
data-bs-title="Regex Find and Replace w/ Match Groups: $1, $2, etc."></i>
</div>
</div>

<div class="d-flex flex-column flex-sm-row gap-1">
<input id="reFind" name="reFind" type="text" class="form-control" placeholder="Find" aria-label="Find">
<!-- <div class="input-group">-->
<!-- <input id="reFind" name="reFind" type="text" class="form-control" placeholder="Find" aria-label="Find">-->
<!-- <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"></button>-->
<!-- <ul class="dropdown-menu dropdown-menu-end">-->
<!-- <li><a class="dropdown-item small" role="button">Item 1</a></li>-->
<!-- <li><a class="dropdown-item small" role="button">Item 2</a></li>-->
<!-- <li><hr class="dropdown-divider my-1"></li>-->
<!-- <li><a class="dropdown-item small" href="#">Manage Saved Values</a></li>-->
<!-- </ul>-->
<!-- </div>-->

<input id="reReplace" name="reReplace" type="text" class="form-control" placeholder="Replace" aria-label="Replace">
<!-- <div class="input-group">-->
<!-- <input id="reReplace" name="reReplace" type="text" class="form-control" placeholder="Replace" aria-label="Replace">-->
<!-- <button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"></button>-->
<!-- <ul class="dropdown-menu dropdown-menu-end">-->
<!-- <li><a class="dropdown-item small" role="button">Item 1</a></li>-->
<!-- <li><a class="dropdown-item small" role="button">Item 2</a></li>-->
<!-- <li><hr class="dropdown-divider my-1"></li>-->
<!-- <li><a class="dropdown-item small" href="#">Manage Saved Values</a></li>-->
<!-- </ul>-->
<!-- </div>-->

<button class="btn btn-outline-success" type="submit">Execute</button>
<button id="reReset" class="btn btn-outline-danger disabled" type="button">Reset</button>
</div>
</form>
<div class="small">
Note: Updates links do not yet work with Datatables (Copy Table, CSV Export, Filter);
however, do work with Copy Links, Download and Open buttons at the top.
</div>
</div>
</div>

<div class="table-wrapper">
<table id="links-table" class="table table-sm table-striped table-hover small w-100" data-counter="links-count">
<thead class="">
Expand Down
127 changes: 126 additions & 1 deletion src/js/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { openURL, textFileDownload } from './exports.js'

window.addEventListener('keydown', handleKeyboard)
document.addEventListener('DOMContentLoaded', initLinks)

document.getElementById('findReplace').addEventListener('submit', findReplace)
document.getElementById('reReset').addEventListener('click', reResetClick)
document
.getElementsByName('reType')
.forEach((el) => el.addEventListener('change', reTypeChange))
document
.querySelectorAll('.copy-links')
.forEach((el) => el.addEventListener('click', copyLinksClick))
Expand All @@ -14,6 +18,19 @@ document
document
.querySelectorAll('.open-in-tabs')
.forEach((el) => el.addEventListener('click', openLinksClick))
document
.querySelectorAll('[data-bs-toggle="tooltip"]')
.forEach((el) => new bootstrap.Tooltip(el))

const findCollapse = document.getElementById('findCollapse')
findCollapse.addEventListener('show.bs.collapse', () => {
console.debug('Show Collapse')
localStorage.setItem('findCollapse', 'shown')
})
findCollapse.addEventListener('hide.bs.collapse', () => {
console.debug('Hide Collapse')
localStorage.setItem('findCollapse', 'hidden')
})

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

Expand Down Expand Up @@ -109,6 +126,7 @@ function genUrl(url) {
link.text = url
link.href = url
link.title = url
link.dataset.original = url
link.target = '_blank'
link.rel = 'noopener'
return link
Expand Down Expand Up @@ -155,6 +173,21 @@ async function initLinks() {
window.close()
}

const collapse = localStorage.getItem('findCollapse')
console.debug('collapse:', collapse)
if (collapse === 'shown') {
// const bsCollapse = new bootstrap.Collapse(findCollapse, {
// toggle: false,
// })
// bsCollapse.show()
findCollapse.classList.add('show')
}
const type = localStorage.getItem('reType')
console.debug('type:', type)
if (type) {
document.getElementById(type).checked = true
}

const { patterns } = await chrome.storage.sync.get(['patterns'])
if (patterns.length) {
const datalist = document.createElement('datalist')
Expand Down Expand Up @@ -307,6 +340,98 @@ function dtVisibility(e, settings, column, state) {
linksTable.rows().invalidate().draw()
}

/**
* Find and Replace Submit Callback
* @function findReplace
* @param {SubmitEvent} event
*/
async function findReplace(event) {
console.debug('findReplace:', event)
event.preventDefault()
const find = event.target.elements.reFind.value
const replace = event.target.elements.reReplace.value
console.debug('find:', find)
console.debug('replace:', replace)
if (!find) {
showToast('You must enter a find value.', 'danger')
return
}
const re = new RegExp(find, 'gm')
console.debug('re:', re)
// const type = document.querySelector('input[name="reType"]:checked').value
const type = event.target.elements.reType.value
console.debug('type:', type)
const links = document.getElementById('links-body').querySelectorAll('a')
let count = 0
for (const link of links) {
const before = link.href
console.debug('before:', before)
if (type === 'normal') {
const result = link.href.replace(find, replace)
console.debug('result:', result)
link.href = result
link.textContent = result
} else if (type === 'regex') {
const result = link.href.replace(re, replace)
console.debug('result:', result)
link.href = result
link.textContent = result
} else if (type === 'groups') {
const matches = link.href.match(re)
console.debug('matches:', matches)
if (matches) {
matches.forEach((match, i) => {
console.debug(`match ${i}:`, match)
const result = replace.replace(`$${i + 1}`, match)
console.debug('result:', result)
link.href = result
link.textContent = result
})
}
}
const after = link.getAttribute('href')
console.debug('after:', after)
if (after !== before) {
count++
}
}
const status = count ? 'success' : 'warning'
showToast(`Updated ${count} Links.`, status)
if (count) {
document.getElementById('reReset').classList.remove('disabled')
}
}

/**
* Reset Regex Click Callback
* @function reResetClick
* @param {MouseEvent} event
*/
async function reResetClick(event) {
console.debug('reResetClick:', event)
event.currentTarget.classList.add('disabled')
document
.getElementById('links-body')
.querySelectorAll('a')
.forEach((el) => {
console.debug('el.dataset.original:', el.dataset.original)
el.href = el.dataset.original
el.textContent = el.dataset.original
})
showToast('Links reset to original values.')
}

/**
* Regex Type Change Callback
* @function reTypeChange
* @param {InputEvent} event
*/
async function reTypeChange(event) {
// console.debug('reTypeChange:', event)
console.debug('reTypeChange id:', event.target.id)
localStorage.setItem('reType', event.target.id)
}

/**
* Copy links Button Click Callback
* @function copyLinksClick
Expand Down

0 comments on commit 22ba580

Please sign in to comment.