Skip to content

Commit 13369cf

Browse files
authored
feat(PdfReader): add Document properties Function (#751)
* refactor: 更新 worker 路径 * feat: 增加 document 属性弹窗 * feat: 增加关闭按钮逻辑 * refactor: 增加关闭文档属性弹窗脚本 * chore: bump version 10.0.7
1 parent 2010373 commit 13369cf

6 files changed

Lines changed: 271 additions & 8 deletions

File tree

src/components/BootstrapBlazor.PdfReader/BootstrapBlazor.PdfReader.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.0.6</Version>
4+
<Version>10.0.7</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/components/BootstrapBlazor.PdfReader/Locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"Print": "Print",
1313
"TwoPageView": "Two pages on view",
1414
"PresentationMode": "Presentation mode",
15-
"DocumentProperty": "Document properties"
15+
"DocumentProperty": "Document properties",
16+
"CloseButtonText": "Close"
1617
}
1718
}

src/components/BootstrapBlazor.PdfReader/Locales/zh.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"Print": "打印",
1313
"TwoPageView": "双页视图",
1414
"PresentationMode": "演示模式",
15-
"DocumentProperty": "文档属性"
15+
"DocumentProperty": "文档属性",
16+
"CloseButtonText": "关闭"
1617
}
1718
}

src/components/BootstrapBlazor.PdfReader/PdfReader.razor

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@
7474
}
7575
@if (ShowTwoPagesOneView || ShowPresentationMode)
7676
{
77-
<Divider></Divider>
77+
<div class="divider">
78+
<div class="divider-mask"></div>
79+
</div>
7880
}
7981
<div class="dropdown-item dropdown-item-doc">
8082
<i class="@_dropdownItemDefaultIcon"></i>
@@ -96,4 +98,80 @@
9698
</div>
9799
</div>
98100
</div>
101+
<div class="bb-view-pdf-info">
102+
<div class="bb-view-pdf-backdrop"></div>
103+
<div class="bb-view-pdf-dialog">
104+
<div class="bb-view-pdf-dialog-title mb-3">Document properties</div>
105+
<div class="bb-view-pdf-dialog-item">
106+
<div class="bb-view-pdf-dialog-label">File name:</div>
107+
<div class="bb-view-pdf-dialog-filename"></div>
108+
</div>
109+
<div class="bb-view-pdf-dialog-item">
110+
<div class="bb-view-pdf-dialog-label">File size:</div>
111+
<div class="bb-view-pdf-dialog-filesize"></div>
112+
</div>
113+
<div class="divider">
114+
<div class="divider-mask"></div>
115+
</div>
116+
<div class="bb-view-pdf-dialog-item">
117+
<div class="bb-view-pdf-dialog-label">Title:</div>
118+
<div class="bb-view-pdf-dialog-title"></div>
119+
</div>
120+
<div class="bb-view-pdf-dialog-item">
121+
<div class="bb-view-pdf-dialog-label">Author:</div>
122+
<div class="bb-view-pdf-dialog-author"></div>
123+
</div>
124+
<div class="bb-view-pdf-dialog-item">
125+
<div class="bb-view-pdf-dialog-label">Subject:</div>
126+
<div class="bb-view-pdf-dialog-subject"></div>
127+
</div>
128+
<div class="bb-view-pdf-dialog-item">
129+
<div class="bb-view-pdf-dialog-label">Keywords:</div>
130+
<div class="bb-view-pdf-dialog-keywords"></div>
131+
</div>
132+
<div class="bb-view-pdf-dialog-item">
133+
<div class="bb-view-pdf-dialog-label">Created:</div>
134+
<div class="bb-view-pdf-dialog-created"></div>
135+
</div>
136+
<div class="bb-view-pdf-dialog-item">
137+
<div class="bb-view-pdf-dialog-label">Modified:</div>
138+
<div class="bb-view-pdf-dialog-modified"></div>
139+
</div>
140+
<div class="bb-view-pdf-dialog-item">
141+
<div class="bb-view-pdf-dialog-label">Application:</div>
142+
<div class="bb-view-pdf-dialog-application"></div>
143+
</div>
144+
<div class="divider">
145+
<div class="divider-mask"></div>
146+
</div>
147+
<div class="bb-view-pdf-dialog-item">
148+
<div class="bb-view-pdf-dialog-label">PDF producer:</div>
149+
<div class="bb-view-pdf-dialog-producer"></div>
150+
</div>
151+
<div class="bb-view-pdf-dialog-item">
152+
<div class="bb-view-pdf-dialog-label">PDF version:</div>
153+
<div class="bb-view-pdf-dialog-version"></div>
154+
</div>
155+
<div class="bb-view-pdf-dialog-item">
156+
<div class="bb-view-pdf-dialog-label">Page count:</div>
157+
<div class="bb-view-pdf-dialog-count"></div>
158+
</div>
159+
<div class="bb-view-pdf-dialog-item">
160+
<div class="bb-view-pdf-dialog-label">Page size:</div>
161+
<div class="bb-view-pdf-dialog-size"></div>
162+
</div>
163+
<div class="divider">
164+
<div class="divider-mask"></div>
165+
</div>
166+
<div class="bb-view-pdf-dialog-item">
167+
<div class="bb-view-pdf-dialog-label">Fast web view:</div>
168+
<div class="bb-view-pdf-dialog-webview">No</div>
169+
</div>
170+
<div class="bb-view-pdf-dialog-close">
171+
<button type="button" class="btn btn-primary btn-close-doc">
172+
<span>@Localizer["CloseButtonText"]</span>
173+
</button>
174+
</div>
175+
</div>
176+
</div>
99177
</div>

src/components/BootstrapBlazor.PdfReader/PdfReader.razor.css

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,56 @@
209209
background-color: #000;
210210
inset: 0;
211211
}
212+
213+
.bb-view-pdf-info {
214+
position: absolute;
215+
inset: 0;
216+
display: flex;
217+
align-items: center;
218+
justify-content: center;
219+
z-index: 5;
220+
}
221+
222+
.bb-view-pdf-info:not(.show) {
223+
display: none;
224+
}
225+
226+
.bb-view-pdf-backdrop {
227+
position: absolute;
228+
inset: 0;
229+
background-color: #000;
230+
opacity: 0.6;
231+
z-index: 1;
232+
}
233+
234+
.bb-view-pdf-dialog {
235+
background-color: #fff;
236+
padding: 1rem;
237+
z-index: 5;
238+
border-radius: var(--bs-border-radius);
239+
}
240+
241+
.bb-view-pdf-dialog-item {
242+
display: flex;
243+
flex-wrap: nowrap;
244+
width: 344px;
245+
}
246+
247+
.bb-view-pdf-dialog-item:not(:last-child) {
248+
margin-block-start: .5rem;
249+
}
250+
251+
.bb-view-pdf-dialog-label {
252+
width: 108px;
253+
white-space: nowrap;
254+
overflow: hidden;
255+
}
256+
257+
.bb-view-pdf-dialog-close {
258+
text-align: right;
259+
padding-block-start: 1rem;
260+
}
261+
262+
.bb-view-pdf-dialog-close .btn {
263+
--bs-btn-padding-x: 1rem;
264+
}

src/components/BootstrapBlazor.PdfReader/PdfReader.razor.js

Lines changed: 134 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Data from '../BootstrapBlazor/modules/data.js';
55
import EventHandler from '../BootstrapBlazor/modules/event-handler.js';
66

77
if (pdfjsLib != null) {
8-
pdfjsLib.GlobalWorkerOptions.workerSrc = './pdf.worker.min.mjs';
8+
pdfjsLib.GlobalWorkerOptions.workerSrc = '/_content/BootstrapBlazor.PdfReader/lib/pdf.worker.min.mjs';
99
}
1010

1111
export async function init(id, invoke, options) {
@@ -101,9 +101,120 @@ const loadPdf = async (el, invoke, options) => {
101101
const pdfDocument = await loadingTask.promise;
102102
pdfViewer.setDocument(pdfDocument);
103103

104+
pdfDocument.getMetadata().then(metadata => {
105+
loadMetadata(el, pdfViewer, metadata);
106+
});
107+
104108
return pdfViewer;
105109
}
106110

111+
const loadMetadata = (el, pdfViewer, metadata) => {
112+
console.log(metadata);
113+
114+
const filename = el.querySelector('.bb-view-pdf-dialog-filename');
115+
const docTitle = el.querySelector('.bb-view-subject');
116+
filename.textContent = docTitle.textContent;
117+
118+
const filesize = el.querySelector('.bb-view-pdf-dialog-filesize');
119+
filesize.textContent = getFilesize(metadata);
120+
121+
const title = el.querySelector('.bb-view-pdf-dialog-title');
122+
const author = el.querySelector('.bb-view-pdf-dialog-author');
123+
const subject = el.querySelector('.bb-view-pdf-dialog-subject');
124+
const keywords = el.querySelector('.bb-view-pdf-dialog-keywords');
125+
const created = el.querySelector('.bb-view-pdf-dialog-created');
126+
created.textContent = parsePdfDate(metadata.info.CreationDate)?.toLocaleString();
127+
128+
const modified = el.querySelector('.bb-view-pdf-dialog-modified');
129+
130+
const application = el.querySelector('.bb-view-pdf-dialog-application');
131+
application.textContent = metadata.info.Creator;
132+
133+
const producer = el.querySelector('.bb-view-pdf-dialog-producer');
134+
producer.textContent = metadata.info.Producer;
135+
136+
const version = el.querySelector('.bb-view-pdf-dialog-version');
137+
version.textContent = metadata.info.PDFFormatVersion;
138+
139+
const count = el.querySelector('.bb-view-pdf-dialog-count');
140+
count.textContent = pdfViewer.pagesCount;
141+
142+
const size = el.querySelector('.bb-view-pdf-dialog-size');
143+
pdfViewer.pdfDocument.getPage(pdfViewer.currentPageNumber).then(page => {
144+
const viewport = page.getViewport({ scale: 1 });
145+
size.textContent = `${(viewport.width / 72).toFixed(2)} * ${(viewport.height / 72).toFixed(2)} in (portrait)`;
146+
});
147+
148+
const webview = el.querySelector('.bb-view-pdf-dialog-webview');
149+
}
150+
151+
function parsePdfDate(pdfDateString) {
152+
if (!pdfDateString || typeof pdfDateString !== 'string') {
153+
return null;
154+
}
155+
156+
let dateStr = pdfDateString.startsWith('D:') ? pdfDateString.substring(2) : pdfDateString;
157+
158+
const pdfDateRegex = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})([Zz+-])(\d{2})'?(\d{2})'?$/;
159+
const match = dateStr.match(pdfDateRegex);
160+
161+
if (!match) {
162+
return null;
163+
}
164+
165+
const [, year, month, day, hours, minutes, seconds, timezoneSign, timezoneHours, timezoneMinutes] = match;
166+
167+
const date = new Date(
168+
parseInt(year),
169+
parseInt(month) - 1,
170+
parseInt(day),
171+
parseInt(hours),
172+
parseInt(minutes),
173+
parseInt(seconds)
174+
);
175+
176+
if (timezoneSign === 'Z' || timezoneSign === 'z') {
177+
const utcTime = Date.UTC(
178+
parseInt(year),
179+
parseInt(month) - 1,
180+
parseInt(day),
181+
parseInt(hours),
182+
parseInt(minutes),
183+
parseInt(seconds)
184+
);
185+
date.setTime(utcTime);
186+
}
187+
else if (timezoneSign === '+' || timezoneSign === '-') {
188+
const offsetHours = parseInt(timezoneHours);
189+
const offsetMinutes = parseInt(timezoneMinutes || 0);
190+
const totalOffsetMinutes = offsetHours * 60 + offsetMinutes;
191+
192+
if (timezoneSign === '+') {
193+
date.setMinutes(date.getMinutes() - totalOffsetMinutes);
194+
}
195+
else {
196+
date.setMinutes(date.getMinutes() + totalOffsetMinutes);
197+
}
198+
}
199+
return date;
200+
}
201+
202+
const getFilesize = metadata => {
203+
const length = metadata.contentLength;
204+
if (length < 1024) {
205+
return `${Math.round(length)}B`;
206+
}
207+
else if (length < 1024 * 1024) {
208+
return `${Math.round(length / 1024)}KB`;
209+
}
210+
else if (length < 1024 * 1024 * 1024) {
211+
return `${length / 1024 / 1024}MB`;
212+
}
213+
else if (length < 1024 * 1024 * 1024 * 1024) {
214+
return `${length / 1024 / 1024 / 1024}GB`;
215+
}
216+
}
217+
107218
const setObserver = el => {
108219
const observer = new ResizeObserver(entries => {
109220
relayoutToolbar(el);
@@ -325,6 +436,20 @@ const addToolbarEventHandlers = (el, pdfViewer, invoke, options) => {
325436
// el.requestFullscreen();
326437
//}
327438
});
439+
EventHandler.on(toolbar, "click", ".dropdown-item-doc", e => {
440+
const dialog = el.querySelector(".bb-view-pdf-info");
441+
if (dialog) {
442+
dialog.classList.add("show");
443+
}
444+
});
445+
446+
const closeButton = el.querySelector(".btn-close-doc");
447+
EventHandler.on(closeButton, 'click', e => {
448+
const dialog = el.querySelector(".bb-view-pdf-info");
449+
if (dialog) {
450+
dialog.classList.remove("show");
451+
}
452+
});
328453
}
329454

330455
const resetToolbarView = (el, pdfViewer) => {
@@ -402,7 +527,7 @@ const updateScaleValue = (el, value) => {
402527
const scaleEl = el.querySelector(".bb-view-scale-input");
403528

404529
const scale = value * 100;
405-
scaleEl.value = `${Math.round(scale, 0)}%`;
530+
scaleEl.value = `${Math.round(scale)}%`;
406531

407532
if (scale === 25) {
408533
minus.classList.add("disabled");
@@ -422,7 +547,7 @@ const updateScale = (pdfViewer, button, rate) => {
422547
}
423548

424549
const scale = pdfViewer.currentScale;
425-
const current = Math.round(parseFloat(scale * 100), 0);
550+
const current = Math.round(parseFloat(scale * 100));
426551
const step = [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500];
427552
const findValues = step.filter(s => rate > 0 ? current < s : current > s);
428553
if (findValues.length === 0) {
@@ -462,7 +587,7 @@ const printPdf = url => {
462587
}
463588

464589
iframe = document.createElement("iframe");
465-
iframe.classList = "bb-view-print-iframe";
590+
iframe.classList.add("bb-view-print-iframe");
466591
iframe.style.position = "fixed";
467592
iframe.style.right = "100%";
468593
iframe.style.bottom = "100%";
@@ -506,5 +631,10 @@ export function dispose(id) {
506631
if (iframe) {
507632
iframe.remove();
508633
}
634+
635+
const closeButton = el.querySelector(".btn-close-doc");
636+
if (closeButton) {
637+
EventHandler.off(closeButton, "click");
638+
}
509639
}
510640
}

0 commit comments

Comments
 (0)