mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: update pdf link processing
This commit is contained in:
1 file changed
+23
-10
@@ -3,7 +3,6 @@
|
|||||||
/* eslint-disable regexp/no-useless-non-capturing-group */
|
/* eslint-disable regexp/no-useless-non-capturing-group */
|
||||||
/* eslint-disable regexp/optimal-quantifier-concatenation */
|
/* eslint-disable regexp/optimal-quantifier-concatenation */
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import type MarkdownIt from 'markdown-it';
|
import type MarkdownIt from 'markdown-it';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
@@ -77,13 +76,22 @@ function resourceUrl(service: string, src: string, url: string) {
|
|||||||
if (service === 'vimeo') return `https://player.vimeo.com/video/${src}`;
|
if (service === 'vimeo') return `https://player.vimeo.com/video/${src}`;
|
||||||
if (service === 'vine') return `https://vine.co/v/${src}/embed/simple`;
|
if (service === 'vine') return `https://vine.co/v/${src}/embed/simple`;
|
||||||
if (service === 'prezi') {
|
if (service === 'prezi') {
|
||||||
return `https://prezi.com/embed/${src}/?bgcolor=ffffff&lock_to_path=0&autoplay=0&autohide_ctrls=0&`
|
return `https://prezi.com/embed/${src}/?bgcolor=ffffff&lock_to_path=0&autoplay=0&autohide_ctrls=0&`
|
||||||
+ 'landing_data=bHVZZmNaNDBIWnNjdEVENDRhZDFNZGNIUE43MHdLNWpsdFJLb2ZHanI5N1lQVHkxSHFxazZ0UUNCRHloSXZROHh3PT0&'
|
+ 'landing_data=bHVZZmNaNDBIWnNjdEVENDRhZDFNZGNIUE43MHdLNWpsdFJLb2ZHanI5N1lQVHkxSHFxazZ0UUNCRHloSXZROHh3PT0&'
|
||||||
+ 'landing_sign=1kD6c0N6aYpMUS0wxnQjxzSqZlEB8qNFdxtdjYhwSuI';
|
+ 'landing_sign=1kD6c0N6aYpMUS0wxnQjxzSqZlEB8qNFdxtdjYhwSuI';
|
||||||
}
|
}
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pdfUrlKind(src: string) {
|
||||||
|
const normalizedSrc = src.replace(/\s/g, '').replace(/\\/g, '/');
|
||||||
|
if (/^data:application\/pdf(?:;[^,]*)?,/i.test(normalizedSrc)) return 'data';
|
||||||
|
if (/^file:\/\//i.test(normalizedSrc)) return 'local';
|
||||||
|
if (/^https?:\/\//i.test(normalizedSrc)) return 'external';
|
||||||
|
if (normalizedSrc.startsWith('//') || /^[a-z][a-z\d+.-]*:/i.test(normalizedSrc)) return 'invalid';
|
||||||
|
return 'local';
|
||||||
|
}
|
||||||
|
|
||||||
declare module 'hydrooj' {
|
declare module 'hydrooj' {
|
||||||
interface ModuleInterfaces {
|
interface ModuleInterfaces {
|
||||||
richmedia: {
|
richmedia: {
|
||||||
@@ -95,21 +103,26 @@ declare module 'hydrooj' {
|
|||||||
export function Media(md: MarkdownIt, { pdfToolbar = false }: { pdfToolbar?: boolean } = {}) {
|
export function Media(md: MarkdownIt, { pdfToolbar = false }: { pdfToolbar?: boolean } = {}) {
|
||||||
const supported = ['youtube', 'vimeo', 'vine', 'prezi', 'bilibili', 'youku', 'msoffice'];
|
const supported = ['youtube', 'vimeo', 'vine', 'prezi', 'bilibili', 'youku', 'msoffice'];
|
||||||
md.renderer.rules.video = function tokenizeReturn(tokens, idx) {
|
md.renderer.rules.video = function tokenizeReturn(tokens, idx) {
|
||||||
let src = md.utils.escapeHtml(tokens[idx].attrGet('src'));
|
const src = tokens[idx].attrGet('src');
|
||||||
const service = tokens[idx].attrGet('service').replace(/[^A-Z0-9]/gi, '').toLowerCase();
|
const service = tokens[idx].attrGet('service').replace(/[^A-Z0-9]/gi, '').toLowerCase();
|
||||||
if (Hydro?.module?.richmedia?.[service]) {
|
if (Hydro?.module?.richmedia?.[service]) {
|
||||||
const result = Hydro?.module?.richmedia[service].get(service, src, md);
|
const result = Hydro?.module?.richmedia[service].get(service, src, md);
|
||||||
if (result) return result;
|
if (result) return result;
|
||||||
}
|
}
|
||||||
if (service === 'pdf') {
|
if (service === 'pdf') {
|
||||||
if (['file://', './', '../'].some((i) => src.startsWith(i)) || (src[1] === '/' && src[2] !== '/')) src += src.includes('?') ? '&noDisposition=1' : '?noDisposition=1';
|
const kind = pdfUrlKind(src);
|
||||||
// A response with has content-disposition header causes the browser to download the file automatically.
|
// A response with has content-disposition header causes the browser to download the file automatically.
|
||||||
// As we cannot control response header from external sites, we block embedding external PDFs.
|
// As we cannot control response header from external sites, we block embedding external PDFs.
|
||||||
else return `<p>Embedding an external PDF is no longer supported.</p> <a href="${_.escape(src)}">Download</a>`;
|
if (kind === 'external') return `<p>Embedding an external PDF is no longer supported.</p> <a href="${md.utils.escapeHtml(src)}">Download</a>`;
|
||||||
|
if (kind === 'invalid') return '<p>Embedding this PDF URL is not supported.</p>';
|
||||||
|
const fragmentPos = src.indexOf('#');
|
||||||
|
const pdfUrl = fragmentPos === -1 ? src : src.slice(0, fragmentPos);
|
||||||
|
const fragment = fragmentPos === -1 ? '' : src.slice(fragmentPos);
|
||||||
|
const pdfSrc = kind === 'data' ? src : `${pdfUrl}${pdfUrl.includes('?') ? '&' : '?'}noDisposition=1${fragment}`;
|
||||||
return `\
|
return `\
|
||||||
<object classid="clsid:${uuid().toUpperCase()}">
|
<object classid="clsid:${uuid().toUpperCase()}">
|
||||||
<param name="SRC" value="${src}">
|
<param name="SRC" value="${md.utils.escapeHtml(pdfSrc)}">
|
||||||
<embed type="application/pdf" width="100%" style="min-height:100vh;border:none;" fullscreen="yes" src="${src}#toolbar=${pdfToolbar ? '0' : '1'}&navpanes=0&view=FitH">
|
<embed type="application/pdf" width="100%" style="min-height:100vh;border:none;" fullscreen="yes" src="${md.utils.escapeHtml(`${pdfSrc}#toolbar=${pdfToolbar ? '0' : '1'}&navpanes=0&view=FitH`)}">
|
||||||
<noembed></noembed>
|
<noembed></noembed>
|
||||||
</embed>
|
</embed>
|
||||||
</object>`;
|
</object>`;
|
||||||
@@ -117,7 +130,7 @@ export function Media(md: MarkdownIt, { pdfToolbar = false }: { pdfToolbar?: boo
|
|||||||
if (['url', 'video'].includes(service)) {
|
if (['url', 'video'].includes(service)) {
|
||||||
return `\
|
return `\
|
||||||
<video width="100%" controls>
|
<video width="100%" controls>
|
||||||
<source src="${src}" type="${src.endsWith('ogg') ? 'video/ogg' : 'video/mp4'}">
|
<source src="${md.utils.escapeHtml(src)}" type="${src.endsWith('ogg') ? 'video/ogg' : 'video/mp4'}">
|
||||||
Your browser doesn't support video tag.
|
Your browser doesn't support video tag.
|
||||||
</video>`;
|
</video>`;
|
||||||
}
|
}
|
||||||
@@ -125,7 +138,7 @@ export function Media(md: MarkdownIt, { pdfToolbar = false }: { pdfToolbar?: boo
|
|||||||
return `\
|
return `\
|
||||||
<iframe class="embed-responsive-item ${service}-player" type="text/html" \
|
<iframe class="embed-responsive-item ${service}-player" type="text/html" \
|
||||||
width="100%" style="min-height: 500px" ${allowFullScreen} \
|
width="100%" style="min-height: 500px" ${allowFullScreen} \
|
||||||
src="${resourceUrl(service, src, tokens[idx].attrGet('url'))}"
|
src="${md.utils.escapeHtml(resourceUrl(service, src, tokens[idx].attrGet('url')))}"
|
||||||
scrolling="no" border="0" frameborder="no" framespacing="0"></iframe>`;
|
scrolling="no" border="0" frameborder="no" framespacing="0"></iframe>`;
|
||||||
}
|
}
|
||||||
return `<div data-${service}>${md.utils.escapeHtml(src)}</div>`;
|
return `<div data-${service}>${md.utils.escapeHtml(src)}</div>`;
|
||||||
|
|||||||
Reference in new issue
Block a user