document.addEventListener('DOMContentLoaded', () => { const zoom = 0.25// From the pdf2htmlex parameter --zoom const zoomRatio = 1 / zoom const saveButton = document.getElementById('saveButton') const whiteoutButton = document.getElementById('whiteoutButton') const editTextButton = document.getElementById('editTextButton') const saveForm = document.getElementById('saveForm') const htmlInput = document.getElementById('htmlInput') const pageContainer = document.getElementById('page-container') let mode = null const toggleMode = newMode => { if (mode === newMode) newMode = null switch (mode) { case 'whiteout': disableWhiteout(); break; case 'editText': disableEditText(); break; } switch (newMode) { case 'whiteout': enableWhiteout(); break; case 'editText': enableEditText(); break; } mode = newMode } document.querySelectorAll('#page-container img').forEach(image => { image.addEventListener('click', () => { const selection = getSelection() selection.removeAllRanges() const range = document.createRange() range.selectNode(image) selection.addRange(range) console.log('selected?') }) }) saveButton.addEventListener('click', () => { htmlInput.value = document.documentElement.outerHTML saveForm.submit() }) // Get screen to print ratio const localStyleSheets = Array.from(document.styleSheets).filter(x => !x.href) const pageOnePixelWidth = localStyleSheets.map(ss => Array.from(ss.rules) .find(rule => rule.selectorText === '.w0' && rule.style.width.endsWith('px')) ).find(x => x).style.width.split('px')[0] const pageOnePointWidth = localStyleSheets.map(ss => Array.from(ss.rules) .filter(rule => rule instanceof CSSMediaRule && rule.conditionText === 'print') .map(mediaRule => Array.from(mediaRule.cssRules) .filter(rule => rule.selectorText === '.w0' && rule.style.width.endsWith('pt')) .find(x => x) ).find(x => x) ).find(x => x).style.width.split('pt')[0] const pixelsPerPoint = 1.3333333333333333 const pageOnePrintPixelWidth = pageOnePointWidth * pixelsPerPoint const screenToPrintRatio = pageOnePrintPixelWidth / pageOnePixelWidth const printToScreenRatio = pageOnePixelWidth / pageOnePrintPixelWidth const myStyle = document.createElement('style') myStyle.type = 'text/css' myStyle.innerHTML = ` @media screen { .replacement { zoom: ${printToScreenRatio}; } } ` document.head.appendChild(myStyle) // Whiteout let start = null const box = document.createElement('div') box.className = 'whiteout-box' whiteoutButton.addEventListener('click', () => toggleMode('whiteout')) const enableWhiteout = () => { whiteoutButton.classList.add('active') pageContainer.classList.add('whiteout') pageContainer.addEventListener('mousedown', whiteoutMouseDown) } const disableWhiteout = () => { whiteoutButton.classList.remove('active') pageContainer.classList.remove('whiteout') pageContainer.removeEventListener('mousedown', whiteoutMouseDown) } const whiteoutMouseDown = event => { start = {x: event.clientX, y: event.clientY} document.body.appendChild(box) drawBox(start, start) window.addEventListener('mousemove', whiteoutMouseMove) window.addEventListener('mouseup', whiteoutMouseUp) } const whiteoutMouseMove = event => { let end = {x: event.clientX, y: event.clientY} drawBox(rect(start, end)) } const whiteoutMouseUp = event => { let end = {x: event.clientX, y: event.clientY} document.body.removeChild(box) const selection = rect(start, end) console.log('whiteout', selection) whiteout(selection) window.removeEventListener('mousemove', whiteoutMouseMove) window.removeEventListener('mouseup', whiteoutMouseUp) } const rect = (a, b) => { const left = Math.min(a.x, b.x) const top = Math.min(a.y, b.y) const right = Math.max(a.x, b.x) const bottom = Math.max(a.y, b.y) return new DOMRect(left, top, right - left, bottom - top) } const drawBox = rect => { box.style.cssText = ` top: ${rect.top - 1}px; left: ${rect.left - 1}px; width: ${rect.width}px; height: ${rect.height}px; ` } const intersects = (r1, r2) => !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top) const whiteout = rect => { const elements = [] const walk = (element) => { let elementRect if (element instanceof HTMLImageElement) { elementRect = element.getBoundingClientRect() } else { const range = document.createRange() range.selectNodeContents(element) elementRect = range.getBoundingClientRect() } if (intersects(rect, elementRect)) { if (element.childNodes && element.childNodes.length) { Array.from(element.childNodes).forEach(walk) } else if (element instanceof Text && element.textContent.length > 1) { while (element.textContent.length) { const next = element.splitText(1) walk(element) element = next } } else { elements.push(element) } } } walk(pageContainer) elements.forEach(element => { if (element instanceof Text) { const range = document.createRange() range.selectNodeContents(element) const elementRect = range.getBoundingClientRect() const replacement = document.createElement('span') replacement.className = 'replacement' replacement.style.cssText = ` width: ${elementRect.width * zoomRatio * screenToPrintRatio}px; display: inline-block; position: relative; ` element.replaceWith(replacement) } else if (element instanceof HTMLImageElement) { const canvas = document.createElement('canvas') canvas.width = element.offsetWidth * zoomRatio canvas.height = element.offsetHeight * zoomRatio const ctx = canvas.getContext('2d') ctx.fillStyle = 'white' ctx.drawImage(element, 0, 0, element.offsetWidth * zoomRatio, element.offsetHeight * zoomRatio) const elementRect = element.getBoundingClientRect() ctx.fillRect( (rect.x - elementRect.x) * zoomRatio, (rect.y - elementRect.y) * zoomRatio, rect.width * zoomRatio, rect.height * zoomRatio ) element.src = canvas.toDataURL() } }) } // Edit Text editTextButton.addEventListener('click', () => toggleMode('editText')) const enableEditText = () => { editTextButton.classList.add('active') pageContainer.classList.add('editText') document.querySelectorAll('.pc').forEach(page => { page.setAttribute('contenteditable', 'true') }) } const disableEditText = () => { editTextButton.classList.remove('active') pageContainer.classList.remove('editText') document.querySelectorAll('.pc').forEach(page => { page.setAttribute('contenteditable', 'false') }) } })