fix: improve pdf rendering and html

This commit is contained in:
tdurieux
2026-08-06 14:35:21 -07:00
parent e54b78c7e6
commit f0fdd9250b
202 changed files with 999 additions and 2051 deletions
+2 -2
View File
@@ -26,9 +26,9 @@ const coreJsFiles = [
];
const vendorJsFiles = [
"public/script/external/pdf.compat.js",
"public/script/external/pdf.js",
"public/script/ng-pdfviewer.min.js",
"public/script/pdf-viewer.js",
"public/script/html-doc.js",
"public/script/external/katex.min.js",
"public/script/external/katex-auto-render.min.js",
"public/script/external/marked-katex-extension.umd.min.js",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"core.min.js": "core.6332b3c288.min.js",
"vendor.min.js": "vendor.c42de05f19.min.js",
"vendor.min.js": "vendor.2c4b28d9af.min.js",
"mermaid.min.js": "mermaid.f848a72d16.min.js",
"all.min.css": "all.be6d7c2c8b.min.css"
"all.min.css": "all.b704319d9c.min.css"
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+115
View File
@@ -1329,6 +1329,11 @@ a:hover {
background: var(--hover-bg-color);
color: var(--color);
}
/* An action that is currently on, e.g. JS execution enabled for this file. */
.status-bar-actions .btn.btn-active {
border-color: currentColor;
font-weight: 600;
}
.paths {
flex: 1 1 auto;
@@ -1372,6 +1377,116 @@ a:hover {
padding: 4px;
}
/* Rendered PDF: a toolbar above a scrolling column of pages. */
.pdf-viewer {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
background-color: var(--main-bg-color);
}
.pdf-toolbar {
display: flex;
align-items: center;
gap: 4px;
flex: 0 0 auto;
padding: 4px 8px;
border-bottom: 1px solid var(--border-color, rgba(0, 0, 0, 0.12));
}
.pdf-toolbar-group {
display: inline-flex;
align-items: center;
gap: 4px;
}
.pdf-toolbar-right {
margin-left: auto;
}
.pdf-toolbar-btn {
border: 0;
background: none;
color: inherit;
padding: 4px 8px;
border-radius: 4px;
font-size: 13px;
line-height: 1.2;
cursor: pointer;
}
.pdf-toolbar-btn:hover:not(:disabled) {
background-color: rgba(128, 128, 128, 0.18);
}
.pdf-toolbar-btn:disabled {
opacity: 0.4;
cursor: default;
}
.pdf-toolbar-zoom {
min-width: 52px;
font-variant-numeric: tabular-nums;
}
.pdf-toolbar-page {
width: 3.5em;
text-align: right;
padding: 2px 4px;
font-size: 13px;
color: inherit;
background: none;
border: 1px solid var(--border-color, rgba(0, 0, 0, 0.2));
border-radius: 4px;
}
.pdf-toolbar-count {
font-size: 13px;
opacity: 0.75;
font-variant-numeric: tabular-nums;
}
.pdf-pages {
flex: 1 1 auto;
min-height: 0;
overflow: auto;
padding: 8px 0;
}
.pdf-viewer-page {
/* Sized to the page's aspect ratio while empty so the scrollbar is honest
and only on-screen pages get rasterised; the canvas takes over once the
page renders. */
margin: 0 auto 12px;
}
.pdf-viewer-page canvas {
display: block;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.pdf-viewer-error {
padding: 24px;
text-align: center;
font-weight: bold;
}
/* Rendered HTML document. Always light: the document brings its own styling
and dark mode can't reach inside a cross-origin frame to adapt it. */
.html-doc {
display: block;
height: 100%;
}
.html-doc-frame {
display: block;
width: 100%;
height: 100%;
border: 0;
background-color: #fff;
}
.file-error {
font-weight: bold;
font-size: 50px;
+1 -1
View File
@@ -105,7 +105,7 @@
</script>
<script src="/script/__VENDOR_JS__" defer onload="
ace.config.set('basePath', '/script/external/ace/');
PDFJS.workerSrc = '/script/external/pdf.worker.js';
pdfjsLib.GlobalWorkerOptions.workerSrc = '/script/external/pdf.worker.js';
angular.bootstrap(document, ['anonymous-github']);
"></script>
<script>
+24
View File
@@ -91,6 +91,30 @@
aria-label="Edit"
><i class="far fa-edit"></i><span class="d-none d-md-inline"> Edit</span></a
>
<button
ng-if="type == 'html-doc' && !showSource"
ng-click="toggleAllowScripts()"
class="btn btn-sm"
ng-class="{'btn-active': allowScripts}"
aria-label="Allow this document to run JavaScript"
title="Scripts in this file are blocked by default. Enable them only if you trust the repository — the document stays isolated from your session either way."
>
<i class="fab fa-js"></i><span class="d-none d-md-inline">
{{ allowScripts ? "JS on" : "JS off" }}</span
>
</button>
<button
ng-if="type == 'html-doc'"
ng-click="toggleSource()"
class="btn btn-sm"
aria-label="Toggle between the rendered document and its source"
title="Toggle between the rendered document and its source"
>
<i class="fas" ng-class="showSource ? 'fa-eye' : 'fa-code'"></i
><span class="d-none d-md-inline">
{{ showSource ? "Rendered" : "Source" }}</span
>
</button>
<a
ng-show="content != null"
ng-href="{{url}}"
+12 -4
View File
@@ -1,11 +1,19 @@
<div ng-if="type == 'text'" ng-model="content" ui-ace="aceOption"></div>
<div ng-if="type == 'html'" ng-bind-html="content" class="file-content markdown-body"></div>
<div ng-if="type == 'code' && content != null" ui-ace="aceOption" ng-model="content"></div>
<html-doc
ng-if="type == 'html-doc' && !showSource && content != null"
content="content"
base-url="{{fileBaseUrl}}"
allow-scripts="allowScripts"
></html-doc>
<div
ng-if="(type == 'code' || (type == 'html-doc' && showSource)) && content != null"
ui-ace="aceOption"
ng-model="content"
></div>
<img ng-if="type == 'image'" class="image-content" ng-src="{{url}}"></img>
<iframe class="h-100 overflow-auto w-100 b-0" ng-if="type == 'media'" ng-src="{{url}}"></iframe>
<div class="h-100 overflow-auto" ng-if="type == 'pdf'">
<pdfviewer class="h-100 overflow-auto" src="{{url}}" id="viewer"></pdfviewer>
</div>
<pdfviewer ng-if="type == 'pdf'" src="{{url}}"></pdfviewer>
<div ng-if="type == 'audio'"><audio controls="controls"><source ng-src="{{url}}" /></audio></div>
<div ng-if="type == 'IPython'"><notebook file="url"></notebook></div>
<div ng-if="type == 'rate_limited'" class="file-error container d-flex h-100">
+43 -3
View File
@@ -4,6 +4,7 @@ angular
"ngSanitize",
"ui.ace",
"ngPDFViewer",
"htmlDoc",
"pascalprecht.translate",
"admin",
])
@@ -2559,8 +2560,7 @@ angular
"$routeParams",
"$sce",
"$q",
"PDFViewerService",
function ($scope, $http, $location, $routeParams, $sce, $q, PDFViewerService) {
function ($scope, $http, $location, $routeParams, $sce, $q) {
$scope.files = [];
$scope.isMac = /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent);
$scope.fileSearchQuery = "";
@@ -2843,6 +2843,18 @@ angular
);
}
// Defined as methods rather than inline `showSource = !showSource` in the
// template: the toolbar and the file view sit in different child scopes,
// so an inline assignment would shadow the value on one of them instead
// of updating the controller's.
$scope.toggleSource = function () {
$scope.showSource = !$scope.showSource;
};
$scope.toggleAllowScripts = function () {
$scope.allowScripts = !$scope.allowScripts;
};
function getMode(extension) {
if (extensionModes[extension]) {
return extensionModes[extension];
@@ -2852,9 +2864,14 @@ angular
function getType(extension) {
if (extension == "pdf") {
$scope.instance = PDFViewerService.Instance("viewer");
return "pdf";
}
// Rendered as a document in a sandboxed frame rather than as source —
// see html-doc.js. "html" is reserved for markup we generated
// ourselves (rendered markdown/org) and inject directly.
if (extension == "html" || extension == "htm") {
return "html-doc";
}
if (extension == "md") {
return "md";
}
@@ -2975,6 +2992,20 @@ angular
$scope.url = `/api/repo/${$scope.repoId}/file/${encodePathForUrl(
$scope.filePath
)}?v=${fileVersion}`;
// Directory the file lives in, used as the <base> for a rendered HTML
// document so its relative images/stylesheets still resolve.
const dirPath = $scope.filePath.substring(
0,
$scope.filePath.lastIndexOf("/") + 1
);
$scope.fileBaseUrl = `/api/repo/${$scope.repoId}/file/${
dirPath ? encodePathForUrl(dirPath) : ""
}`;
$scope.showSource = false;
// Scripts in a repository's HTML are opt-in, per file — see
// html-doc.js. Reset on navigation so trust never carries over from
// one file to the next.
$scope.allowScripts = false;
let extension = $scope.filePath.toLowerCase();
const extensionIndex = extension.lastIndexOf(".");
@@ -3112,6 +3143,15 @@ angular
}
$scope.type = getType(extension);
if ($scope.type == "pdf") {
// The viewer streams the file itself from $scope.url, so fetching
// the bytes again here only to hold them as a JS string wastes a
// request and a lot of memory on a large report. Content stays
// non-null so the Raw/Download actions remain available.
$scope.content = "pdf";
return;
}
getContent($scope.filePath, $scope.file);
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEáCNS2-H
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSEá ETen-B5-H` ^
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
àRCopyright 1990-2009 Adobe Systems Incorporated.
All rights reserved.
See ./LICENSE!!º]aX!!]`21> p z$]"Rd-Uƒ7*4„%+ „Z „{/%…<9K…b1]†." ‰`]‡,"]ˆ
"]ˆh"]‰F"]Š$"]"]`"]Œ>"]"]z"]ŽX"]6"]"]r"]P"]."]“ "]“j"]”H"]•&"]"]b"]—@"]˜"]˜|"]™Z"]š8"]"]t"]œR"]0"]ž"]žl"]ŸJ"] ("]¡"]¡d"]¢B"]£ "X£~']¤W"]¥5"]¦"]¦q"]§O"]¨-"]© "]©i"]ªG"]«%"]¬"]¬a"]­?"]®"]®{"]¯Y"]°7"]±"]±s"]²Q"]³/"]´ "]´k"]µI"]¶'"]·"]·c"]¸A"]¹"]¹}"]º["]»9
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More