enable ESLint for viewer/latexworkshop.ts

This commit is contained in:
Takashi Tamura 2019-11-27 20:06:21 +09:00
parent 18f3a87415
commit d358c377c8
4 changed files with 128 additions and 116 deletions

View File

@ -10,5 +10,3 @@ __pycache__/
.pytest_cache/
.venv/
.vscode/.ropeproject
viewer/**

View File

@ -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"
}
}
]

View File

@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"include": [
"viewer/**/*.ts"
],
"exclude": [
"src/**",
"dev/**"
],
"compilerOptions": {
"allowJs": true,
"checkJs": true
}
}

View File

@ -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)