From 9448729548b4fd4f278ecb038049b0b14efcf054 Mon Sep 17 00:00:00 2001 From: David Bogner Date: Thu, 12 Oct 2023 16:02:21 +0200 Subject: [PATCH] WIP: Embed PDF with pdf.js --- amd/build/pdfembed.min.js | 4 +-- amd/build/pdfembed.min.js.map | 2 +- amd/src/pdfembed.js | 36 +++++++++++++------ field/file/renderer.php | 68 ++++++++++++++++++++--------------- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/amd/build/pdfembed.min.js b/amd/build/pdfembed.min.js index 656b9b7c..7eda1c05 100644 --- a/amd/build/pdfembed.min.js +++ b/amd/build/pdfembed.min.js @@ -1,4 +1,4 @@ -define("mod_datalynx/pdfembed",["exports","mod_datalynx/pdf","mod_datalynx/pdf.worker"],(function(_exports,pdfjsLib,_pdf2){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.renderPDF=function(){const pdf=M.cfg.wwwroot+"/mod/datalynx/tests/turnen.pdf",canvas=document.querySelector("#resourceobject").parentElement;console.log(pdfjsLib), +define("mod_datalynx/pdfembed",["exports","mod_datalynx/pdf","mod_datalynx/pdf.worker"],(function(_exports,pdfjsLib,_pdf2){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.renderPDF=function(pdfUrl,canvasContainerId){M.cfg.wwwroot;const container=document.querySelector("#".concat(canvasContainerId));console.log(pdfjsLib),console.log(pdfUrl),console.log(container), /** * This module provides functionality for embedding PDFs using pdf.js. * @@ -6,6 +6,6 @@ define("mod_datalynx/pdfembed",["exports","mod_datalynx/pdf","mod_datalynx/pdf.w * @copyright 2023 David Bogner * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -function(url,canvasContainer,options){options=options||{scale:1};function renderPage(page){var viewport=page.getViewport(options.scale),canvas=document.createElement("canvas"),renderContext={canvasContext:canvas.getContext("2d"),viewport:viewport};canvas.height=viewport.height,canvas.width=viewport.width,canvasContainer.appendChild(canvas),console.log(canvasContainer,canvas),page.render(renderContext)}function renderPages(pdfDoc){for(var num=1;num<=pdfDoc.numPages;num++)pdfDoc.getPage(num).then(renderPage)}pdfjsLib.GlobalWorkerOptions.workerSrc=_pdf2.default,console.log(pdfjsLib.version,_pdf2.default),pdfjsLib.getDocument(url).promise.then(renderPages)}(pdf,canvas)},pdfjsLib=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(pdfjsLib),_pdf2=(obj=_pdf2)&&obj.__esModule?obj:{default:obj}})); +function(url,canvasContainer){function renderPage(page){var viewport=page.getViewport({scale:1}),canvas=document.createElement("canvas"),renderContext={canvasContext:canvas.getContext("2d"),viewport:viewport},widthScale=canvasContainer.clientWidth/viewport.width,heightScale=canvasContainer.clientHeight/viewport.height,scale=Math.min(widthScale,heightScale);canvas.width=viewport.width*scale,canvas.height=viewport.height*scale,canvasContainer.appendChild(canvas),console.log(canvasContainer,canvas,canvas.height),page.render(renderContext)}function renderPages(pdfDoc){for(var num=1;num<=pdfDoc.numPages;num++)pdfDoc.getPage(num).then(renderPage)}pdfjsLib.GlobalWorkerOptions.workerSrc=_pdf2.default,console.log(pdfjsLib.version,_pdf2.default),pdfjsLib.getDocument(url).promise.then(renderPages)}(pdfUrl,container)},pdfjsLib=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(pdfjsLib),_pdf2=(obj=_pdf2)&&obj.__esModule?obj:{default:obj}})); //# sourceMappingURL=pdfembed.min.js.map \ No newline at end of file diff --git a/amd/build/pdfembed.min.js.map b/amd/build/pdfembed.min.js.map index 6a4a7d79..6820217c 100644 --- a/amd/build/pdfembed.min.js.map +++ b/amd/build/pdfembed.min.js.map @@ -1 +1 @@ -{"version":3,"file":"pdfembed.min.js","sources":["../src/pdfembed.js"],"sourcesContent":["// This file is part of the mod_coursecertificate plugin for Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module provides functionality for embedding PDFs using pdf.js.\n *\n * @module mod_datalynx/pdfembed\n * @copyright 2023 David Bogner \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n// import 'mod_datalynx/pdf';\n\nimport * as pdfjsLib from 'mod_datalynx/pdf';\nimport pdfjsWorker from 'mod_datalynx/pdf.worker';\n\nfunction renderPDFfunction(url, canvasContainer, options) {\n\n var options = options || { scale: 1 };\n\n function renderPage(page) {\n var viewport = page.getViewport(options.scale);\n var canvas = document.createElement('canvas');\n var ctx = canvas.getContext('2d');\n var renderContext = {\n canvasContext: ctx,\n viewport: viewport\n };\n\n canvas.height = viewport.height;\n canvas.width = viewport.width;\n\n canvasContainer.appendChild(canvas);\n\n console.log(canvasContainer, canvas);\n\n page.render(renderContext);\n }\n\n function renderPages(pdfDoc) {\n for (var num = 1; num <= pdfDoc.numPages; num++)\n pdfDoc.getPage(num).then(renderPage);\n }\n\n pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;\n\n // eslint-disable-next-line no-console\n console.log(pdfjsLib.version, pdfjsWorker);\n\n pdfjsLib.getDocument(url).promise.then(renderPages);\n\n}\n\n// eslint-disable-next-line require-jsdoc\nexport function renderPDF() {\n\n const pdf = M.cfg.wwwroot + '/mod/datalynx/tests/turnen.pdf';\n const canvas = document.querySelector('#resourceobject').parentElement;\n\n // eslint-disable-next-line no-console\n console.log(pdfjsLib);\n\n renderPDFfunction(pdf, canvas);\n};"],"names":["pdf","M","cfg","wwwroot","canvas","document","querySelector","parentElement","console","log","pdfjsLib","url","canvasContainer","options","scale","renderPage","page","viewport","getViewport","createElement","renderContext","canvasContext","getContext","height","width","appendChild","render","renderPages","pdfDoc","num","numPages","getPage","then","GlobalWorkerOptions","workerSrc","pdfjsWorker","version","getDocument","promise","renderPDFfunction"],"mappings":"kfAmEUA,IAAMC,EAAEC,IAAIC,QAAU,iCACtBC,OAASC,SAASC,cAAc,mBAAmBC,cAGzDC,QAAQC,IAAIC;;;;;;;;SA5CWC,IAAKC,gBAAiBC,SAEzCA,QAAUA,SAAW,CAAEC,MAAO,YAEzBC,WAAWC,UACZC,SAAWD,KAAKE,YAAYL,QAAQC,OACpCV,OAASC,SAASc,cAAc,UAEhCC,cAAgB,CAChBC,cAFMjB,OAAOkB,WAAW,MAGxBL,SAAUA,UAGdb,OAAOmB,OAASN,SAASM,OACzBnB,OAAOoB,MAAQP,SAASO,MAExBZ,gBAAgBa,YAAYrB,QAE5BI,QAAQC,IAAIG,gBAAiBR,QAE7BY,KAAKU,OAAON,wBAGPO,YAAYC,YACZ,IAAIC,IAAM,EAAGA,KAAOD,OAAOE,SAAUD,MACtCD,OAAOG,QAAQF,KAAKG,KAAKjB,YAGjCL,SAASuB,oBAAoBC,UAAYC,cAGzC3B,QAAQC,IAAIC,SAAS0B,QAASD,eAE9BzB,SAAS2B,YAAY1B,KAAK2B,QAAQN,KAAKL,aAavCY,CAAkBvC,IAAKI"} \ No newline at end of file +{"version":3,"file":"pdfembed.min.js","sources":["../src/pdfembed.js"],"sourcesContent":["// This file is part of the mod_coursecertificate plugin for Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module provides functionality for embedding PDFs using pdf.js.\n *\n * @module mod_datalynx/pdfembed\n * @copyright 2023 David Bogner \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n// import 'mod_datalynx/pdf';\n\nimport * as pdfjsLib from 'mod_datalynx/pdf';\nimport pdfjsWorker from 'mod_datalynx/pdf.worker';\n\n\nfunction renderPDFfunction(url, canvasContainer) {\n\n function renderPage(page) {\n var viewport = page.getViewport({ scale: 1 });\n var canvas = document.createElement('canvas');\n var ctx = canvas.getContext('2d');\n var renderContext = {\n canvasContext: ctx,\n viewport: viewport\n };\n // Calculate the scaling factors to fit the container's width and height\n var widthScale = canvasContainer.clientWidth / viewport.width;\n var heightScale = canvasContainer.clientHeight / viewport.height;\n\n // Use the minimum scale to ensure that the entire page fits within the container\n var scale = Math.min(widthScale, heightScale);\n\n // Apply the scaling factor\n canvas.width = viewport.width * scale;\n canvas.height = viewport.height * scale;\n\n // canvas.height = canvasContainer.clientHeight;\n // canvas.width = canvasContainer.clientWidth;\n\n // canvas.height = 800;\n // canvas.width = 1200;\n\n canvasContainer.appendChild(canvas);\n\n // eslint-disable-next-line no-console\n console.log(canvasContainer, canvas, canvas.height);\n\n page.render(renderContext);\n }\n\n function renderPages(pdfDoc) {\n for (var num = 1; num <= pdfDoc.numPages; num++)\n pdfDoc.getPage(num).then(renderPage);\n }\n\n pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;\n\n // eslint-disable-next-line no-console\n console.log(pdfjsLib.version, pdfjsWorker);\n\n pdfjsLib.getDocument(url).promise.then(renderPages);\n\n}\n\n// eslint-disable-next-line require-jsdoc\nexport function renderPDF(pdfUrl, canvasContainerId) {\n\n // eslint-disable-next-line no-unused-vars\n const pdf = M.cfg.wwwroot + '/mod/datalynx/tests/turnen.pdf';\n const container = document.querySelector(`#${canvasContainerId}`);\n\n // eslint-disable-next-line no-console\n console.log(pdfjsLib);\n console.log(pdfUrl);\n console.log(container);\n\n renderPDFfunction(pdfUrl, container);\n}"],"names":["pdfUrl","canvasContainerId","M","cfg","wwwroot","container","document","querySelector","console","log","pdfjsLib","url","canvasContainer","renderPage","page","viewport","getViewport","scale","canvas","createElement","renderContext","canvasContext","getContext","widthScale","clientWidth","width","heightScale","clientHeight","height","Math","min","appendChild","render","renderPages","pdfDoc","num","numPages","getPage","then","GlobalWorkerOptions","workerSrc","pdfjsWorker","version","getDocument","promise","renderPDFfunction"],"mappings":"0eA8E0BA,OAAQC,mBAGlBC,EAAEC,IAAIC,cACZC,UAAYC,SAASC,yBAAkBN,oBAG7CO,QAAQC,IAAIC,UACZF,QAAQC,IAAIT,QACZQ,QAAQC,IAAIJ;;;;;;;;SA3DWM,IAAKC,0BAEnBC,WAAWC,UACZC,SAAWD,KAAKE,YAAY,CAAEC,MAAO,IACrCC,OAASZ,SAASa,cAAc,UAEhCC,cAAgB,CAChBC,cAFMH,OAAOI,WAAW,MAGxBP,SAAUA,UAGVQ,WAAaX,gBAAgBY,YAAcT,SAASU,MACpDC,YAAcd,gBAAgBe,aAAeZ,SAASa,OAGtDX,MAAQY,KAAKC,IAAIP,WAAYG,aAGjCR,OAAOO,MAAQV,SAASU,MAAQR,MAChCC,OAAOU,OAASb,SAASa,OAASX,MAQlCL,gBAAgBmB,YAAYb,QAG5BV,QAAQC,IAAIG,gBAAiBM,OAAQA,OAAOU,QAE5Cd,KAAKkB,OAAOZ,wBAGPa,YAAYC,YACZ,IAAIC,IAAM,EAAGA,KAAOD,OAAOE,SAAUD,MACtCD,OAAOG,QAAQF,KAAKG,KAAKzB,YAGjCH,SAAS6B,oBAAoBC,UAAYC,cAGzCjC,QAAQC,IAAIC,SAASgC,QAASD,eAE9B/B,SAASiC,YAAYhC,KAAKiC,QAAQN,KAAKL,aAgBvCY,CAAkB7C,OAAQK"} \ No newline at end of file diff --git a/amd/src/pdfembed.js b/amd/src/pdfembed.js index 10580131..7e32c848 100644 --- a/amd/src/pdfembed.js +++ b/amd/src/pdfembed.js @@ -25,25 +25,38 @@ import * as pdfjsLib from 'mod_datalynx/pdf'; import pdfjsWorker from 'mod_datalynx/pdf.worker'; -function renderPDFfunction(url, canvasContainer, options) { - var options = options || { scale: 1 }; +function renderPDFfunction(url, canvasContainer) { function renderPage(page) { - var viewport = page.getViewport(options.scale); + var viewport = page.getViewport({scale: 1}); var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var renderContext = { canvasContext: ctx, viewport: viewport }; + // Calculate the scaling factors to fit the container's width and height + var widthScale = canvasContainer.clientWidth / viewport.width; + var heightScale = canvasContainer.clientHeight / viewport.height; - canvas.height = viewport.height; - canvas.width = viewport.width; + // Use the minimum scale to ensure that the entire page fits within the container + var scale = Math.min(widthScale, heightScale); + + // Apply the scaling factor + canvas.width = viewport.width * scale; + canvas.height = viewport.height * scale; + + // canvas.height = canvasContainer.clientHeight; + // canvas.width = canvasContainer.clientWidth; + + // canvas.height = 800; + // canvas.width = 1200; canvasContainer.appendChild(canvas); - console.log(canvasContainer, canvas); + // eslint-disable-next-line no-console + console.log(canvasContainer, canvas, canvas.height); page.render(renderContext); } @@ -63,13 +76,16 @@ function renderPDFfunction(url, canvasContainer, options) { } // eslint-disable-next-line require-jsdoc -export function renderPDF() { +export function renderPDF(pdfUrl, canvasContainerId) { + // eslint-disable-next-line no-unused-vars const pdf = M.cfg.wwwroot + '/mod/datalynx/tests/turnen.pdf'; - const canvas = document.querySelector('#resourceobject').parentElement; + const container = document.querySelector(`#${canvasContainerId}`); // eslint-disable-next-line no-console console.log(pdfjsLib); + console.log(pdfUrl); + console.log(container); - renderPDFfunction(pdf, canvas); -}; \ No newline at end of file + renderPDFfunction(pdfUrl, container); +} \ No newline at end of file diff --git a/field/file/renderer.php b/field/file/renderer.php index f468b848..5e04c266 100644 --- a/field/file/renderer.php +++ b/field/file/renderer.php @@ -69,7 +69,7 @@ public function render_edit_mode(MoodleQuickForm &$mform, stdClass $entry, array /** */ - public function render_display_mode(stdClass $entry, array $params) { + public function render_display_mode(stdClass $entry, array $params): ?string { $field = $this->_field; $fieldid = $field->id(); $entryid = $entry->id; @@ -101,12 +101,10 @@ public function render_display_mode(stdClass $entry, array $params) { if (!$file->is_directory()) { $filename = $file->get_filename(); - $mimetype = $file->get_mimetype(); - $filenameinfo = pathinfo($filename); $path = "/{$field->df()->context->id}/mod_datalynx/content/$contentid"; // ToDo: Remove or implement altname. $altname = ""; - $strfiles[] = $this->display_file($file, $path, $altname, $params); + $strfiles[] = $this->display_file($file, $entryid, $path, $altname, $params); } } @@ -118,7 +116,13 @@ public function render_display_mode(stdClass $entry, array $params) { return implode("
\n", $strfiles); } - public function render_search_mode(MoodleQuickForm &$mform, $i = 0, $value = '') { + /** + * @param MoodleQuickForm $mform + * @param int $i + * @param string $value + * @return array + */ + public function render_search_mode(MoodleQuickForm &$mform, $i = 0, $value = ''): array { $fieldid = $this->_field->id(); $fieldname = "f_{$i}_$fieldid"; @@ -143,19 +147,27 @@ public function render_search_mode(MoodleQuickForm &$mform, $i = 0, $value = '') } /** + * Render file html. + * + * @param stored_file $file + * @param int $entryid + * @param string $path + * @param string $altname + * @param array|null $params + * @return moodle_url|string */ - protected function display_file($file, string $path, string $altname = '', ?array $params = null) { - global $PAGE; - $PAGE->requires->js_call_amd('mod_datalynx/pdfembed', 'renderPDF', ['http://localhost/401_moodle/pluginfile.php/14444/mod_resource/content/1/%28SDAW%29%20Search%20on%20Commons%20Research%20Report%20%28June%202020%29.pdf', 'maincontent']); - + protected function display_file(stored_file $file, int $entryid, string $path, string $altname = '', ?array $params = null) { + $field = $this->_field; + $fieldid = $field->id(); + $fieldname = "field_{$fieldid}_{$entryid}"; $filename = $file->get_filename(); $mimetype = $file->get_mimetype(); $pluginfileurl = '/pluginfile.php'; if ($mimetype === 'application/pdf') { - // PDF document + // PDF document. $moodleurl = moodle_url::make_file_url($pluginfileurl, "$path/$filename"); - return $this->embed_pdf($moodleurl->out(), $filename, "Click"); + return $this->embed_pdf($moodleurl->out(), $fieldname); } if (!empty($params['url'])) { @@ -182,32 +194,30 @@ protected function display_file($file, string $path, string $altname = '', ?arra /** * Returns general link or pdf embedding html. * @param string $fullurl - * @param string $title - * @param string $clicktoopen + * @param string $fieldname * @return string html */ - protected function embed_pdf(string $fullurl): string { + protected function embed_pdf(string $fullurl, string $fieldname): string { global $PAGE; - $html = << - - - - -EOT; - /** - $html = '
- -

Unable to display PDF file. Download instead.

-'; - **/ + $PAGE->requires->js_call_amd('mod_datalynx/pdfembed', 'renderPDF', + [$fullurl, $fieldname]); + return '
+
+ '; // the size is hardcoded in the boject obove intentionally because it is adjusted by the following function on-the-fly - $PAGE->requires->js_call_amd('mod_datalynx/maximiseembed', 'initMaximisedEmbed', ['resourceembed']); - return $html; + // $PAGE->requires->js_call_amd('mod_datalynx/maximiseembed', 'initMaximisedEmbed', ['resourceembed']); } /** + * Render a link. + * @param $file + * @param $path + * @param $altname + * @param $params + * @return string */ protected function display_link($file, $path, $altname, $params = null): string { global $OUTPUT;