feat: implement PDF handling to prepare for in-IDE statement viewing
This commit is contained in:
parent
217979e9d7
commit
09355188b1
68
src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDBrowserViewer.kt
Normal file
68
src/main/kotlin/io/gitlab/jfronny/sdom/ui/SDBrowserViewer.kt
Normal file
@ -0,0 +1,68 @@
|
||||
package io.gitlab.jfronny.sdom.ui
|
||||
|
||||
import com.intellij.openapi.fileEditor.FileEditor
|
||||
import com.intellij.openapi.fileEditor.FileEditorLocation
|
||||
import com.intellij.openapi.fileEditor.FileEditorState
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.jcef.JBCefBrowser
|
||||
import com.intellij.ui.jcef.JBCefBrowserBuilder
|
||||
import com.intellij.ui.jcef.JBCefClient
|
||||
import io.gitlab.jfronny.sdom.util.pdfBootstrap
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.beans.PropertyChangeListener
|
||||
import javax.swing.JComponent
|
||||
|
||||
class SDBrowserViewer(private val file: VirtualFile, cefClient: JBCefClient) : UserDataHolderBase(), FileEditor {
|
||||
private val browser: JBCefBrowser = JBCefBrowserBuilder().setClient(cefClient)
|
||||
.setEnableOpenDevToolsMenuItem(false)
|
||||
.build()
|
||||
|
||||
init {
|
||||
browser.loadHTML(pdfBootstrap(file.contentsToByteArray()))
|
||||
}
|
||||
|
||||
private val component = browser.component
|
||||
|
||||
override fun getComponent(): JComponent {
|
||||
return component
|
||||
}
|
||||
|
||||
override fun getPreferredFocusedComponent(): JComponent? {
|
||||
return component
|
||||
}
|
||||
|
||||
override fun getName(): @Nls(capitalization = Nls.Capitalization.Title) String {
|
||||
return "S-dom Integrated Statement Viewer"
|
||||
}
|
||||
|
||||
override fun setState(fileEditorState: FileEditorState) {
|
||||
}
|
||||
|
||||
override fun isModified(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
return file.isValid
|
||||
}
|
||||
|
||||
override fun addPropertyChangeListener(propertyChangeListener: PropertyChangeListener) {
|
||||
}
|
||||
|
||||
override fun removePropertyChangeListener(propertyChangeListener: PropertyChangeListener) {
|
||||
}
|
||||
|
||||
override fun getCurrentLocation(): FileEditorLocation? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
Disposer.dispose(this)
|
||||
}
|
||||
|
||||
override fun getFile(): VirtualFile? {
|
||||
return this.file
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package io.gitlab.jfronny.sdom.ui
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.fileEditor.FileEditor
|
||||
import com.intellij.openapi.fileEditor.FileEditorPolicy
|
||||
import com.intellij.openapi.fileEditor.FileEditorProvider
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.LightVirtualFileBase
|
||||
import com.intellij.ui.jcef.JBCefApp
|
||||
import org.jetbrains.annotations.NonNls
|
||||
|
||||
class SDBrowserViewerProvider : FileEditorProvider, DumbAware {
|
||||
private val ourCefClient = JBCefApp.getInstance().createClient()
|
||||
|
||||
init {
|
||||
Disposer.register(ApplicationManager.getApplication(), ourCefClient)
|
||||
}
|
||||
|
||||
override fun accept(project: Project, virtualFile: VirtualFile): Boolean {
|
||||
return virtualFile is LightVirtualFileBase && virtualFile.extension == "pdf"
|
||||
}
|
||||
|
||||
override fun createEditor(project: Project, virtualFile: VirtualFile): FileEditor {
|
||||
return SDBrowserViewer(virtualFile, ourCefClient)
|
||||
}
|
||||
|
||||
override fun getEditorTypeId(): @NonNls String {
|
||||
return EDITOR_TYPE_ID
|
||||
}
|
||||
|
||||
override fun getPolicy(): FileEditorPolicy {
|
||||
return FileEditorPolicy.HIDE_DEFAULT_EDITOR
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EDITOR_TYPE_ID = "SdomBrowserViewer"
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package io.gitlab.jfronny.sdom.util
|
||||
|
||||
import com.intellij.ui.jcef.JBCefScrollbarsHelper
|
||||
import org.intellij.lang.annotations.Language
|
||||
import java.util.Base64
|
||||
|
||||
@Language("HTML")
|
||||
fun pdfBootstrap(pdf: ByteArray) = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script src="https://mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
|
||||
<link rel='stylesheet' type='text/css' href='https://mozilla.github.io/pdf.js/web/viewer.css'>
|
||||
<style type='text/css'>
|
||||
${JBCefScrollbarsHelper.getOverlayScrollbarStyle()}
|
||||
</style>
|
||||
|
||||
<script type="module">
|
||||
const pdfData = atob('${Base64.getEncoder().encodeToString(pdf)}');
|
||||
|
||||
// Loaded via <script> tag, create shortcut to access PDF.js exports.
|
||||
const { pdfjsLib } = globalThis;
|
||||
|
||||
// The workerSrc property shall be specified.
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.mjs';
|
||||
|
||||
// Using DocumentInitParameters object to load binary data.
|
||||
const loadingTask = pdfjsLib.getDocument({data: pdfData});
|
||||
loadingTask.promise.then(function(pdf) {
|
||||
console.log('PDF loaded');
|
||||
|
||||
const body = document.getElementById('our-body');
|
||||
for (let i = 1; i <= pdf.numPages; i++) {
|
||||
pdf.getPage(i).then(function(page) {
|
||||
console.log('Page loaded');
|
||||
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({scale: scale});
|
||||
|
||||
// Prepare canvas using PDF page dimensions
|
||||
const canvas = document.createElement('canvas');
|
||||
const textLayer = document.createElement('div');
|
||||
textLayer.className = "textLayer"
|
||||
body.appendChild(canvas)
|
||||
body.appendChild(textLayer)
|
||||
const context = canvas.getContext('2d');
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
// Render PDF page into canvas context
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
const renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function () {
|
||||
return page.getTextContent()
|
||||
}).then(function (textContent) {
|
||||
|
||||
pdfjsLib.renderTextLayer({
|
||||
textContentSource: textContent,
|
||||
container: textLayer,
|
||||
viewport: viewport,
|
||||
textDivs: []
|
||||
});
|
||||
textLayer.style.left = canvas.offsetLeft + 'px';
|
||||
textLayer.style.top = canvas.offsetTop + 'px';
|
||||
textLayer.style.height = canvas.offsetHeight + 'px';
|
||||
textLayer.style.width = canvas.offsetWidth + 'px';
|
||||
});
|
||||
});
|
||||
}
|
||||
}, function (reason) {
|
||||
// PDF loading error
|
||||
console.error(reason);
|
||||
});
|
||||
</script>
|
||||
<div id="our-body" style="width: 100%" />
|
||||
</body>
|
||||
</html>
|
||||
""".trimIndent()
|
@ -25,6 +25,7 @@
|
||||
<!-- Extension points defined by the plugin.
|
||||
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<fileEditorProvider implementation="io.gitlab.jfronny.sdom.ui.SDBrowserViewerProvider"/>
|
||||
<toolWindow factoryClass="io.gitlab.jfronny.sdom.toolwindow.SDToolWindowFactory"
|
||||
id="S-DOM" anchor="bottom" canCloseContents="true" icon="io.gitlab.jfronny.sdom.icons.SDIcons.ToolWindow" />
|
||||
<notificationGroup id="sdom.notifications" displayType="BALLOON" />
|
||||
|
Loading…
Reference in New Issue
Block a user