Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/icewind1991/files_markdown.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2017-08-28 17:37:02 +0300
committerRobin Appelman <robin@icewind.nl>2017-08-28 18:40:21 +0300
commit8322441915a9baa85d99b663714ba65ba414f782 (patch)
tree1c123c62c25eac33bf02fde32d79f56d86a3dc44 /js
parent6482a0f64a967b068bec9f13218318fa23da361a (diff)
video plugin
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'js')
-rw-r--r--js/MermaidPlugin.ts6
-rw-r--r--js/Renderer.ts4
-rw-r--r--js/VideoPlugin.ts148
3 files changed, 154 insertions, 4 deletions
diff --git a/js/MermaidPlugin.ts b/js/MermaidPlugin.ts
index 695c2ba..657b111 100644
--- a/js/MermaidPlugin.ts
+++ b/js/MermaidPlugin.ts
@@ -42,12 +42,12 @@ export const MermaidPlugin = (md: MarkdownIt.MarkdownIt) => {
const token = tokens[idx];
const code = token.content.trim();
if (token.info === 'mermaid') {
- return mermaidChart(code)
+ return mermaidChart(code);
}
const firstLine = code.split(/\n/)[0].trim();
if (firstLine === 'gantt' || firstLine === 'sequenceDiagram' || firstLine.match(/^graph (?:TB|BT|RL|LR|TD);?$/)) {
- return mermaidChart(code)
+ return mermaidChart(code);
}
- return originalRenderer(tokens, idx, options, env, slf)
+ return originalRenderer(tokens, idx, options, env, slf);
}
}; \ No newline at end of file
diff --git a/js/Renderer.ts b/js/Renderer.ts
index 7b0aba8..1b60d57 100644
--- a/js/Renderer.ts
+++ b/js/Renderer.ts
@@ -4,6 +4,7 @@ import {CheckboxPlugin} from './CheckboxPlugin';
import * as AnchorPlugin from 'markdown-it-anchor';
import * as slugify from 'slugify';
import * as TOCPlugin from 'markdown-it-table-of-contents';
+import VideoPlugin from './VideoPlugin';
import 'katex/dist/katex.min.css';
import 'highlight.js/styles/github.css';
@@ -81,6 +82,7 @@ export class Renderer {
this.md.use(TOCPlugin, {
slugify: slugifyHeading
});
+ this.md.use(VideoPlugin);
this.md.use(iterator, 'url_new_win', 'link_open', (tokens: MarkdownIt.Token[], idx: number) => {
const href = tokens[idx].attrGet('href') as string;
if (href[0] !== '#') {
@@ -111,7 +113,7 @@ export class Renderer {
}
getImageUrl(path: string): string {
- if (!path) {
+ if (!path || path.indexOf('.') === -1) {
return path;
}
if (path.substr(0, 7) === 'http://' || path.substr(0, 8) === 'https://' || path.substr(0, 3) === '://') {
diff --git a/js/VideoPlugin.ts b/js/VideoPlugin.ts
new file mode 100644
index 0000000..3a72e4f
--- /dev/null
+++ b/js/VideoPlugin.ts
@@ -0,0 +1,148 @@
+// based on https://github.com/brianjgeiger/markdown-it-video
+
+import {default as MarkdownIt, Token} from "markdown-it";
+
+type VideoService = 'youtube' | 'vimeo' | 'vine' | 'prezi';
+
+function isVideoService(service: string): service is VideoService {
+ return ['youtube', 'vimeo', 'vine', 'prezi'].indexOf(service) !== -1;
+}
+
+const youtubeRegex = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
+
+function youtubeParser(url: string): string {
+ const match = url.match(youtubeRegex);
+ return match && match[7].length === 11 ? match[7] : url;
+}
+
+/*eslint-disable max-len */
+const vimeoRegex = /https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|)(\d+)(?:$|\/|\?)/;
+
+/*eslint-enable max-len */
+function vimeoParser(url: string): string {
+ const match = url.match(vimeoRegex);
+ return match && typeof match[3] === 'string' ? match[3] : url;
+}
+
+const vineRegex = /^http(?:s?):\/\/(?:www\.)?vine\.co\/v\/([a-zA-Z0-9]{1,13}).*/;
+
+function vineParser(url: string): string {
+ const match = url.match(vineRegex);
+ return match && match[1].length === 11 ? match[1] : url;
+}
+
+const preziRegex = /^https:\/\/prezi.com\/(.[^/]+)/;
+
+function preziParser(url: string): string {
+ const match = url.match(preziRegex);
+ return match ? match[1] : url;
+}
+
+function getVideoId(service: string, url: string): string | false {
+ const serviceLower = service.toLowerCase();
+ if (serviceLower === 'youtube') {
+ return youtubeParser(url);
+ } else if (serviceLower === 'vimeo') {
+ return vimeoParser(url);
+ } else if (serviceLower === 'vine') {
+ return vineParser(url);
+ } else if (serviceLower === 'prezi') {
+ return preziParser(url);
+ }
+ return false;
+}
+
+function videoUrl(service: VideoService, videoID: string, options: VideoOptions): string {
+ switch (service) {
+ case 'youtube':
+ return '//www.youtube.com/embed/' + videoID;
+ case 'vimeo':
+ return '//player.vimeo.com/video/' + videoID;
+ case 'vine':
+ return '//vine.co/v/' + videoID + '/embed/' + options.vine.embed;
+ case 'prezi':
+ return 'https://prezi.com/embed/' + videoID +
+ '/?bgcolor=ffffff&amp;lock_to_path=0&amp;autoplay=0&amp;autohide_ctrls=0&amp;' +
+ 'landing_data=bHVZZmNaNDBIWnNjdEVENDRhZDFNZGNIUE43MHdLNWpsdFJLb2ZHanI5N1lQVHkxSHFxazZ0UUNCRHloSXZROHh3PT0&amp;' +
+ 'landing_sign=1kD6c0N6aYpMUS0wxnQjxzSqZlEB8qNFdxtdjYhwSuI';
+ }
+}
+
+function isEmbeddedVideo(url: string) {
+ return url.match(/\.(webm|mp4|ogv)/) !== null;
+}
+
+function renderVideo(md: MarkdownIt.MarkdownIt, options: VideoOptions) {
+ const altTokenizer = md.renderer['renderInlineAsText'];
+ return (tokens: Token[], idx: number, env) => {
+ const token = tokens[idx];
+ const url = token.attrGet('src');
+ if (!url) {
+ return false;
+ }
+ token.attrs[token.attrIndex('alt')][1] = altTokenizer(token.children, options, env);
+ const alt = token.attrGet('alt');
+ if (alt && isVideoService(alt)) {
+ return renderVideoService(md, options, alt, url);
+ }
+ console.log(url, isEmbeddedVideo(url));
+ if (isEmbeddedVideo(url)) {
+ return renderEmbededVideo(md, options, url);
+ }
+
+ return false;
+ }
+}
+
+function renderVideoService(md: MarkdownIt.MarkdownIt, options: VideoOptions, service: VideoService, url: string): string | false {
+ const videoID = getVideoId(service, url as string);
+ if (!videoID) {
+ return false;
+ }
+ const escapedVideoId = md.utils.escapeHtml(videoID);
+ const lowerService = service.toLowerCase() as VideoService;
+ const height = options[lowerService].width / 16 * 9;
+ return videoID === '' ? '' :
+ '<div class="embed-responsive"><iframe class="embed-responsive-item" id="' +
+ service + 'player" type="text/html" width="' + (options[lowerService].width) +
+ '" height="' + (height) +
+ '" src="' + videoUrl(lowerService, escapedVideoId, options) +
+ '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>';
+}
+
+function renderEmbededVideo(md: MarkdownIt.MarkdownIt, options: VideoOptions, url: string) {
+ url = md.utils.escapeHtml(url);
+ return `<div class="embed-responsive"><video controls="controls" src="${url}"/></div>`;
+}
+
+export interface VideoServiceOptions {
+ width: number;
+}
+
+export interface VineOptions extends VideoServiceOptions {
+ embed: string;
+}
+
+export interface VideoOptions {
+ youtube: VideoServiceOptions;
+ vimeo: VideoServiceOptions;
+ vine: VineOptions;
+ prezi: VideoServiceOptions;
+}
+
+const defaults: VideoOptions = {
+ youtube: {width: 640},
+ vimeo: {width: 500},
+ vine: {width: 600, embed: 'simple'},
+ prezi: {width: 550}
+};
+
+export default function VideoPlugin(md: MarkdownIt.MarkdownIt, options: VideoOptions) {
+ const originalRenderer = md.renderer.rules.image;
+ md.renderer.rules.image = (tokens: Token[], idx: number, options: VideoOptions, env, slf) => {
+ options = $.extend(defaults, options);
+ console.log(JSON.stringify(tokens[idx]));
+ const videoResult = renderVideo(md, options)(tokens, idx, env);
+ return videoResult || originalRenderer(tokens, idx, options, env, slf)
+ };
+} \ No newline at end of file