Skip to content

Commit

Permalink
text a page clipper implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
htrinter committed Nov 26, 2023
1 parent 61a923d commit eea0eaf
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 4 deletions.
7 changes: 6 additions & 1 deletion src/browseraction/assets/browseraction.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ input[type='checkbox'] {
margin-right: 5px;
}

#extract {
#extract,
#clipper {
float: right;
}

#clipper {
margin-right: 10px;
}
13 changes: 13 additions & 0 deletions src/browseraction/components/ActionBar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<section id="action-bar">
<button id="extract" tabindex="6" @click="setUrlListInputData">Extract URLs from text</button>
<button id="clipper" tabindex="6" @click="invokePageClipper">Clipper</button>
<button id="open" tabindex="2" @click="openURLs">
<strong>Open URLs</strong>
</button>
Expand All @@ -24,6 +25,8 @@
import { getTabCount, loadSites } from '@/browseraction/components/logic/load'
import { extractURLs } from '@/browseraction/components/logic/extract'
import { store } from '@/browseraction/components/store/store'
import browser from 'webextension-polyfill'
import { version } from '../../../package.json'
export default {
methods: {
Expand All @@ -38,6 +41,16 @@ export default {
},
setUrlListInputData() {
store.setUrlList(extractURLs(store.urlList))
},
async invokePageClipper() {
const currentTab = await browser.tabs.query({ active: true, currentWindow: true })
const currentTabId = currentTab[0]?.id
if (currentTabId !== undefined) {
await browser.scripting.executeScript({
target: { tabId: currentTabId, allFrames: true },
files: [`assets/ClipperContentScript-${version}.js`]
})
}
}
},
computed: {
Expand Down
117 changes: 117 additions & 0 deletions src/clipper/content-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
if (!document.body.hasAttribute('omu-clipper-initialized')) {
console.log('initialize clipper')
const collectedUrls: string[] = []
let selectedElement: HTMLElement | null = null

const addUrlsToCollection = (element: HTMLElement) => {
const wrapper = document.createElement('div')
wrapper.appendChild(element.cloneNode(true))

Array.from(wrapper.querySelectorAll('a')).forEach((link) => {
const href = link.getAttribute('href')
if (href) {
const prependProtocol = !href.startsWith(window.location.protocol)
const prependHost = prependProtocol && !href.startsWith(window.location.host)
const prependPath = prependHost && !href.startsWith('/')

const url = `${prependProtocol ? `${window.location.protocol}//` : ''}${
prependHost ? window.location.host : ''
}${
prependPath
? `${window.location.pathname}${!window.location.pathname.endsWith('/') ? '/' : ''}`
: ''
}${href}`

collectedUrls.push(url)
}
})
const collectedCountEl = document.querySelector('#collected-count')
if (collectedCountEl) {
collectedCountEl.innerHTML = String(collectedUrls.length)
}
}

const copyCollectionToClipboard = () => {
navigator.clipboard.writeText(collectedUrls.join('\n'))
}

const handleMouseOver = (event: MouseEvent) => {
if (
selectedElement !== event.target &&
!(event.target as HTMLElement).classList.contains('opmurls')
) {
if (selectedElement) {
selectedElement.style.outline = ''
}
selectedElement = event.target as HTMLElement
selectedElement.style.outline = '4px solid red'
}
event.stopPropagation()
}

const handleMouseOut = (event: MouseEvent) => {
if (
selectedElement &&
selectedElement === event.target &&
!(event.target as HTMLElement).classList.contains('opmurls')
) {
selectedElement.style.outline = ''
selectedElement = null
}
event.stopPropagation()
}

const handleClick = (event: MouseEvent) => {
const clickedElement = event.target as HTMLElement
if (clickedElement && !clickedElement.classList.contains('opmurls')) {
console.log('element chosen', clickedElement)
addUrlsToCollection(clickedElement)

event.preventDefault()
event.stopPropagation()
}
}

document.addEventListener('mouseover', handleMouseOver, true)
document.addEventListener('mouseout', handleMouseOut, true)
document.addEventListener('click', handleClick, true)

document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
console.log('unload clipper')

document.removeEventListener('mouseover', handleMouseOver, true)
document.removeEventListener('mouseout', handleMouseOut, true)
document.removeEventListener('click', handleClick, true)

if (selectedElement) {
selectedElement.style.outline = ''
}

document.querySelector("#opmurls-overlay")?.remove()
document.body.removeAttribute('omu-clipper-initialized')
}
})

document.body.innerHTML += `
<div id="opmurls-overlay" class="opmurls" style="z-index: 10000000; position: fixed; top: 10px; left: 10px; right: 10px; background: rgba(0, 0, 0, 0.9); color: #fff; border-radius: 10px; font-family: sans-serif;">
<div class="opmurls" style="padding: 20px; float:right">
<span class="opmurls" style="display: inline-block; margin-right:15px;"><span class="opmurls" id="collected-count">0</span> URLs</span>
<strong class="opmurls" id="copytoclipboard" style="display: inline-block; margin-right:15px; cursor: pointer; text-decoration: underline;">Copy to Clipboard</strong>
<strong class="opmurls" style="display: inline-block; margin-right:15px; cursor: pointer; text-decoration: underline;">View</strong>
<strong class="opmurls" style="display: inline-block; cursor: pointer; text-decoration: underline;">Clear</strong>
</div>
<div class="opmurls" style="padding: 20px;">
Select an element and click on it to extract links. Press <strong>escape</strong> to finish.
</div>
</div>
`
document.querySelector('.opmurls #copytoclipboard')?.addEventListener('click', () => {
copyCollectionToClipboard()
alert('URLs copied to clipboard.')
})

document.body.setAttribute('omu-clipper-initialized', '')
} else {
console.log('clipper already initialized')
}
3 changes: 2 additions & 1 deletion src/manifest/chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"default": "CTRL+M"
}
},
"permissions": ["storage"],
"permissions": ["storage", "activeTab", "scripting"],
"optional_permissions": [],
"incognito": "split"
}
3 changes: 2 additions & 1 deletion tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
"playwright.config.*",
"package.json"
],
"compilerOptions": {
"composite": true,
Expand Down
7 changes: 6 additions & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { fileURLToPath, URL } from "node:url"
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import {viteStaticCopy} from "vite-plugin-static-copy";
import { version } from './package.json';

// https://vitejs.dev/config/
export default defineConfig({
Expand Down Expand Up @@ -41,14 +42,18 @@ export default defineConfig({
input: {
BrowserAction: "./browseraction.html",
LazyLoading: "./lazyloading.html",
ClipperContentScript: "./src/clipper/content-script.ts"
},
output: {
manualChunks(id) {
if (id.includes("node_modules")) {
return "vendor";
}
},
entryFileNames() {
return `assets/[name]-${version}.js`;
}
}
},
}
}
})

0 comments on commit eea0eaf

Please sign in to comment.