first commit
This commit is contained in:
commit
9ab627d5c1
BIN
.gitignore
vendored
Normal file
BIN
.gitignore
vendored
Normal file
Binary file not shown.
BIN
src/.gitignore
vendored
Normal file
BIN
src/.gitignore
vendored
Normal file
Binary file not shown.
186
src/dist/bundle.js
vendored
Normal file
186
src/dist/bundle.js
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
|
||||
* This devtool is neither made for production nor for readable output files.
|
||||
* It uses "eval()" calls to create a separate source file in the browser devtools.
|
||||
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
|
||||
* or disable the default devtool with "devtool: false".
|
||||
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
|
||||
*/
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ({
|
||||
|
||||
/***/ "./doc_viewer/api/canvas_factory.js":
|
||||
/*!******************************************!*\
|
||||
!*** ./doc_viewer/api/canvas_factory.js ***!
|
||||
\******************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CanvasFactory: () => (/* binding */ CanvasFactory)\n/* harmony export */ });\n\r\nclass CanvasFactory {\r\n /**\r\n * @param {number} width\r\n * @param {number} height\r\n */\r\n create(width, height) {\r\n if (typeof OffscreenCanvas !== \"undefined\") {\r\n const canvas = new OffscreenCanvas(width, height);\r\n const context = canvas.getContext('2d');\r\n return {\r\n canvas,\r\n context,\r\n };\r\n } else if (typeof document !== \"undefined\") {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n const context = canvas.getContext('2d');\r\n return {\r\n canvas,\r\n context,\r\n };\r\n } else {\r\n throw new Error(`Not implemented`);\r\n }\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/api/canvas_factory.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/api/interfaces.js":
|
||||
/*!**************************************!*\
|
||||
!*** ./doc_viewer/api/interfaces.js ***!
|
||||
\**************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DocStruct: () => (/* binding */ DocStruct),\n/* harmony export */ IPageView: () => (/* binding */ IPageView),\n/* harmony export */ IPageViewFactory: () => (/* binding */ IPageViewFactory),\n/* harmony export */ IRender: () => (/* binding */ IRender),\n/* harmony export */ PageViewPort: () => (/* binding */ PageViewPort)\n/* harmony export */ });\n\r\nclass PageViewPort {\r\n #width;\r\n #height;\r\n #scale;\r\n #rotation;\r\n\r\n constructor({\r\n width = 0,\r\n height = 0,\r\n scale = 1,\r\n rotation = 0,\r\n }) {\r\n this.#width = width;\r\n this.#height = height;\r\n this.#scale = scale;\r\n this.#rotation = rotation;\r\n }\r\n\r\n get width() {\r\n return this.#width;\r\n }\r\n\r\n get height() {\r\n return this.#height;\r\n }\r\n\r\n get scale() {\r\n return this.#scale;\r\n }\r\n\r\n get rotation() {\r\n return this.#rotation;\r\n }\r\n}\r\n\r\nclass IRender {\r\n constructor() {\r\n }\r\n\r\n render() {\r\n const div = document.createElement('div');\r\n return div;\r\n }\r\n\r\n dispose() {\r\n }\r\n}\r\n\r\nclass IPageView extends IRender {\r\n constructor() {\r\n super();\r\n this.viewport = new PageViewPort({});\r\n }\r\n\r\n dispose() {\r\n super.dispose();\r\n }\r\n\r\n /**\r\n * @returns {Promise<void>}\r\n */\r\n draw() {\r\n }\r\n}\r\n\r\nclass IPageViewFactory {\r\n constructor() {\r\n }\r\n\r\n async createViews() {\r\n const pageView = new IPageView();\r\n return [pageView];\r\n }\r\n}\r\n\r\nclass DocStruct {\r\n #title;\r\n #factory;\r\n\r\n /**\r\n * @param {string} title\r\n * @param {IPageViewFactory | IPageViewFactory[]} factory\r\n */\r\n constructor(title, factory) {\r\n this.#title = title;\r\n this.#factory = factory;\r\n }\r\n\r\n get title() {\r\n return this.#title;\r\n }\r\n\r\n get factory() {\r\n return this.#factory;\r\n }\r\n\r\n async createPageViews() {\r\n if (Array.isArray(this.#factory)) {\r\n const buffer = [];\r\n for (const factory of this.#factory) {\r\n const result = await factory.createViews();\r\n buffer.push(...result);\r\n }\r\n\r\n return buffer;\r\n }\r\n\r\n return await this.#factory.createViews();\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/api/interfaces.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/api/views/images/image_page_view.js":
|
||||
/*!********************************************************!*\
|
||||
!*** ./doc_viewer/api/views/images/image_page_view.js ***!
|
||||
\********************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImagePageView: () => (/* binding */ ImagePageView)\n/* harmony export */ });\n/* harmony import */ var _interfaces_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../interfaces.js */ \"./doc_viewer/api/interfaces.js\");\n/* harmony import */ var _canvas_factory_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../canvas_factory.js */ \"./doc_viewer/api/canvas_factory.js\");\n\r\n\r\n\r\nclass ImagePageView extends _interfaces_js__WEBPACK_IMPORTED_MODULE_0__.IPageView {\r\n /** @type {HTMLImageElement | null} */\r\n #image;\r\n /** @type {string | null} */\r\n #src;\r\n\r\n /**\r\n * @param {CanvasImageSource} imageSource\r\n */\r\n constructor(imageSource) {\r\n super();\r\n this.imageSource = imageSource;\r\n this.#image = null;\r\n this.#src = null;\r\n this.#calcRectangle();\r\n }\r\n\r\n #calcRectangle() {\r\n if (\"naturalWidth\" in this.imageSource) {\r\n this.width = this.imageSource.naturalWidth;\r\n this.height = this.imageSource.naturalHeight;\r\n } else {\r\n this.width = this.imageSource.width;\r\n this.height = this.imageSource.height;\r\n }\r\n }\r\n\r\n render() {\r\n const div = super.render();\r\n div.style.width = `calc(${this.width}px)`;\r\n div.style.height = `calc(${this.height}px)`;\r\n this.#image ||= document.createElement('img');\r\n div.append(this.#image);\r\n return div;\r\n }\r\n\r\n async draw() {\r\n await super.draw();\r\n if (this.#src) return;\r\n\r\n const factory = new _canvas_factory_js__WEBPACK_IMPORTED_MODULE_1__.CanvasFactory();\r\n const { canvas, context } = factory.create(this.width, this.height);\r\n\r\n try {\r\n context.drawImage(this.imageSource, 0, 0);\r\n let blob = null;\r\n if (\"convertToBlob\" in canvas) {\r\n blob = await canvas.convertToBlob();\r\n } else {\r\n blob = await new Promise(resolve => canvas.toBlob(resolve));\r\n }\r\n\r\n this.#src = window.URL.createObjectURL(blob);\r\n const promise = Promise.withResolvers();\r\n\r\n this.#image.onload = promise.resolve;\r\n this.#image.onerror = promise.reject;\r\n this.#image.src = this.#src;\r\n\r\n await promise.promise;\r\n } finally {\r\n canvas.width = 0;\r\n canvas.height = 0;\r\n }\r\n }\r\n\r\n dispose() {\r\n super.dispose();\r\n if (this.#src) {\r\n window.URL.revokeObjectURL(this.#src);\r\n }\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/api/views/images/image_page_view.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/api/views/images/image_page_view_factory.js":
|
||||
/*!****************************************************************!*\
|
||||
!*** ./doc_viewer/api/views/images/image_page_view_factory.js ***!
|
||||
\****************************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImagePageViewFactory: () => (/* binding */ ImagePageViewFactory)\n/* harmony export */ });\n/* harmony import */ var _interfaces_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../interfaces.js */ \"./doc_viewer/api/interfaces.js\");\n/* harmony import */ var _image_page_view_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./image_page_view.js */ \"./doc_viewer/api/views/images/image_page_view.js\");\n\r\n\r\n\r\nclass ImagePageViewFactory extends _interfaces_js__WEBPACK_IMPORTED_MODULE_0__.IPageViewFactory {\r\n /**\r\n * @param {(string | Blob)[]} sources\r\n */\r\n constructor(sources) {\r\n super();\r\n this.sources = sources;\r\n }\r\n\r\n async createViews() {\r\n const views = [];\r\n for (const src of this.sources) {\r\n let blob = src;\r\n if (typeof src === \"string\") {\r\n blob = await fetch(src).then(response => response.blob());\r\n }\r\n\r\n const bitmap = await createImageBitmap(blob);\r\n views.push(new _image_page_view_js__WEBPACK_IMPORTED_MODULE_1__.ImagePageView(bitmap));\r\n }\r\n\r\n return views;\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/api/views/images/image_page_view_factory.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/app.js":
|
||||
/*!*******************************!*\
|
||||
!*** ./doc_viewer/web/app.js ***!
|
||||
\*******************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ViewerApplication: () => (/* binding */ ViewerApplication)\n/* harmony export */ });\n/* harmony import */ var _api_interfaces_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api/interfaces.js */ \"./doc_viewer/api/interfaces.js\");\n/* harmony import */ var _components_document_factory_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/document_factory.js */ \"./doc_viewer/web/components/document_factory.js\");\n/* harmony import */ var _components_event_bus_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/event_bus.js */ \"./doc_viewer/web/components/event_bus.js\");\n/* harmony import */ var _components_file_selecter_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./components/file_selecter.js */ \"./doc_viewer/web/components/file_selecter.js\");\n/* harmony import */ var _components_rendering_queue_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./components/rendering_queue.js */ \"./doc_viewer/web/components/rendering_queue.js\");\n/* harmony import */ var _doc_viewer_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./doc_viewer.js */ \"./doc_viewer/web/doc_viewer.js\");\n\r\n\r\n\r\n\r\n\r\n\r\n\r\nclass ViewerApplication {\r\n #config;\r\n #eventBus;\r\n #viewer;\r\n\r\n constructor(config) {\r\n this.#config = config;\r\n this.#eventBus = new _components_event_bus_js__WEBPACK_IMPORTED_MODULE_2__.EventBus();\r\n this.#viewer = new _doc_viewer_js__WEBPACK_IMPORTED_MODULE_5__.DocViewer(this.#config.pageViewer, this.#eventBus);\r\n this.fileSelector = new _components_file_selecter_js__WEBPACK_IMPORTED_MODULE_3__.FileSelector(this.#config.fileSelector, this.#eventBus);\r\n this.renderingQueue = new _components_rendering_queue_js__WEBPACK_IMPORTED_MODULE_4__.RenderingQueue(this.#viewer, this.#eventBus);\r\n\r\n this.#initEvent();\r\n }\r\n\r\n /**\r\n * @param {DocStruct | null} doc\r\n */\r\n setDocument(doc) {\r\n this.#viewer.setDocument(doc);\r\n }\r\n\r\n #initEvent() {\r\n this.#eventBus.on('fileSelector:input', ({ files }) => {\r\n const factory = new _components_document_factory_js__WEBPACK_IMPORTED_MODULE_1__.DocumentFactory(files);\r\n this.setDocument(factory.create());\r\n });\r\n\r\n this.#eventBus.on('docViewer:ready', () => {\r\n console.log('ready viewer');\r\n });\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/app.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/components/document_factory.js":
|
||||
/*!*******************************************************!*\
|
||||
!*** ./doc_viewer/web/components/document_factory.js ***!
|
||||
\*******************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DocumentFactory: () => (/* binding */ DocumentFactory)\n/* harmony export */ });\n/* harmony import */ var _api_interfaces_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../api/interfaces.js */ \"./doc_viewer/api/interfaces.js\");\n/* harmony import */ var _api_views_images_image_page_view_factory_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../api/views/images/image_page_view_factory.js */ \"./doc_viewer/api/views/images/image_page_view_factory.js\");\n\r\n\r\n\r\nclass DocumentFactory {\r\n /**\r\n * @param {Blob[]} files\r\n */\r\n constructor(files) {\r\n this.files = files;\r\n }\r\n\r\n create() {\r\n const factories = [];\r\n for (const file of this.files) {\r\n const ret = this.#ensure(file);\r\n factories.push(ret);\r\n }\r\n\r\n const docStruct = new _api_interfaces_js__WEBPACK_IMPORTED_MODULE_0__.DocStruct(\"\", factories);\r\n return docStruct;\r\n }\r\n\r\n /**\r\n * @param {Blob} file\r\n */\r\n #ensure(file) {\r\n switch (file.type) {\r\n case \"image/jpeg\":\r\n case \"image/png\":\r\n case \"image/gif\":\r\n case \"image/bmp\": {\r\n return new _api_views_images_image_page_view_factory_js__WEBPACK_IMPORTED_MODULE_1__.ImagePageViewFactory([file]);\r\n }\r\n default: {\r\n throw new Error(`Unknown file type.`);\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/components/document_factory.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/components/event_bus.js":
|
||||
/*!************************************************!*\
|
||||
!*** ./doc_viewer/web/components/event_bus.js ***!
|
||||
\************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ EventBus: () => (/* binding */ EventBus)\n/* harmony export */ });\n\r\nclass EventBus {\r\n /** @type {Map<string, Function[]>} */\r\n #listeners;\r\n\r\n constructor() {\r\n this.#listeners = new Map();\r\n }\r\n\r\n on(eventName, eventListener) {\r\n const stack = this.#ensureEventStack(eventName);\r\n stack.push(eventListener);\r\n }\r\n\r\n off(eventName, eventListener) {\r\n const stack = this.#ensureEventStack(eventName);\r\n const ix = stack.indexOf(eventListener);\r\n if (ix !== -1) {\r\n stack.splice(ix, 1);\r\n }\r\n }\r\n\r\n dispatch(eventName, eventDetails) {\r\n for (const handler of this.#ensureEventStack(eventName).slice()) {\r\n handler?.(eventDetails);\r\n }\r\n }\r\n\r\n /**\r\n * @param {string} eventName\r\n */\r\n #ensureEventStack(eventName) {\r\n if (!this.#listeners.has(eventName)) {\r\n this.#listeners.set(eventName, []);\r\n }\r\n\r\n return this.#listeners.get(eventName);\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/components/event_bus.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/components/file_selecter.js":
|
||||
/*!****************************************************!*\
|
||||
!*** ./doc_viewer/web/components/file_selecter.js ***!
|
||||
\****************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ FileSelector: () => (/* binding */ FileSelector)\n/* harmony export */ });\n/* harmony import */ var _event_bus_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./event_bus.js */ \"./doc_viewer/web/components/event_bus.js\");\n\r\n\r\nclass FileSelector {\r\n #fileInput;\r\n #openButton;\r\n #eventBus;\r\n\r\n /**\r\n * @param {Object} options\r\n * @param {HTMLInputElement} options.fileInput\r\n * @param {HTMLButtonElement} options.openButton\r\n * @param {EventBus} eventBus\r\n */\r\n constructor({\r\n fileInput,\r\n openButton\r\n }, eventBus) {\r\n this.#fileInput = fileInput;\r\n this.#openButton = openButton;\r\n this.#eventBus = eventBus;\r\n this.#initialize();\r\n }\r\n\r\n #initialize() {\r\n this.#openButton.addEventListener('click', e => {\r\n this.#fileInput.click();\r\n });\r\n\r\n this.#fileInput.addEventListener('input', e => {\r\n const files = this.#fileInput.files;\r\n if (!files?.[0]) {\r\n return;\r\n }\r\n\r\n this.#eventBus.dispatch('fileSelector:input', {\r\n files: [...files],\r\n });\r\n this.#fileInput.value = \"\";\r\n });\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/components/file_selecter.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/components/rendering_queue.js":
|
||||
/*!******************************************************!*\
|
||||
!*** ./doc_viewer/web/components/rendering_queue.js ***!
|
||||
\******************************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ RenderingQueue: () => (/* binding */ RenderingQueue)\n/* harmony export */ });\n/* harmony import */ var _doc_viewer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../doc_viewer.js */ \"./doc_viewer/web/doc_viewer.js\");\n/* harmony import */ var _event_bus_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./event_bus.js */ \"./doc_viewer/web/components/event_bus.js\");\n\r\n\r\n\r\nclass RenderingQueue {\r\n #viewer;\r\n #eventBus;\r\n\r\n /**\r\n * @param {DocViewer} viewer\r\n * @param {EventBus} eventBus\r\n */\r\n constructor(viewer, eventBus) {\r\n this.#viewer = viewer;\r\n this.#eventBus = eventBus;\r\n\r\n this.#bindEvents();\r\n }\r\n\r\n #bindEvents() {\r\n this.#eventBus.on('docViewer:ready', () => {\r\n this.#ensureTask();\r\n });\r\n }\r\n\r\n async #ensureTask(p = 0) {\r\n const view = this.#viewer.getView(p);\r\n if (!view) return;\r\n await view.draw();\r\n return this.#ensureTask(p++);\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/components/rendering_queue.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/doc_viewer.js":
|
||||
/*!**************************************!*\
|
||||
!*** ./doc_viewer/web/doc_viewer.js ***!
|
||||
\**************************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DocViewer: () => (/* binding */ DocViewer)\n/* harmony export */ });\n/* harmony import */ var _api_interfaces_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../api/interfaces.js */ \"./doc_viewer/api/interfaces.js\");\n/* harmony import */ var _components_event_bus_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/event_bus.js */ \"./doc_viewer/web/components/event_bus.js\");\n\r\n\r\n\r\nclass DocViewer {\r\n /** @type {DocStruct | null} */\r\n #document;\r\n /** @type {IPageView[]} */\r\n #views;\r\n #eventBus;\r\n #options;\r\n\r\n /**\r\n * @param {Record<string, HTMLElement>} options\r\n * @param {EventBus} eventBus\r\n */\r\n constructor(options, eventBus) {\r\n this.#document = null;\r\n this.#views = [];\r\n this.#eventBus = eventBus;\r\n this.#options = options;\r\n }\r\n\r\n /**\r\n * @param {DocStruct | null} document\r\n */\r\n setDocument(document) {\r\n if (this.#document) {\r\n for (const view of this.#views) {\r\n view.dispose();\r\n }\r\n this.#views.length = 0;\r\n }\r\n\r\n this.#document = document;\r\n if (!document) {\r\n return;\r\n }\r\n\r\n document.createPageViews().then(pageViews => {\r\n this.#views.length = 0;\r\n for (const view of pageViews) {\r\n this.#views.push(view);\r\n }\r\n return this.#initialize();\r\n }).then(() => {\r\n this.#eventBus.dispatch('docViewer:ready');\r\n });\r\n }\r\n\r\n async #initialize() {\r\n for (const view of this.#views) {\r\n const div = view.render();\r\n this.#options.container.append(div);\r\n }\r\n }\r\n\r\n get pagesCount() {\r\n return this.#views.length;\r\n }\r\n\r\n getView(pageNumber) {\r\n return this.#views.at(pageNumber);\r\n }\r\n\r\n async drawAll() {\r\n for (const view of this.#views) {\r\n await view.draw();\r\n }\r\n }\r\n}\r\n\r\n\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/doc_viewer.js?");
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./doc_viewer/web/viewer.js":
|
||||
/*!**********************************!*\
|
||||
!*** ./doc_viewer/web/viewer.js ***!
|
||||
\**********************************/
|
||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||
|
||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _app_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./app.js */ \"./doc_viewer/web/app.js\");\n\r\n\r\nfunction getViewerConfiguration() {\r\n return {\r\n pageViewer: {\r\n container: document.getElementById('page-viewer'),\r\n },\r\n fileSelector: {\r\n container: document.getElementById('file-selector'),\r\n openButton: document.getElementById('file-selector-button'),\r\n fileInput: document.getElementById('file-selector-input'),\r\n },\r\n };\r\n}\r\n\r\nfunction onLoaded() {\r\n const viewer = getViewerConfiguration();\r\n const app = new _app_js__WEBPACK_IMPORTED_MODULE_0__.ViewerApplication(viewer);\r\n window.app = app;\r\n return app;\r\n}\r\n\r\nif (document.readyState === \"loading\") {\r\n document.addEventListener('DOMContentLoaded', onLoaded);\r\n} else {\r\n onLoaded();\r\n}\r\n\n\n//# sourceURL=webpack:///./doc_viewer/web/viewer.js?");
|
||||
|
||||
/***/ })
|
||||
|
||||
/******/ });
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ // no module.id needed
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = (exports, definition) => {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/
|
||||
/******/ // startup
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ // This entry module can't be inlined because the eval devtool is used.
|
||||
/******/ var __webpack_exports__ = __webpack_require__("./doc_viewer/web/viewer.js");
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
0
src/dist/viewer.css
vendored
Normal file
0
src/dist/viewer.css
vendored
Normal file
25
src/dist/viewer.html
vendored
Normal file
25
src/dist/viewer.html
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Doc Viewer</title>
|
||||
<link rel="stylesheet" href="./viewer.css" />
|
||||
<script src="./bundle.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="viewer-container">
|
||||
<div class="toolbar-container">
|
||||
<div class="file-selector-component" id="file-selector">
|
||||
<button type="button" id="file-selector-button"></button>
|
||||
<input type="file" id="file-selector-input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-container">
|
||||
<div id="page-viewer"></div>
|
||||
</div>
|
||||
<div class="bottom-toolbar-container">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
32
src/doc_viewer/api/canvas_factory.js
Normal file
32
src/doc_viewer/api/canvas_factory.js
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
class CanvasFactory {
|
||||
/**
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
*/
|
||||
create(width, height) {
|
||||
if (typeof OffscreenCanvas !== "undefined") {
|
||||
const canvas = new OffscreenCanvas(width, height);
|
||||
const context = canvas.getContext('2d');
|
||||
return {
|
||||
canvas,
|
||||
context,
|
||||
};
|
||||
} else if (typeof document !== "undefined") {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const context = canvas.getContext('2d');
|
||||
return {
|
||||
canvas,
|
||||
context,
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Not implemented`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
CanvasFactory,
|
||||
}
|
119
src/doc_viewer/api/interfaces.js
Normal file
119
src/doc_viewer/api/interfaces.js
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
class PageViewPort {
|
||||
#width;
|
||||
#height;
|
||||
#scale;
|
||||
#rotation;
|
||||
|
||||
constructor({
|
||||
width = 0,
|
||||
height = 0,
|
||||
scale = 1,
|
||||
rotation = 0,
|
||||
}) {
|
||||
this.#width = width;
|
||||
this.#height = height;
|
||||
this.#scale = scale;
|
||||
this.#rotation = rotation;
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.#width;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.#height;
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.#scale;
|
||||
}
|
||||
|
||||
get rotation() {
|
||||
return this.#rotation;
|
||||
}
|
||||
}
|
||||
|
||||
class IRender {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
render() {
|
||||
const div = document.createElement('div');
|
||||
return div;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
}
|
||||
}
|
||||
|
||||
class IPageView extends IRender {
|
||||
constructor() {
|
||||
super();
|
||||
this.viewport = new PageViewPort({});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
draw() {
|
||||
}
|
||||
}
|
||||
|
||||
class IPageViewFactory {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
async createViews() {
|
||||
const pageView = new IPageView();
|
||||
return [pageView];
|
||||
}
|
||||
}
|
||||
|
||||
class DocStruct {
|
||||
#title;
|
||||
#factory;
|
||||
|
||||
/**
|
||||
* @param {string} title
|
||||
* @param {IPageViewFactory | IPageViewFactory[]} factory
|
||||
*/
|
||||
constructor(title, factory) {
|
||||
this.#title = title;
|
||||
this.#factory = factory;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.#title;
|
||||
}
|
||||
|
||||
get factory() {
|
||||
return this.#factory;
|
||||
}
|
||||
|
||||
async createPageViews() {
|
||||
if (Array.isArray(this.#factory)) {
|
||||
const buffer = [];
|
||||
for (const factory of this.#factory) {
|
||||
const result = await factory.createViews();
|
||||
buffer.push(...result);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return await this.#factory.createViews();
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
PageViewPort,
|
||||
IRender,
|
||||
IPageView,
|
||||
IPageViewFactory,
|
||||
DocStruct,
|
||||
}
|
80
src/doc_viewer/api/views/images/image_page_view.js
Normal file
80
src/doc_viewer/api/views/images/image_page_view.js
Normal file
@ -0,0 +1,80 @@
|
||||
import { IPageView } from "../../interfaces.js";
|
||||
import { CanvasFactory } from "../../canvas_factory.js";
|
||||
|
||||
class ImagePageView extends IPageView {
|
||||
/** @type {HTMLImageElement | null} */
|
||||
#image;
|
||||
/** @type {string | null} */
|
||||
#src;
|
||||
|
||||
/**
|
||||
* @param {CanvasImageSource} imageSource
|
||||
*/
|
||||
constructor(imageSource) {
|
||||
super();
|
||||
this.imageSource = imageSource;
|
||||
this.#image = null;
|
||||
this.#src = null;
|
||||
this.#calcRectangle();
|
||||
}
|
||||
|
||||
#calcRectangle() {
|
||||
if ("naturalWidth" in this.imageSource) {
|
||||
this.width = this.imageSource.naturalWidth;
|
||||
this.height = this.imageSource.naturalHeight;
|
||||
} else {
|
||||
this.width = this.imageSource.width;
|
||||
this.height = this.imageSource.height;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const div = super.render();
|
||||
div.style.width = `calc(${this.width}px)`;
|
||||
div.style.height = `calc(${this.height}px)`;
|
||||
this.#image ||= document.createElement('img');
|
||||
div.append(this.#image);
|
||||
return div;
|
||||
}
|
||||
|
||||
async draw() {
|
||||
await super.draw();
|
||||
if (this.#src) return;
|
||||
|
||||
const factory = new CanvasFactory();
|
||||
const { canvas, context } = factory.create(this.width, this.height);
|
||||
|
||||
try {
|
||||
context.drawImage(this.imageSource, 0, 0);
|
||||
let blob = null;
|
||||
if ("convertToBlob" in canvas) {
|
||||
blob = await canvas.convertToBlob();
|
||||
} else {
|
||||
blob = await new Promise(resolve => canvas.toBlob(resolve));
|
||||
}
|
||||
|
||||
this.#src = window.URL.createObjectURL(blob);
|
||||
const promise = Promise.withResolvers();
|
||||
|
||||
this.#image.onload = promise.resolve;
|
||||
this.#image.onerror = promise.reject;
|
||||
this.#image.src = this.#src;
|
||||
|
||||
await promise.promise;
|
||||
} finally {
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
if (this.#src) {
|
||||
window.URL.revokeObjectURL(this.#src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ImagePageView,
|
||||
}
|
31
src/doc_viewer/api/views/images/image_page_view_factory.js
Normal file
31
src/doc_viewer/api/views/images/image_page_view_factory.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { IPageViewFactory } from "../../interfaces.js";
|
||||
import { ImagePageView } from "./image_page_view.js";
|
||||
|
||||
class ImagePageViewFactory extends IPageViewFactory {
|
||||
/**
|
||||
* @param {(string | Blob)[]} sources
|
||||
*/
|
||||
constructor(sources) {
|
||||
super();
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
async createViews() {
|
||||
const views = [];
|
||||
for (const src of this.sources) {
|
||||
let blob = src;
|
||||
if (typeof src === "string") {
|
||||
blob = await fetch(src).then(response => response.blob());
|
||||
}
|
||||
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
views.push(new ImagePageView(bitmap));
|
||||
}
|
||||
|
||||
return views;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ImagePageViewFactory,
|
||||
}
|
44
src/doc_viewer/web/app.js
Normal file
44
src/doc_viewer/web/app.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { DocStruct } from "../api/interfaces.js";
|
||||
import { DocumentFactory } from "./components/document_factory.js";
|
||||
import { EventBus } from "./components/event_bus.js";
|
||||
import { FileSelector } from "./components/file_selecter.js";
|
||||
import { RenderingQueue } from "./components/rendering_queue.js";
|
||||
import { DocViewer } from "./doc_viewer.js";
|
||||
|
||||
class ViewerApplication {
|
||||
#config;
|
||||
#eventBus;
|
||||
#viewer;
|
||||
|
||||
constructor(config) {
|
||||
this.#config = config;
|
||||
this.#eventBus = new EventBus();
|
||||
this.#viewer = new DocViewer(this.#config.pageViewer, this.#eventBus);
|
||||
this.fileSelector = new FileSelector(this.#config.fileSelector, this.#eventBus);
|
||||
this.renderingQueue = new RenderingQueue(this.#viewer, this.#eventBus);
|
||||
|
||||
this.#initEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {DocStruct | null} doc
|
||||
*/
|
||||
setDocument(doc) {
|
||||
this.#viewer.setDocument(doc);
|
||||
}
|
||||
|
||||
#initEvent() {
|
||||
this.#eventBus.on('fileSelector:input', ({ files }) => {
|
||||
const factory = new DocumentFactory(files);
|
||||
this.setDocument(factory.create());
|
||||
});
|
||||
|
||||
this.#eventBus.on('docViewer:ready', () => {
|
||||
console.log('ready viewer');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ViewerApplication,
|
||||
}
|
43
src/doc_viewer/web/components/document_factory.js
Normal file
43
src/doc_viewer/web/components/document_factory.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { DocStruct } from "../../api/interfaces.js";
|
||||
import { ImagePageViewFactory } from "../../api/views/images/image_page_view_factory.js";
|
||||
|
||||
class DocumentFactory {
|
||||
/**
|
||||
* @param {Blob[]} files
|
||||
*/
|
||||
constructor(files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
create() {
|
||||
const factories = [];
|
||||
for (const file of this.files) {
|
||||
const ret = this.#ensure(file);
|
||||
factories.push(ret);
|
||||
}
|
||||
|
||||
const docStruct = new DocStruct("", factories);
|
||||
return docStruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Blob} file
|
||||
*/
|
||||
#ensure(file) {
|
||||
switch (file.type) {
|
||||
case "image/jpeg":
|
||||
case "image/png":
|
||||
case "image/gif":
|
||||
case "image/bmp": {
|
||||
return new ImagePageViewFactory([file]);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown file type.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DocumentFactory,
|
||||
}
|
43
src/doc_viewer/web/components/event_bus.js
Normal file
43
src/doc_viewer/web/components/event_bus.js
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
class EventBus {
|
||||
/** @type {Map<string, Function[]>} */
|
||||
#listeners;
|
||||
|
||||
constructor() {
|
||||
this.#listeners = new Map();
|
||||
}
|
||||
|
||||
on(eventName, eventListener) {
|
||||
const stack = this.#ensureEventStack(eventName);
|
||||
stack.push(eventListener);
|
||||
}
|
||||
|
||||
off(eventName, eventListener) {
|
||||
const stack = this.#ensureEventStack(eventName);
|
||||
const ix = stack.indexOf(eventListener);
|
||||
if (ix !== -1) {
|
||||
stack.splice(ix, 1);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(eventName, eventDetails) {
|
||||
for (const handler of this.#ensureEventStack(eventName).slice()) {
|
||||
handler?.(eventDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} eventName
|
||||
*/
|
||||
#ensureEventStack(eventName) {
|
||||
if (!this.#listeners.has(eventName)) {
|
||||
this.#listeners.set(eventName, []);
|
||||
}
|
||||
|
||||
return this.#listeners.get(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
EventBus,
|
||||
}
|
45
src/doc_viewer/web/components/file_selecter.js
Normal file
45
src/doc_viewer/web/components/file_selecter.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { EventBus } from "./event_bus.js";
|
||||
|
||||
class FileSelector {
|
||||
#fileInput;
|
||||
#openButton;
|
||||
#eventBus;
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {HTMLInputElement} options.fileInput
|
||||
* @param {HTMLButtonElement} options.openButton
|
||||
* @param {EventBus} eventBus
|
||||
*/
|
||||
constructor({
|
||||
fileInput,
|
||||
openButton
|
||||
}, eventBus) {
|
||||
this.#fileInput = fileInput;
|
||||
this.#openButton = openButton;
|
||||
this.#eventBus = eventBus;
|
||||
this.#initialize();
|
||||
}
|
||||
|
||||
#initialize() {
|
||||
this.#openButton.addEventListener('click', e => {
|
||||
this.#fileInput.click();
|
||||
});
|
||||
|
||||
this.#fileInput.addEventListener('input', e => {
|
||||
const files = this.#fileInput.files;
|
||||
if (!files?.[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#eventBus.dispatch('fileSelector:input', {
|
||||
files: [...files],
|
||||
});
|
||||
this.#fileInput.value = "";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
FileSelector,
|
||||
}
|
35
src/doc_viewer/web/components/rendering_queue.js
Normal file
35
src/doc_viewer/web/components/rendering_queue.js
Normal file
@ -0,0 +1,35 @@
|
||||
import { DocViewer } from "../doc_viewer.js";
|
||||
import { EventBus } from "./event_bus.js";
|
||||
|
||||
class RenderingQueue {
|
||||
#viewer;
|
||||
#eventBus;
|
||||
|
||||
/**
|
||||
* @param {DocViewer} viewer
|
||||
* @param {EventBus} eventBus
|
||||
*/
|
||||
constructor(viewer, eventBus) {
|
||||
this.#viewer = viewer;
|
||||
this.#eventBus = eventBus;
|
||||
|
||||
this.#bindEvents();
|
||||
}
|
||||
|
||||
#bindEvents() {
|
||||
this.#eventBus.on('docViewer:ready', () => {
|
||||
this.#ensureTask();
|
||||
});
|
||||
}
|
||||
|
||||
async #ensureTask(p = 0) {
|
||||
const view = this.#viewer.getView(p);
|
||||
if (!view) return;
|
||||
await view.draw();
|
||||
return this.#ensureTask(p++);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
RenderingQueue,
|
||||
}
|
74
src/doc_viewer/web/doc_viewer.js
Normal file
74
src/doc_viewer/web/doc_viewer.js
Normal file
@ -0,0 +1,74 @@
|
||||
import { DocStruct, IPageView } from "../api/interfaces.js";
|
||||
import { EventBus } from "./components/event_bus.js";
|
||||
|
||||
class DocViewer {
|
||||
/** @type {DocStruct | null} */
|
||||
#document;
|
||||
/** @type {IPageView[]} */
|
||||
#views;
|
||||
#eventBus;
|
||||
#options;
|
||||
|
||||
/**
|
||||
* @param {Record<string, HTMLElement>} options
|
||||
* @param {EventBus} eventBus
|
||||
*/
|
||||
constructor(options, eventBus) {
|
||||
this.#document = null;
|
||||
this.#views = [];
|
||||
this.#eventBus = eventBus;
|
||||
this.#options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {DocStruct | null} document
|
||||
*/
|
||||
setDocument(document) {
|
||||
if (this.#document) {
|
||||
for (const view of this.#views) {
|
||||
view.dispose();
|
||||
}
|
||||
this.#views.length = 0;
|
||||
}
|
||||
|
||||
this.#document = document;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.createPageViews().then(pageViews => {
|
||||
this.#views.length = 0;
|
||||
for (const view of pageViews) {
|
||||
this.#views.push(view);
|
||||
}
|
||||
return this.#initialize();
|
||||
}).then(() => {
|
||||
this.#eventBus.dispatch('docViewer:ready');
|
||||
});
|
||||
}
|
||||
|
||||
async #initialize() {
|
||||
for (const view of this.#views) {
|
||||
const div = view.render();
|
||||
this.#options.container.append(div);
|
||||
}
|
||||
}
|
||||
|
||||
get pagesCount() {
|
||||
return this.#views.length;
|
||||
}
|
||||
|
||||
getView(pageNumber) {
|
||||
return this.#views[pageNumber];
|
||||
}
|
||||
|
||||
async drawAll() {
|
||||
for (const view of this.#views) {
|
||||
await view.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DocViewer,
|
||||
}
|
0
src/doc_viewer/web/viewer.css
Normal file
0
src/doc_viewer/web/viewer.css
Normal file
25
src/doc_viewer/web/viewer.html
Normal file
25
src/doc_viewer/web/viewer.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Doc Viewer</title>
|
||||
<link rel="stylesheet" href="./viewer.css" />
|
||||
<script src="./viewer.js" type="module" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="viewer-container">
|
||||
<div class="toolbar-container">
|
||||
<div class="file-selector-component" id="file-selector">
|
||||
<button type="button" id="file-selector-button"></button>
|
||||
<input type="file" id="file-selector-input" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-container">
|
||||
<div id="page-viewer"></div>
|
||||
</div>
|
||||
<div class="bottom-toolbar-container">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
27
src/doc_viewer/web/viewer.js
Normal file
27
src/doc_viewer/web/viewer.js
Normal file
@ -0,0 +1,27 @@
|
||||
import { ViewerApplication } from "./app.js";
|
||||
|
||||
function getViewerConfiguration() {
|
||||
return {
|
||||
pageViewer: {
|
||||
container: document.getElementById('page-viewer'),
|
||||
},
|
||||
fileSelector: {
|
||||
container: document.getElementById('file-selector'),
|
||||
openButton: document.getElementById('file-selector-button'),
|
||||
fileInput: document.getElementById('file-selector-input'),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function onLoaded() {
|
||||
const viewer = getViewerConfiguration();
|
||||
const app = new ViewerApplication(viewer);
|
||||
window.app = app;
|
||||
return app;
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener('DOMContentLoaded', onLoaded);
|
||||
} else {
|
||||
onLoaded();
|
||||
}
|
3806
src/package-lock.json
generated
Normal file
3806
src/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
src/package.json
Normal file
13
src/package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "webpack serve --config webpack.config.js --hot",
|
||||
"build": "webpack --config webpack.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack": "^5.96.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^5.1.0"
|
||||
}
|
||||
}
|
29
src/webpack.config.js
Normal file
29
src/webpack.config.js
Normal file
@ -0,0 +1,29 @@
|
||||
const path = require("path");
|
||||
|
||||
/** @type {import("webpack").Configuration} */
|
||||
module.exports = {
|
||||
entry: './doc_viewer/web/viewer.js',
|
||||
output: {
|
||||
filename: 'bundle.js', // contenthashは使用しない
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
publicPath: ''
|
||||
},
|
||||
mode: 'development', // development
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, '/doc_viewer'),
|
||||
},
|
||||
compress: true,
|
||||
port: 9000,
|
||||
},
|
||||
module: {
|
||||
// rules: [
|
||||
// {
|
||||
// test: /\.css$/,
|
||||
// use: [
|
||||
// 'style-loader', 'css-loader' // MiniCssExtractPluginを使用しない
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
},
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user