diff --git a/public/js/extra.js b/public/js/extra.js index ba61a669..f1681b2e 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -1,15 +1,17 @@ require('prismjs/themes/prism.css'); - -var Prism = require('prismjs'); require('prismjs/components/prism-wiki'); require('prismjs/components/prism-haskell'); require('prismjs/components/prism-go'); require('prismjs/components/prism-typescript'); require('prismjs/components/prism-jsx'); -var hljs = require('highlight.js'); -var PDFObject = require('pdfobject'); -var S = require('string'); -var saveAs = require('file-saver').saveAs; + +import Prism from 'prismjs'; +import hljs from 'highlight.js'; +import PDFObject from 'pdfobject'; +import S from 'string'; +import { saveAs } from 'file-saver'; + +require('./common'); require('../vendor/md-toc'); //auto update last change @@ -21,9 +23,10 @@ window.lastchangeui = { user: $(".ui-lastchangeuser"), nouser: $(".ui-no-lastchangeuser") } -var ownerui = $(".ui-owner"); -function updateLastChange() { +const ownerui = $(".ui-owner"); + +export function updateLastChange() { if (!lastchangeui) return; if (createtime) { if (createtime && !lastchangetime) { @@ -31,7 +34,7 @@ function updateLastChange() { } else { lastchangeui.status.text('changed'); } - var time = lastchangetime || createtime; + const time = lastchangetime || createtime; lastchangeui.time.html(moment(time).fromNow()); lastchangeui.time.attr('title', moment(time).format('llll')); } @@ -40,13 +43,14 @@ setInterval(updateLastChange, 60000); window.lastchangeuser = null; window.lastchangeuserprofile = null; -function updateLastChangeUser() { + +export function updateLastChangeUser() { if (lastchangeui) { if (lastchangeuser && lastchangeuserprofile) { - var icon = lastchangeui.user.children('i'); + const icon = lastchangeui.user.children('i'); icon.attr('title', lastchangeuserprofile.name).tooltip('fixTitle'); if (lastchangeuserprofile.photo) - icon.attr('style', 'background-image:url(' + lastchangeuserprofile.photo + ')'); + icon.attr('style', `background-image:url(${lastchangeuserprofile.photo})`); lastchangeui.user.show(); lastchangeui.nouser.hide(); } else { @@ -58,12 +62,13 @@ function updateLastChangeUser() { window.owner = null; window.ownerprofile = null; -function updateOwner() { + +export function updateOwner() { if (ownerui) { if (owner && ownerprofile && owner !== lastchangeuser) { - var icon = ownerui.children('i'); + const icon = ownerui.children('i'); icon.attr('title', ownerprofile.name).tooltip('fixTitle'); - var styleString = 'background-image:url(' + ownerprofile.photo + ')'; + const styleString = `background-image:url(${ownerprofile.photo})`; if (ownerprofile.photo && icon.attr('style') !== styleString) icon.attr('style', styleString); ownerui.show(); @@ -75,11 +80,11 @@ function updateOwner() { //get title function getTitle(view) { - var title = ""; + let title = ""; if (md && md.meta && md.meta.title && (typeof md.meta.title == "string" || typeof md.meta.title == "number")) { title = md.meta.title; } else { - var h1s = view.find("h1"); + const h1s = view.find("h1"); if (h1s.length > 0) { title = h1s.first().text(); } else { @@ -90,8 +95,8 @@ function getTitle(view) { } //render title -function renderTitle(view) { - var title = getTitle(view); +export function renderTitle(view) { + let title = getTitle(view); if (title) { title += ' - HackMD'; } else { @@ -101,8 +106,8 @@ function renderTitle(view) { } //render filename -function renderFilename(view) { - var filename = getTitle(view); +export function renderFilename(view) { + let filename = getTitle(view); if (!filename) { filename = 'Untitled'; } @@ -110,29 +115,29 @@ function renderFilename(view) { } // render tags -function renderTags(view) { - var tags = []; - var rawtags = []; +export function renderTags(view) { + const tags = []; + const rawtags = []; if (md && md.meta && md.meta.tags && (typeof md.meta.tags == "string" || typeof md.meta.tags == "number")) { - var metaTags = ('' + md.meta.tags).split(','); + const metaTags = (`${md.meta.tags}`).split(','); for (var i = 0; i < metaTags.length; i++) { - var text = metaTags[i].trim(); + const text = metaTags[i].trim(); if (text) rawtags.push(text); } } else { - view.find('h6').each(function (key, value) { + view.find('h6').each((key, value) => { if (/^tags/gmi.test($(value).text())) { - var codes = $(value).find("code"); - for (var i = 0; i < codes.length; i++) { - var text = codes[i].innerHTML.trim(); + const codes = $(value).find("code"); + for (let i = 0; i < codes.length; i++) { + const text = codes[i].innerHTML.trim(); if (text) rawtags.push(text); } } }); } for (var i = 0; i < rawtags.length; i++) { - var found = false; - for (var j = 0; j < tags.length; j++) { + let found = false; + for (let j = 0; j < tags.length; j++) { if (tags[j] == rawtags[i]) { found = true; break; @@ -145,13 +150,13 @@ function renderTags(view) { } function slugifyWithUTF8(text) { - var newText = S(text.toLowerCase()).trim().stripTags().dasherize().s; + let newText = S(text.toLowerCase()).trim().stripTags().dasherize().s; newText = newText.replace(/([\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\[\\\]\^\`\{\|\}\~])/g, ''); return newText; } -function isValidURL(str) { - var pattern = new RegExp('^(https?:\\/\\/)?' + // protocol +export function isValidURL(str) { + const pattern = new RegExp('^(https?:\\/\\/)?' + // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path @@ -165,12 +170,12 @@ function isValidURL(str) { } //parse meta -function parseMeta(md, edit, view, toc, tocAffix) { - var lang = null; - var dir = null; - var breaks = true; +export function parseMeta(md, edit, view, toc, tocAffix) { + let lang = null; + let dir = null; + let breaks = true; if (md && md.meta) { - var meta = md.meta; + const meta = md.meta; lang = meta.lang; dir = meta.dir; breaks = meta.breaks; @@ -210,13 +215,13 @@ function parseMeta(md, edit, view, toc, tocAffix) { window.viewAjaxCallback = null; //regex for extra tags -var spaceregex = /\s*/; -var notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/; -var coloregex = /\[color=([#|\(|\)|\s|\,|\w]*?)\]/; +const spaceregex = /\s*/; +const notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/; +let coloregex = /\[color=([#|\(|\)|\s|\,|\w]*?)\]/; coloregex = new RegExp(coloregex.source + notinhtmltagregex.source, "g"); -var nameregex = /\[name=(.*?)\]/; -var timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*?)\]/; -var nameandtimeregex = new RegExp(nameregex.source + spaceregex.source + timeregex.source + notinhtmltagregex.source, "g"); +let nameregex = /\[name=(.*?)\]/; +let timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*?)\]/; +const nameandtimeregex = new RegExp(nameregex.source + spaceregex.source + timeregex.source + notinhtmltagregex.source, "g"); nameregex = new RegExp(nameregex.source + notinhtmltagregex.source, "g"); timeregex = new RegExp(timeregex.source + notinhtmltagregex.source, "g"); @@ -231,35 +236,36 @@ function replaceExtraTags(html) { if (typeof mermaid !== 'undefined' && mermaid) mermaid.startOnLoad = false; //dynamic event or object binding here -function finishView(view) { +export function finishView(view) { //todo list - var lis = view.find('li.raw').removeClass("raw").sortByDepth().toArray(); - for (var i = 0; i < lis.length; i++) { - var li = lis[i]; - var html = $(li).clone()[0].innerHTML; - var p = $(li).children('p'); + const lis = view.find('li.raw').removeClass("raw").sortByDepth().toArray(); + + for (let li of lis) { + let html = $(li).clone()[0].innerHTML; + const p = $(li).children('p'); if (p.length == 1) { html = p.html(); li = p[0]; } html = replaceExtraTags(html); li.innerHTML = html; - var disabled = 'disabled'; + let disabled = 'disabled'; if(typeof editor !== 'undefined' && havePermission()) disabled = ''; if (/^\s*\[[x ]\]\s*/.test(html)) { - li.innerHTML = html.replace(/^\s*\[ \]\s*/, '') - .replace(/^\s*\[x\]\s*/, ''); - lis[i].setAttribute('class', 'task-list-item'); + li.innerHTML = html.replace(/^\s*\[ \]\s*/, ``) + .replace(/^\s*\[x\]\s*/, ``); + li.setAttribute('class', 'task-list-item'); } if (typeof editor !== 'undefined' && havePermission()) $(li).find('input').change(toggleTodoEvent); //color tag in list will convert it to tag icon with color - var tag_color = $(li).closest('ul').find(".color"); - tag_color.each(function (key, value) { + const tag_color = $(li).closest('ul').find(".color"); + tag_color.each((key, value) => { $(value).addClass('fa fa-tag').css('color', $(value).attr('data-color')); }); } + //youtube view.find("div.youtube.raw").removeClass("raw") .click(function () { @@ -270,41 +276,41 @@ function finishView(view) { .click(function () { imgPlayiframe(this, '//player.vimeo.com/video/'); }) - .each(function (key, value) { + .each((key, value) => { $.ajax({ type: 'GET', - url: '//vimeo.com/api/v2/video/' + $(value).attr('data-videoid') + '.json', + url: `//vimeo.com/api/v2/video/${$(value).attr('data-videoid')}.json`, jsonp: 'callback', dataType: 'jsonp', - success: function (data) { - var thumbnail_src = data[0].thumbnail_large; - var image = ''; + success(data) { + const thumbnail_src = data[0].thumbnail_large; + const image = ``; $(value).prepend(image); if(viewAjaxCallback) viewAjaxCallback(); } }); }); //gist - view.find("code[data-gist-id]").each(function (key, value) { + view.find("code[data-gist-id]").each((key, value) => { if ($(value).children().length == 0) $(value).gist(viewAjaxCallback); }); //sequence diagram - var sequences = view.find("div.sequence-diagram.raw").removeClass("raw"); - sequences.each(function (key, value) { + const sequences = view.find("div.sequence-diagram.raw").removeClass("raw"); + sequences.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var sequence = $value; + const sequence = $value; sequence.sequenceDiagram({ theme: 'simple' }); $ele.addClass('sequence-diagram'); $value.children().unwrap().unwrap(); - var svg = $ele.find('> svg'); - svg[0].setAttribute('viewBox', '0 0 ' + svg.attr('width') + ' ' + svg.attr('height')); + const svg = $ele.find('> svg'); + svg[0].setAttribute('viewBox', `0 0 ${svg.attr('width')} ${svg.attr('height')}`); svg[0].setAttribute('preserveAspectRatio', 'xMidYMid meet'); } catch (err) { $value.unwrap(); @@ -312,13 +318,13 @@ function finishView(view) { } }); //flowchart - var flow = view.find("div.flow-chart.raw").removeClass("raw"); - flow.each(function (key, value) { + const flow = view.find("div.flow-chart.raw").removeClass("raw"); + flow.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var chart = flowchart.parse($value.text()); + const chart = flowchart.parse($value.text()); $value.html(''); chart.drawSVG(value, { 'line-width': 2, @@ -335,14 +341,14 @@ function finishView(view) { } }); //graphviz - var Viz = require("viz.js"); - var graphvizs = view.find("div.graphviz.raw").removeClass("raw"); - graphvizs.each(function (key, value) { + const Viz = require("viz.js"); + const graphvizs = view.find("div.graphviz.raw").removeClass("raw"); + graphvizs.each((key, value) => { try { var $value = $(value); - var $ele = $(value).parent().parent(); + const $ele = $(value).parent().parent(); - var graphviz = Viz($value.text()); + const graphviz = Viz($value.text()); if (!graphviz) throw Error('viz.js output empty graph'); $value.html(graphviz); @@ -354,14 +360,14 @@ function finishView(view) { } }); //mermaid - var mermaids = view.find("div.mermaid.raw").removeClass("raw"); - mermaids.each(function (key, value) { + const mermaids = view.find("div.mermaid.raw").removeClass("raw"); + mermaids.each((key, value) => { try { var $value = $(value); - var $ele = $(value).closest('pre'); + const $ele = $(value).closest('pre'); - var mermaidError = null; - mermaid.parseError = function (err, hash) { + let mermaidError = null; + mermaid.parseError = (err, hash) => { mermaidError = err; }; @@ -379,44 +385,44 @@ function finishView(view) { } }); //image href new window(emoji not included) - var images = view.find("img.raw[src]").removeClass("raw"); - images.each(function (key, value) { + const images = view.find("img.raw[src]").removeClass("raw"); + images.each((key, value) => { // if it's already wrapped by link, then ignore - var $value = $(value); - $value[0].onload = function (e) { + const $value = $(value); + $value[0].onload = e => { if(viewAjaxCallback) viewAjaxCallback(); }; }); //blockquote - var blockquote = view.find("blockquote.raw").removeClass("raw"); - var blockquote_p = blockquote.find("p"); - blockquote_p.each(function (key, value) { - var html = $(value).html(); + const blockquote = view.find("blockquote.raw").removeClass("raw"); + const blockquote_p = blockquote.find("p"); + blockquote_p.each((key, value) => { + let html = $(value).html(); html = replaceExtraTags(html); $(value).html(html); }); //color tag in blockquote will change its left border color - var blockquote_color = blockquote.find(".color"); - blockquote_color.each(function (key, value) { + const blockquote_color = blockquote.find(".color"); + blockquote_color.each((key, value) => { $(value).closest("blockquote").css('border-left-color', $(value).attr('data-color')); }); //slideshare view.find("div.slideshare.raw").removeClass("raw") - .each(function (key, value) { + .each((key, value) => { $.ajax({ type: 'GET', - url: '//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/' + $(value).attr('data-slideshareid') + '&format=json', + url: `//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/${$(value).attr('data-slideshareid')}&format=json`, jsonp: 'callback', dataType: 'jsonp', - success: function (data) { - var $html = $(data.html); - var iframe = $html.closest('iframe'); - var caption = $html.closest('div'); - var inner = $('
').append(iframe); - var height = iframe.attr('height'); - var width = iframe.attr('width'); - var ratio = (height / width) * 100; - inner.css('padding-bottom', ratio + '%'); + success(data) { + const $html = $(data.html); + const iframe = $html.closest('iframe'); + const caption = $html.closest('div'); + const inner = $('').append(iframe); + const height = iframe.attr('height'); + const width = iframe.attr('width'); + const ratio = (height / width) * 100; + inner.css('padding-bottom', `${ratio}%`); $(value).html(inner).append(caption); if(viewAjaxCallback) viewAjaxCallback(); } @@ -424,31 +430,31 @@ function finishView(view) { }); //speakerdeck view.find("div.speakerdeck.raw").removeClass("raw") - .each(function (key, value) { - var url = 'https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2F' + encodeURIComponent($(value).attr('data-speakerdeckid')); + .each((key, value) => { + const url = `https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2F${encodeURIComponent($(value).attr('data-speakerdeckid'))}`; //use yql because speakerdeck not support jsonp $.ajax({ url: 'https://query.yahooapis.com/v1/public/yql', data: { - q: "select * from json where url ='" + url + "'", + q: `select * from json where url ='${url}'`, format: "json" }, dataType: "jsonp", - success: function (data) { + success(data) { if (!data.query || !data.query.results) return; - var json = data.query.results.json; - var html = json.html; + const json = data.query.results.json; + const html = json.html; var ratio = json.height / json.width; $(value).html(html); - var iframe = $(value).children('iframe'); - var src = iframe.attr('src'); + const iframe = $(value).children('iframe'); + const src = iframe.attr('src'); if (src.indexOf('//') == 0) - iframe.attr('src', 'https:' + src); - var inner = $('').append(iframe); - var height = iframe.attr('height'); - var width = iframe.attr('width'); + iframe.attr('src', `https:${src}`); + const inner = $('').append(iframe); + const height = iframe.attr('height'); + const width = iframe.attr('width'); var ratio = (height / width) * 100; - inner.css('padding-bottom', ratio + '%'); + inner.css('padding-bottom', `${ratio}%`); $(value).html(inner); if(viewAjaxCallback) viewAjaxCallback(); } @@ -457,8 +463,8 @@ function finishView(view) { //pdf view.find("div.pdf.raw").removeClass("raw") .each(function (key, value) { - var url = $(value).attr('data-pdfurl'); - var inner = $(''); + const url = $(value).attr('data-pdfurl'); + const inner = $(''); $(this).append(inner); PDFObject.embed(url, inner, { height: '400px' @@ -466,12 +472,12 @@ function finishView(view) { }); //syntax highlighting view.find("code.raw").removeClass("raw") - .each(function (key, value) { - var langDiv = $(value); + .each((key, value) => { + const langDiv = $(value); if (langDiv.length > 0) { - var reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim(); - var codeDiv = langDiv.find('.code'); - var code = ""; + const reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim(); + const codeDiv = langDiv.find('.code'); + let code = ""; if (codeDiv.length > 0) code = codeDiv.html(); else code = langDiv.html(); if (!reallang) { @@ -490,8 +496,8 @@ function finishView(view) { }; } else { code = S(code).unescapeHTML().s; - var languages = hljs.listLanguages(); - if (languages.indexOf(reallang) == -1) { + const languages = hljs.listLanguages(); + if (!languages.includes(reallang)) { var result = hljs.highlightAuto(code); } else { var result = hljs.highlight(reallang, code); @@ -502,7 +508,7 @@ function finishView(view) { } }); //mathjax - var mathjaxdivs = view.find('span.mathjax.raw').removeClass("raw").toArray(); + const mathjaxdivs = view.find('span.mathjax.raw').removeClass("raw").toArray(); try { if (mathjaxdivs.length > 1) { MathJax.Hub.Queue(["Typeset", MathJax.Hub, mathjaxdivs]); @@ -519,16 +525,16 @@ function finishView(view) { } //only static transform should be here -function postProcess(code) { - var result = $(''
- + highlighted
- + '
\n';
+ return `${highlighted}
\n`;
};
/* Defined regex markdown it plugins */
-var Plugin = require('markdown-it-regexp');
+import Plugin from 'markdown-it-regexp';
//youtube
-var youtubePlugin = new Plugin(
+const youtubePlugin = new Plugin(
// regexp to match
/{%youtube\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var videoid = match[1];
+ (match, utils) => {
+ const videoid = match[1];
if (!videoid) return;
- var div = $('');
+ const div = $('');
div.attr('data-videoid', videoid);
- var thumbnail_src = '//img.youtube.com/vi/' + videoid + '/hqdefault.jpg';
- var image = '';
+ const thumbnail_src = `//img.youtube.com/vi/${videoid}/hqdefault.jpg`;
+ const image = ``;
div.append(image);
- var icon = '';
+ const icon = '';
div.append(icon);
return div[0].outerHTML;
}
);
//vimeo
-var vimeoPlugin = new Plugin(
+const vimeoPlugin = new Plugin(
// regexp to match
/{%vimeo\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var videoid = match[1];
+ (match, utils) => {
+ const videoid = match[1];
if (!videoid) return;
- var div = $('');
+ const div = $('');
div.attr('data-videoid', videoid);
- var icon = '';
+ const icon = '';
div.append(icon);
return div[0].outerHTML;
}
);
//gist
-var gistPlugin = new Plugin(
+const gistPlugin = new Plugin(
// regexp to match
/{%gist\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var gistid = match[1];
- var code = '
';
+ (match, utils) => {
+ const gistid = match[1];
+ const code = `
`;
return code;
}
);
//TOC
-var tocPlugin = new Plugin(
+const tocPlugin = new Plugin(
// regexp to match
/^\[TOC\]$/i,
- // this function will be called when something matches
- function (match, utils) {
- return '';
- }
+ (match, utils) => ''
);
//slideshare
-var slidesharePlugin = new Plugin(
+const slidesharePlugin = new Plugin(
// regexp to match
/{%slideshare\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var slideshareid = match[1];
- var div = $('');
+ (match, utils) => {
+ const slideshareid = match[1];
+ const div = $('');
div.attr('data-slideshareid', slideshareid);
return div[0].outerHTML;
}
);
//speakerdeck
-var speakerdeckPlugin = new Plugin(
+const speakerdeckPlugin = new Plugin(
// regexp to match
/{%speakerdeck\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var speakerdeckid = match[1];
- var div = $('');
+ (match, utils) => {
+ const speakerdeckid = match[1];
+ const div = $('');
div.attr('data-speakerdeckid', speakerdeckid);
return div[0].outerHTML;
}
);
//pdf
-var pdfPlugin = new Plugin(
+const pdfPlugin = new Plugin(
// regexp to match
/{%pdf\s*([\d\D]*?)\s*%}/,
- // this function will be called when something matches
- function (match, utils) {
- var pdfurl = match[1];
+ (match, utils) => {
+ const pdfurl = match[1];
if (!isValidURL(pdfurl)) return match[0];
- var div = $('');
+ const div = $('');
div.attr('data-pdfurl', pdfurl);
return div[0].outerHTML;
}
@@ -1090,8 +1081,8 @@ var pdfPlugin = new Plugin(
//yaml meta, from https://github.com/eugeneware/remarkable-meta
function get(state, line) {
- var pos = state.bMarks[line];
- var max = state.eMarks[line];
+ const pos = state.bMarks[line];
+ const max = state.eMarks[line];
return state.src.substr(pos, max - pos);
}
@@ -1100,9 +1091,9 @@ function meta(state, start, end, silent) {
if (state.tShift[start] < 0) return false;
if (!get(state, start).match(/^---$/)) return false;
- var data = [];
+ const data = [];
for (var line = start + 1; line < end; line++) {
- var str = get(state, line);
+ const str = get(state, line);
if (str.match(/^(\.{3}|-{3})$/)) break;
if (state.tShift[line] < 0) break;
data.push(str);
@@ -1138,24 +1129,6 @@ md.use(slidesharePlugin);
md.use(speakerdeckPlugin);
md.use(pdfPlugin);
-module.exports = {
- md: md,
- updateLastChange: updateLastChange,
- postProcess: postProcess,
- finishView: finishView,
- autoLinkify: autoLinkify,
- deduplicatedHeaderId: deduplicatedHeaderId,
- renderTOC: renderTOC,
- renderTitle: renderTitle,
- renderFilename: renderFilename,
- renderTags: renderTags,
- isValidURL: isValidURL,
- generateToc: generateToc,
- smoothHashScroll: smoothHashScroll,
- scrollToHash: scrollToHash,
- updateLastChangeUser: updateLastChangeUser,
- updateOwner: updateOwner,
- parseMeta: parseMeta,
- exportToHTML: exportToHTML,
- exportToRawHTML: exportToRawHTML
+export default {
+ md
};
diff --git a/public/js/index.js b/public/js/index.js
index 381f051e..7406c9a2 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -30,26 +30,27 @@ import {
version
} from './common';
-var extra = require('./extra');
-var md = extra.md;
-var updateLastChange = extra.updateLastChange;
-var postProcess = extra.postProcess;
-var finishView = extra.finishView;
-var autoLinkify = extra.autoLinkify;
-var generateToc = extra.generateToc;
-var smoothHashScroll = extra.smoothHashScroll;
-var deduplicatedHeaderId = extra.deduplicatedHeaderId;
-var renderTOC = extra.renderTOC;
-var renderTitle = extra.renderTitle;
-var renderFilename = extra.renderFilename;
-var renderTags = extra.renderTags;
-var isValidURL = extra.isValidURL;
-var scrollToHash = extra.scrollToHash;
-var updateLastChangeUser = extra.updateLastChangeUser;
-var updateOwner = extra.updateOwner;
-var parseMeta = extra.parseMeta;
-var exportToHTML = extra.exportToHTML;
-var exportToRawHTML = extra.exportToRawHTML;
+import {
+ autoLinkify,
+ deduplicatedHeaderId,
+ exportToHTML,
+ exportToRawHTML,
+ finishView,
+ generateToc,
+ isValidURL,
+ md,
+ parseMeta,
+ postProcess,
+ renderFilename,
+ renderTOC,
+ renderTags,
+ renderTitle,
+ scrollToHash,
+ smoothHashScroll,
+ updateLastChange,
+ updateLastChangeUser,
+ updateOwner
+} from './extra';
import {
clearMap,