mirror of
https://github.com/James-Yu/LaTeX-Workshop.git
synced 2024-10-05 07:37:24 +03:00
enable ESLint for viewer/latexworkshop.ts
This commit is contained in:
parent
18f3a87415
commit
d358c377c8
@ -10,5 +10,3 @@ __pycache__/
|
||||
.pytest_cache/
|
||||
.venv/
|
||||
.vscode/.ropeproject
|
||||
|
||||
viewer/**
|
||||
|
@ -106,17 +106,13 @@
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["latexworkshop.js"],
|
||||
"files": ["latexworkshop.ts"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"project": "./tsconfig.eslint.viewer.json"
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/ban-ts-ignore": "off",
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/class-name-casing": "off",
|
||||
"@typescript-eslint/type-annotation-spacing": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"@typescript-eslint/semi": "off",
|
||||
"@typescript-eslint/member-delimiter-style": "off",
|
||||
"no-case-declarations": "off"
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
14
tsconfig.eslint.viewer.json
Normal file
14
tsconfig.eslint.viewer.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"viewer/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**",
|
||||
"dev/**"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
const embedded = window.parent !== window
|
||||
let documentTitle = ''
|
||||
|
||||
let PDFViewerApplication: any
|
||||
let PDFViewerApplicationOptions: any
|
||||
declare let PDFViewerApplication: any
|
||||
declare let PDFViewerApplicationOptions: any
|
||||
|
||||
document.addEventListener('webviewerloaded', () => {
|
||||
// PDFViewerApplication detects whether it's embedded in an iframe (window.parent !== window)
|
||||
// and if so it behaves more "discretely", eg it disables its history mechanism.
|
||||
// We dont want that, so we unset the flag here (to keep viewer.js as vanilla as possible)
|
||||
//
|
||||
PDFViewerApplication.isViewerEmbedded = false;
|
||||
});
|
||||
PDFViewerApplication.isViewerEmbedded = false
|
||||
})
|
||||
|
||||
class ViewerHistory {
|
||||
_history: { scroll: number, temporary: boolean}[]
|
||||
@ -77,8 +77,8 @@ class ViewerHistory {
|
||||
cur = cur - 1
|
||||
prevScroll = this._history[cur].scroll
|
||||
} else {
|
||||
const tmp = {scroll: container.scrollTop, temporary: true};
|
||||
this._history.push(tmp);
|
||||
const tmp = {scroll: container.scrollTop, temporary: true}
|
||||
this._history.push(tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,12 +120,14 @@ let viewerHistory = new ViewerHistory()
|
||||
|
||||
const pdfFilePrefix = 'pdf..'
|
||||
|
||||
/*
|
||||
function encodePath(path) {
|
||||
const s = encodeURIComponent(path)
|
||||
const b64 = window.btoa(s)
|
||||
const b64url = b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
|
||||
return b64url
|
||||
}
|
||||
*/
|
||||
|
||||
function decodePath(b64url) {
|
||||
const tmp = b64url + '='.repeat((4 - b64url.length % 4) % 4)
|
||||
@ -184,7 +186,7 @@ function setupWebSocket() {
|
||||
socket.addEventListener('message', (event) => {
|
||||
const data = JSON.parse(event.data)
|
||||
switch (data.type) {
|
||||
case 'synctex':
|
||||
case 'synctex': {
|
||||
// use the offsetTop of the actual page, much more accurate than multiplying the offsetHeight of the first page
|
||||
const container = document.getElementById('viewerContainer')
|
||||
const pos = PDFViewerApplication.pdfViewer._pages[data.data.page - 1].viewport.convertToViewportPoint(data.data.x, data.data.y)
|
||||
@ -203,7 +205,8 @@ function setupWebSocket() {
|
||||
indicator.style.top = `${scrollY}px`
|
||||
setTimeout(() => indicator.className = 'hide', 10)
|
||||
break
|
||||
case 'refresh':
|
||||
}
|
||||
case 'refresh': {
|
||||
// Note: without showPreviousViewOnLoad = false restoring the position after the refresh will fail if
|
||||
// the user has clicked on any link in the past (pdf.js will automatically navigate to that link).
|
||||
const pack = {
|
||||
@ -217,20 +220,21 @@ function setupWebSocket() {
|
||||
viewerHistory: { history: viewerHistory._history, currentIndex: viewerHistory._currentIndex }
|
||||
}
|
||||
socket.send(JSON.stringify(pack))
|
||||
PDFViewerApplicationOptions.set('showPreviousViewOnLoad', false);
|
||||
PDFViewerApplicationOptions.set('showPreviousViewOnLoad', false)
|
||||
PDFViewerApplication.open(`${pdfFilePrefix}${encodedPdfFilePath}`).then( () => {
|
||||
// reset the document title to the original value to avoid duplication
|
||||
document.title = documentTitle
|
||||
|
||||
// ensure that trimming is invoked if needed.
|
||||
setTimeout(() => {
|
||||
window.dispatchEvent( new Event('pagerendered') );
|
||||
}, 2000);
|
||||
window.dispatchEvent( new Event('pagerendered') )
|
||||
}, 2000)
|
||||
setTimeout(() => {
|
||||
window.dispatchEvent( new Event('refreshed') );
|
||||
}, 2000);
|
||||
});
|
||||
window.dispatchEvent( new Event('refreshed') )
|
||||
}, 2000)
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'position':
|
||||
PDFViewerApplication.pdfViewer.currentScaleValue = data.scale
|
||||
PDFViewerApplication.pdfViewer.scrollMode = data.scrollMode
|
||||
@ -314,7 +318,7 @@ if (embedded) {
|
||||
const target = e.target as HTMLAnchorElement
|
||||
if (target.nodeName === 'A' && !target.href.startsWith(window.location.href)) { // is external link
|
||||
socket.send(JSON.stringify({type:'external_link', url:target.href}))
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -322,14 +326,14 @@ if (embedded) {
|
||||
|
||||
function callSynctex(e, page, pageDom, viewerContainer) {
|
||||
const canvasDom = pageDom.getElementsByTagName('canvas')[0]
|
||||
const selection = window.getSelection();
|
||||
const selection = window.getSelection()
|
||||
let textBeforeSelection = ''
|
||||
let textAfterSelection = ''
|
||||
// workaround for https://github.com/James-Yu/LaTeX-Workshop/issues/1314
|
||||
if(selection && selection.anchorNode && selection.anchorNode.nodeName === '#text'){
|
||||
const text = selection.anchorNode.textContent;
|
||||
textBeforeSelection = text.substring(0, selection.anchorOffset);
|
||||
textAfterSelection = text.substring(selection.anchorOffset);
|
||||
const text = selection.anchorNode.textContent
|
||||
textBeforeSelection = text.substring(0, selection.anchorOffset)
|
||||
textAfterSelection = text.substring(selection.anchorOffset)
|
||||
}
|
||||
const trimSelect = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
let left = e.pageX - pageDom.offsetLeft + viewerContainer.scrollLeft
|
||||
@ -356,15 +360,15 @@ function registerSynctexKeybinding(keybinding) {
|
||||
}
|
||||
callSynctex(e, page, pageDom, viewerContainer)
|
||||
}
|
||||
break;
|
||||
break
|
||||
case 'double-click':
|
||||
pageDom.ondblclick = (e) => {
|
||||
callSynctex(e, page, pageDom, viewerContainer)
|
||||
}
|
||||
break;
|
||||
break
|
||||
default:
|
||||
console.log(`Unknown keybinding ${keybinding} (view.pdf.internal.synctex.keybinding)`)
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -373,7 +377,7 @@ document.addEventListener('pagesinit', () => {
|
||||
if (reverseSynctexKeybinding) {
|
||||
registerSynctexKeybinding(reverseSynctexKeybinding)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const setHistory = () => {
|
||||
const container = document.getElementById('viewerContainer')
|
||||
@ -394,7 +398,7 @@ document.addEventListener('pagesinit', () => {
|
||||
document.getElementById('historyForward').addEventListener('click', () => {
|
||||
viewerHistory.forward()
|
||||
})
|
||||
}, { once: true });
|
||||
}, { once: true })
|
||||
|
||||
// keyboard bindings
|
||||
window.addEventListener('keydown', (evt) => {
|
||||
@ -410,9 +414,9 @@ window.addEventListener('keydown', (evt) => {
|
||||
// Back/Forward don't work in the embedded viewer, so we simulate them.
|
||||
if (embedded && (evt.altKey || evt.metaKey)) {
|
||||
if (evt.keyCode === 37) {
|
||||
viewerHistory.back();
|
||||
viewerHistory.back()
|
||||
} else if(evt.keyCode === 39) {
|
||||
viewerHistory.forward();
|
||||
viewerHistory.forward()
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -440,102 +444,102 @@ document.addEventListener('pagesinit', () => {
|
||||
showToolbar(true)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
let currentUserSelectScale = undefined;
|
||||
let originalUserSelectIndex = undefined;
|
||||
let currentUserSelectScale = undefined
|
||||
let originalUserSelectIndex = undefined
|
||||
|
||||
const getTrimScale = () => {
|
||||
const trimSelect = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
if (trimSelect.selectedIndex <= 0) {
|
||||
return 1.0;
|
||||
return 1.0
|
||||
}
|
||||
const trimValue = trimSelect.options[trimSelect.selectedIndex].value;
|
||||
return 1.0/(1 - 2*Number(trimValue));
|
||||
};
|
||||
const trimValue = trimSelect.options[trimSelect.selectedIndex].value
|
||||
return 1.0/(1 - 2*Number(trimValue))
|
||||
}
|
||||
|
||||
document.addEventListener('pagesinit', () => {
|
||||
document.getElementById('trimSelect').addEventListener('change', () => {
|
||||
const trimScale = getTrimScale();
|
||||
const trimScale = getTrimScale()
|
||||
const trimSelect = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
const scaleSelect = document.getElementById('scaleSelect') as HTMLSelectElement
|
||||
const e = new Event('change');
|
||||
let o;
|
||||
const scaleSelect = document.getElementById('scaleSelect') as HTMLSelectElement
|
||||
const e = new Event('change')
|
||||
let o
|
||||
if (trimSelect.selectedIndex <= 0) {
|
||||
for ( o of scaleSelect.options ) {
|
||||
o.disabled = false;
|
||||
o.disabled = false
|
||||
}
|
||||
(document.getElementById('trimOption') as HTMLOptionElement).disabled = true;
|
||||
document.getElementById('trimOption').hidden = true;
|
||||
(document.getElementById('trimOption') as HTMLOptionElement).disabled = true
|
||||
document.getElementById('trimOption').hidden = true
|
||||
if (originalUserSelectIndex !== undefined) {
|
||||
scaleSelect.selectedIndex = originalUserSelectIndex;
|
||||
scaleSelect.selectedIndex = originalUserSelectIndex
|
||||
}
|
||||
scaleSelect.dispatchEvent(e);
|
||||
currentUserSelectScale = undefined;
|
||||
originalUserSelectIndex = undefined;
|
||||
const viewer = document.getElementById('viewer');
|
||||
scaleSelect.dispatchEvent(e)
|
||||
currentUserSelectScale = undefined
|
||||
originalUserSelectIndex = undefined
|
||||
const viewer = document.getElementById('viewer')
|
||||
for ( const page of viewer.getElementsByClassName('page') ) {
|
||||
for ( const layer of page.getElementsByClassName('annotationLayer') ) {
|
||||
for ( const secionOfAnnotation of layer.getElementsByTagName('section') ) {
|
||||
if (secionOfAnnotation.dataset.originalLeft !== undefined) {
|
||||
secionOfAnnotation.style.left = secionOfAnnotation.dataset.originalLeft;
|
||||
secionOfAnnotation.style.left = secionOfAnnotation.dataset.originalLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
for ( o of scaleSelect.options ) {
|
||||
o.disabled = true;
|
||||
o.disabled = true
|
||||
}
|
||||
if (currentUserSelectScale === undefined) {
|
||||
currentUserSelectScale = PDFViewerApplication.pdfViewer._currentScale;
|
||||
currentUserSelectScale = PDFViewerApplication.pdfViewer._currentScale
|
||||
}
|
||||
if (originalUserSelectIndex === undefined) {
|
||||
originalUserSelectIndex = scaleSelect.selectedIndex;
|
||||
originalUserSelectIndex = scaleSelect.selectedIndex
|
||||
}
|
||||
o = document.getElementById('trimOption');
|
||||
o.value = currentUserSelectScale * trimScale;
|
||||
o.selected = true;
|
||||
scaleSelect.dispatchEvent(e);
|
||||
});
|
||||
});
|
||||
o = document.getElementById('trimOption')
|
||||
o.value = currentUserSelectScale * trimScale
|
||||
o.selected = true
|
||||
scaleSelect.dispatchEvent(e)
|
||||
})
|
||||
})
|
||||
|
||||
const trimPage = (page) => {
|
||||
const trimScale = getTrimScale();
|
||||
const textLayer = page.getElementsByClassName('textLayer')[0];
|
||||
const canvasWrapper = page.getElementsByClassName('canvasWrapper')[0];
|
||||
const canvas = page.getElementsByTagName('canvas')[0];
|
||||
const trimScale = getTrimScale()
|
||||
const textLayer = page.getElementsByClassName('textLayer')[0]
|
||||
const canvasWrapper = page.getElementsByClassName('canvasWrapper')[0]
|
||||
const canvas = page.getElementsByTagName('canvas')[0]
|
||||
if ( !canvasWrapper || !canvas ) {
|
||||
if (page.style.width !== '250px') {
|
||||
page.style.width = '250px';
|
||||
page.style.width = '250px'
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
const w = canvas.style.width;
|
||||
const m = w.match(/(\d+)/);
|
||||
const w = canvas.style.width
|
||||
const m = w.match(/(\d+)/)
|
||||
if (m) {
|
||||
// add -4px to ensure that no horizontal scroll bar appears.
|
||||
const widthNum = Math.floor(Number(m[1])/trimScale) - 4;
|
||||
const width = widthNum + 'px';
|
||||
page.style.width = width;
|
||||
canvasWrapper.style.width = width;
|
||||
const offsetX = - Number(m[1]) * (1 - 1/trimScale) / 2;
|
||||
canvas.style.left = offsetX + 'px';
|
||||
canvas.style.position = 'relative';
|
||||
canvas.setAttribute('data-is-trimmed', 'trimmed');
|
||||
const widthNum = Math.floor(Number(m[1])/trimScale) - 4
|
||||
const width = widthNum + 'px'
|
||||
page.style.width = width
|
||||
canvasWrapper.style.width = width
|
||||
const offsetX = - Number(m[1]) * (1 - 1/trimScale) / 2
|
||||
canvas.style.left = offsetX + 'px'
|
||||
canvas.style.position = 'relative'
|
||||
canvas.setAttribute('data-is-trimmed', 'trimmed')
|
||||
if ( textLayer && textLayer.dataset.isTrimmed !== 'trimmed' ) {
|
||||
textLayer.style.width = widthNum - offsetX + 'px';
|
||||
textLayer.style.left = offsetX + 'px';
|
||||
textLayer.setAttribute('data-is-trimmed', 'trimmed');
|
||||
textLayer.style.width = widthNum - offsetX + 'px'
|
||||
textLayer.style.left = offsetX + 'px'
|
||||
textLayer.setAttribute('data-is-trimmed', 'trimmed')
|
||||
}
|
||||
const secionOfAnnotationArray = page.getElementsByTagName('section');
|
||||
const secionOfAnnotationArray = page.getElementsByTagName('section')
|
||||
for ( const secionOfAnnotation of secionOfAnnotationArray ) {
|
||||
let originalLeft = secionOfAnnotation.style.left;
|
||||
let originalLeft = secionOfAnnotation.style.left
|
||||
if (secionOfAnnotation.dataset.originalLeft === undefined) {
|
||||
secionOfAnnotation.setAttribute('data-original-left', secionOfAnnotation.style.left);
|
||||
secionOfAnnotation.setAttribute('data-original-left', secionOfAnnotation.style.left)
|
||||
} else {
|
||||
originalLeft = secionOfAnnotation.dataset.originalLeft;
|
||||
originalLeft = secionOfAnnotation.dataset.originalLeft
|
||||
}
|
||||
const mat = originalLeft.match(/(\d+)/)
|
||||
if (mat) {
|
||||
@ -546,40 +550,40 @@ const trimPage = (page) => {
|
||||
}
|
||||
|
||||
window.addEventListener('pagerendered', () => {
|
||||
const container = document.getElementById('trimSelectContainer');
|
||||
const container = document.getElementById('trimSelectContainer')
|
||||
const select = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
container.setAttribute('style', 'display: inherit;');
|
||||
container.setAttribute('style', 'display: inherit;')
|
||||
if (container.clientWidth > 0) {
|
||||
select.setAttribute('style', 'min-width: inherit;');
|
||||
const width = select.clientWidth + 8;
|
||||
select.setAttribute('style', 'min-width: ' + (width + 22) + 'px;');
|
||||
container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;');
|
||||
select.setAttribute('style', 'min-width: inherit;')
|
||||
const width = select.clientWidth + 8
|
||||
select.setAttribute('style', 'min-width: ' + (width + 22) + 'px;')
|
||||
container.setAttribute('style', 'min-width: ' + width + 'px; ' + 'max-width: ' + width + 'px;')
|
||||
}
|
||||
if (select.selectedIndex <= 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const viewer = document.getElementById('viewer');
|
||||
const viewer = document.getElementById('viewer')
|
||||
for( const page of viewer.getElementsByClassName('page') ){
|
||||
trimPage(page);
|
||||
trimPage(page)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const setObserverToTrim = () => {
|
||||
const observer = new MutationObserver(records => {
|
||||
const trimSelect = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
if (trimSelect.selectedIndex <= 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
records.forEach(record => {
|
||||
const page = record.target;
|
||||
trimPage(page);
|
||||
const page = record.target
|
||||
trimPage(page)
|
||||
})
|
||||
})
|
||||
const viewer = document.getElementById('viewer');
|
||||
const viewer = document.getElementById('viewer')
|
||||
for( const page of viewer.getElementsByClassName('page') as HTMLCollectionOf<HTMLElement> ){
|
||||
if (page.dataset.isObserved !== 'observed') {
|
||||
observer.observe(page, {attributes: true, childList: true, attributeFilter: ['style']});
|
||||
page.setAttribute('data-is-observed', 'observed');
|
||||
observer.observe(page, {attributes: true, childList: true, attributeFilter: ['style']})
|
||||
page.setAttribute('data-is-observed', 'observed')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -587,18 +591,18 @@ const setObserverToTrim = () => {
|
||||
// We need to recaluculate scale and left offset for trim mode on each resize event.
|
||||
window.addEventListener('resize', () =>{
|
||||
const trimSelect = document.getElementById('trimSelect') as HTMLSelectElement
|
||||
const ind = trimSelect.selectedIndex;
|
||||
const ind = trimSelect.selectedIndex
|
||||
if (!trimSelect || ind <= 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
trimSelect.selectedIndex = 0;
|
||||
const e = new Event('change');
|
||||
trimSelect.dispatchEvent(e);
|
||||
trimSelect.selectedIndex = ind;
|
||||
trimSelect.dispatchEvent(e);
|
||||
trimSelect.selectedIndex = 0
|
||||
const e = new Event('change')
|
||||
trimSelect.dispatchEvent(e)
|
||||
trimSelect.selectedIndex = ind
|
||||
trimSelect.dispatchEvent(e)
|
||||
})
|
||||
|
||||
// Set observers after a pdf file is loaded in the first time.
|
||||
window.addEventListener('pagerendered', setObserverToTrim, {once: true});
|
||||
window.addEventListener('pagerendered', setObserverToTrim, {once: true})
|
||||
// Set observers each time a pdf file is refresed.
|
||||
window.addEventListener('refreshed', setObserverToTrim);
|
||||
window.addEventListener('refreshed', setObserverToTrim)
|
||||
|
Loading…
Reference in New Issue
Block a user