mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-13 22:54:42 -04:00
Jump to 0.3.1
This commit is contained in:
parent
f7f8c901f4
commit
10c9811fc5
49 changed files with 2336 additions and 448 deletions
|
@ -1,43 +1,75 @@
|
|||
//auto update last change
|
||||
var lastchangetime = null;
|
||||
var lastchangeui = null;
|
||||
|
||||
function updateLastChange() {
|
||||
if (lastchangetime && lastchangeui) {
|
||||
lastchangeui.html(' <i class="fa fa-clock-o"></i> change ' + moment(lastchangetime).fromNow());
|
||||
lastchangeui.attr('title', moment(lastchangetime).format('llll'));
|
||||
}
|
||||
}
|
||||
setInterval(updateLastChange, 60000);
|
||||
|
||||
//get title
|
||||
function getTitle(view) {
|
||||
var h1s = view.find("h1");
|
||||
var title = "";
|
||||
if (h1s.length > 0) {
|
||||
if (h1s.length > 0) {
|
||||
title = h1s.first().text();
|
||||
} else {
|
||||
title = null;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
//render title
|
||||
function renderTitle(view) {
|
||||
var title = getTitle(view);
|
||||
if (title) {
|
||||
if (title) {
|
||||
title += ' - HackMD';
|
||||
} else {
|
||||
title = 'HackMD - Collaborative notes';
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
//render filename
|
||||
function renderFilename(view) {
|
||||
var filename = getTitle(view);
|
||||
if (!filename) {
|
||||
if (!filename) {
|
||||
filename = 'Untitled';
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
function slugifyWithUTF8(text) {
|
||||
var newText = S(text.toLowerCase()).trim().stripTags().dasherize().s;
|
||||
newText = newText.replace(/([\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\[\\\]\^\`\{\|\}\~])/g, '');
|
||||
return newText;
|
||||
}
|
||||
|
||||
var viewAjaxCallback = null;
|
||||
|
||||
//regex for blockquote
|
||||
var spaceregex = /\s*/;
|
||||
var notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/;
|
||||
var 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");
|
||||
nameregex = new RegExp(nameregex.source + notinhtmltagregex.source, "g");
|
||||
timeregex = new RegExp(timeregex.source + notinhtmltagregex.source, "g");
|
||||
|
||||
//dynamic event or object binding here
|
||||
function finishView(view) {
|
||||
//youtube
|
||||
view.find(".youtube").click(function () {
|
||||
imgPlayiframe(this, '//www.youtube.com/embed/');
|
||||
});
|
||||
view.find(".youtube.raw").removeClass("raw")
|
||||
.click(function () {
|
||||
imgPlayiframe(this, '//www.youtube.com/embed/');
|
||||
});
|
||||
//vimeo
|
||||
view.find(".vimeo")
|
||||
view.find(".vimeo.raw").removeClass("raw")
|
||||
.click(function () {
|
||||
imgPlayiframe(this, '//player.vimeo.com/video/');
|
||||
})
|
||||
|
@ -54,35 +86,32 @@ function finishView(view) {
|
|||
});
|
||||
});
|
||||
//gist
|
||||
view.find("code[data-gist-id]").each(function(key, value) {
|
||||
if($(value).children().length == 0)
|
||||
view.find("code[data-gist-id]").each(function (key, value) {
|
||||
if ($(value).children().length == 0)
|
||||
$(value).gist(viewAjaxCallback);
|
||||
});
|
||||
//emojify
|
||||
emojify.run(view[0]);
|
||||
//mathjax
|
||||
var mathjaxdivs = view.find('.mathjax').toArray();
|
||||
var mathjaxdivs = view.find('.mathjax.raw').removeClass("raw").toArray();
|
||||
try {
|
||||
for (var i = 0; i < mathjaxdivs.length; i++) {
|
||||
MathJax.Hub.Queue(["Typeset", MathJax.Hub, mathjaxdivs[i].innerHTML]);
|
||||
MathJax.Hub.Queue(viewAjaxCallback);
|
||||
$(mathjaxdivs[i]).removeClass("mathjax");
|
||||
}
|
||||
} catch(err) {
|
||||
}
|
||||
} catch (err) {}
|
||||
//sequence diagram
|
||||
var sequence = view.find(".sequence-diagram");
|
||||
var sequence = view.find(".sequence-diagram.raw").removeClass("raw");
|
||||
try {
|
||||
sequence.sequenceDiagram({
|
||||
theme: 'simple'
|
||||
});
|
||||
sequence.parent().parent().replaceWith(sequence);
|
||||
sequence.removeClass("sequence-diagram");
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
//flowchart
|
||||
var flow = view.find(".flow-chart");
|
||||
var flow = view.find(".flow-chart.raw").removeClass("raw");
|
||||
flow.each(function (key, value) {
|
||||
try {
|
||||
var chart = flowchart.parse($(value).text());
|
||||
|
@ -94,26 +123,41 @@ function finishView(view) {
|
|||
'font-family': "'Andale Mono', monospace"
|
||||
});
|
||||
$(value).parent().parent().replaceWith(value);
|
||||
$(value).removeClass("flow-chart");
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
//image href new window(emoji not included)
|
||||
var images = view.find("p > img[src]:not([class])");
|
||||
images.each(function (key, value) {
|
||||
var src = $(value).attr('src');
|
||||
var a = $('<a>');
|
||||
if (src) {
|
||||
a.attr('href', src);
|
||||
a.attr('target', "_blank");
|
||||
}
|
||||
a.html($(value).clone());
|
||||
$(value).replaceWith(a);
|
||||
});
|
||||
//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();
|
||||
html = html.replace(coloregex, '<span class="color" data-color="$1"></span>');
|
||||
html = html.replace(nameandtimeregex, '<small><i class="fa fa-user"></i> $1 <i class="fa fa-clock-o"></i> $2</small>');
|
||||
html = html.replace(nameregex, '<small><i class="fa fa-user"></i> $1</small>');
|
||||
html = html.replace(timeregex, '<small><i class="fa fa-clock-o"></i> $1</small>');
|
||||
$(value).html(html);
|
||||
});
|
||||
var blockquote_color = blockquote.find(".color");
|
||||
blockquote_color.each(function (key, value) {
|
||||
$(value).closest("blockquote").css('border-left-color', $(value).attr('data-color'));
|
||||
});
|
||||
//render title
|
||||
document.title = renderTitle(view);
|
||||
}
|
||||
|
||||
//regex for blockquote
|
||||
var spaceregex = /\s*/;
|
||||
var notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/;
|
||||
var coloregex = /\[color=([#|\(|\)|\s|\,|\w]*)\]/;
|
||||
coloregex = new RegExp(coloregex.source + notinhtmltagregex.source, "g");
|
||||
var nameregex = /\[name=([-|_|\s|\w]*)\]/;
|
||||
var timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*)\]/;
|
||||
var 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");
|
||||
|
||||
//only static transform should be here
|
||||
function postProcess(code) {
|
||||
var result = $('<div>' + code + '</div>');
|
||||
|
@ -125,32 +169,107 @@ function postProcess(code) {
|
|||
return "<noiframe>" + $(this).html() + "</noiframe>"
|
||||
});
|
||||
//todo list
|
||||
var lis = result[0].getElementsByTagName('li');
|
||||
var lis = result.find('li.raw').removeClass("raw").sortByDepth().toArray();
|
||||
for (var i = 0; i < lis.length; i++) {
|
||||
var html = lis[i].innerHTML;
|
||||
if (/^\s*\[[x ]\]\s+/.test(html)) {
|
||||
lis[i].innerHTML = html.replace(/^\s*\[ \]\s*/, '<input type="checkbox" class="task-list-item-checkbox" disabled>')
|
||||
.replace(/^\s*\[x\]\s*/, '<input type="checkbox" class="task-list-item-checkbox" checked disabled>');
|
||||
var li = lis[i];
|
||||
var html = $(li).clone()[0].innerHTML;
|
||||
var p = $(li).children('p');
|
||||
if (p.length == 1) {
|
||||
html = p.html();
|
||||
li = p[0];
|
||||
}
|
||||
if (/^\s*\[[x ]\]\s*/.test(html)) {
|
||||
li.innerHTML = html.replace(/^\s*\[ \]\s*/, '<input type="checkbox" class="task-list-item-checkbox" disabled><label></label>')
|
||||
.replace(/^\s*\[x\]\s*/, '<input type="checkbox" class="task-list-item-checkbox" checked disabled><label></label>');
|
||||
lis[i].setAttribute('class', 'task-list-item');
|
||||
}
|
||||
}
|
||||
//blockquote
|
||||
var blockquote = result.find("blockquote");
|
||||
blockquote.each(function (key, value) {
|
||||
var html = $(value).html();
|
||||
html = html.replace(coloregex, '<span class="color" data-color="$1"></span>');
|
||||
html = html.replace(nameandtimeregex, '<small><i class="fa fa-user"></i> $1 <i class="fa fa-clock-o"></i> $2</small>');
|
||||
html = html.replace(nameregex, '<small><i class="fa fa-user"></i> $1</small>');
|
||||
html = html.replace(timeregex, '<small><i class="fa fa-clock-o"></i> $1</small>');
|
||||
$(value).html(html);
|
||||
});
|
||||
var blockquotecolor = result.find("blockquote .color");
|
||||
blockquotecolor.each(function (key, value) {
|
||||
$(value).closest("blockquote").css('border-left-color', $(value).attr('data-color'));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
//jQuery sortByDepth
|
||||
$.fn.sortByDepth = function () {
|
||||
var ar = this.map(function () {
|
||||
return {
|
||||
length: $(this).parents().length,
|
||||
elt: this
|
||||
}
|
||||
}).get(),
|
||||
result = [],
|
||||
i = ar.length;
|
||||
ar.sort(function (a, b) {
|
||||
return a.length - b.length;
|
||||
});
|
||||
while (i--) {
|
||||
result.push(ar[i].elt);
|
||||
}
|
||||
return $(result);
|
||||
};
|
||||
|
||||
//remove hash
|
||||
function removeHash() {
|
||||
history.pushState("", document.title, window.location.pathname + window.location.search);
|
||||
}
|
||||
|
||||
//toc
|
||||
function generateToc(id) {
|
||||
var target = $('#' + id);
|
||||
target.html('');
|
||||
new Toc('doc', {
|
||||
'level': 3,
|
||||
'top': -1,
|
||||
'class': 'toc',
|
||||
'targetId': id
|
||||
});
|
||||
if(target.text() == 'undefined')
|
||||
target.html('');
|
||||
var backtotop = $('<a class="back-to-top" href="#">Back to top</a>');
|
||||
var gotobottom = $('<a class="go-to-bottom" href="#">Go to bottom</a>');
|
||||
backtotop.click(function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (scrollToTop)
|
||||
scrollToTop();
|
||||
removeHash();
|
||||
});
|
||||
gotobottom.click(function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (scrollToBottom)
|
||||
scrollToBottom();
|
||||
removeHash();
|
||||
});
|
||||
target.append(backtotop).append(gotobottom);
|
||||
}
|
||||
|
||||
//smooth all hash trigger scrolling
|
||||
function smoothHashScroll() {
|
||||
var hashElements = $("a[href^='#']:not([smoothhashscroll])").toArray();
|
||||
for (var i = 0; i < hashElements.length; i++) {
|
||||
var element = hashElements[i];
|
||||
var $element = $(element);
|
||||
var hash = element.hash;
|
||||
if (hash) {
|
||||
$element.on('click', function (e) {
|
||||
// store hash
|
||||
var hash = this.hash;
|
||||
if ($(hash).length <= 0) return;
|
||||
// prevent default anchor click behavior
|
||||
e.preventDefault();
|
||||
// animate
|
||||
$('html, body').animate({
|
||||
scrollTop: $(hash).offset().top
|
||||
}, 100, "linear", function () {
|
||||
// when done, add hash to url
|
||||
// (default click behaviour)
|
||||
window.location.hash = hash;
|
||||
});
|
||||
});
|
||||
$element.attr('smoothhashscroll', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setSizebyAttr(element, target) {
|
||||
var width = $(element).attr("width") ? $(element).attr("width") : '100%';
|
||||
var height = $(element).attr("height") ? $(element).attr("height") : '360px';
|
||||
|
@ -168,10 +287,10 @@ function imgPlayiframe(element, src) {
|
|||
|
||||
var anchorForId = function (id) {
|
||||
var anchor = document.createElement("a");
|
||||
anchor.className = "header-link";
|
||||
anchor.className = "header-link hidden-xs";
|
||||
anchor.href = "#" + id;
|
||||
anchor.innerHTML = "<span class=\"sr-only\">Permalink</span><i class=\"fa fa-link\"></i>";
|
||||
anchor.title = "Permalink";
|
||||
anchor.innerHTML = "<span class=\"sr-only\"></span><i class=\"fa fa-link\"></i>";
|
||||
anchor.title = id;
|
||||
return anchor;
|
||||
};
|
||||
|
||||
|
@ -179,12 +298,14 @@ var linkifyAnchors = function (level, containingElement) {
|
|||
var headers = containingElement.getElementsByTagName("h" + level);
|
||||
for (var h = 0; h < headers.length; h++) {
|
||||
var header = headers[h];
|
||||
|
||||
if (typeof header.id == "undefined" || header.id == "") {
|
||||
var id = S(header.innerHTML.toLowerCase()).trim().stripTags().dasherize().s;
|
||||
header.id = encodeURIComponent(id);
|
||||
if (header.getElementsByClassName("header-link").length == 0) {
|
||||
if (typeof header.id == "undefined" || header.id == "") {
|
||||
//to escape characters not allow in css and humanize
|
||||
var id = slugifyWithUTF8(header.innerHTML);
|
||||
header.id = id;
|
||||
}
|
||||
header.appendChild(anchorForId(header.id));
|
||||
}
|
||||
header.appendChild(anchorForId(header.id));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -207,10 +328,10 @@ function scrollToHash() {
|
|||
function highlightRender(code, lang) {
|
||||
if (!lang || /no(-?)highlight|plain|text/.test(lang))
|
||||
return;
|
||||
if(lang == 'sequence') {
|
||||
return '<div class="sequence-diagram">' + code + '</div>';
|
||||
} else if(lang == 'flow') {
|
||||
return '<div class="flow-chart">' + code + '</div>';
|
||||
if (lang == 'sequence') {
|
||||
return '<div class="sequence-diagram raw">' + code + '</div>';
|
||||
} else if (lang == 'flow') {
|
||||
return '<div class="flow-chart raw">' + code + '</div>';
|
||||
}
|
||||
var reallang = lang.replace('=', '');
|
||||
var languages = hljs.listLanguages();
|
||||
|
@ -238,10 +359,56 @@ emojify.setConfig({
|
|||
|
||||
var md = new Remarkable('full', {
|
||||
html: true,
|
||||
breaks: true,
|
||||
langPrefix: "",
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
highlight: highlightRender
|
||||
});
|
||||
md.renderer.rules.list_item_open = function (/* tokens, idx, options, env */) {
|
||||
return '<li class="raw">';
|
||||
};
|
||||
md.renderer.rules.blockquote_open = function (tokens, idx /*, options, env */ ) {
|
||||
return '<blockquote class="raw">\n';
|
||||
};
|
||||
md.renderer.rules.hardbreak = function (tokens, idx, options /*, env */ ) {
|
||||
return md.options.xhtmlOut ? '<br /><br />' : '<br><br>';
|
||||
};
|
||||
md.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
||||
var token = tokens[idx];
|
||||
var langClass = '';
|
||||
var langPrefix = options.langPrefix;
|
||||
var langName = '',
|
||||
fenceName;
|
||||
var highlighted;
|
||||
|
||||
if (token.params) {
|
||||
|
||||
//
|
||||
// ```foo bar
|
||||
//
|
||||
// Try custom renderer "foo" first. That will simplify overwrite
|
||||
// for diagrams, latex, and any other fenced block with custom look
|
||||
//
|
||||
|
||||
fenceName = token.params.split(/\s+/g)[0];
|
||||
|
||||
if (Remarkable.utils.has(self.rules.fence_custom, fenceName)) {
|
||||
return self.rules.fence_custom[fenceName](tokens, idx, options, env, self);
|
||||
}
|
||||
|
||||
langName = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(Remarkable.utils.unescapeMd(fenceName)));
|
||||
langClass = ' class="' + langPrefix + langName.replace('=', '') + ' hljs"';
|
||||
}
|
||||
|
||||
if (options.highlight) {
|
||||
highlighted = options.highlight(token.content, langName) || Remarkable.utils.escapeHtml(token.content);
|
||||
} else {
|
||||
highlighted = Remarkable.utils.escapeHtml(token.content);
|
||||
}
|
||||
|
||||
return '<pre><code' + langClass + '>' + highlighted + '</code></pre>' + md.renderer.getBreak(tokens, idx);
|
||||
};
|
||||
//youtube
|
||||
var youtubePlugin = new Plugin(
|
||||
// regexp to match
|
||||
|
@ -251,7 +418,7 @@ var youtubePlugin = new Plugin(
|
|||
function (match, utils) {
|
||||
var videoid = match[1];
|
||||
if (!videoid) return;
|
||||
var div = $('<div class="youtube"></div>');
|
||||
var div = $('<div class="youtube raw"></div>');
|
||||
setSizebyAttr(div, div);
|
||||
div.attr('videoid', videoid);
|
||||
var icon = '<i class="icon fa fa-youtube-play fa-5x"></i>';
|
||||
|
@ -270,7 +437,7 @@ var vimeoPlugin = new Plugin(
|
|||
function (match, utils) {
|
||||
var videoid = match[1];
|
||||
if (!videoid) return;
|
||||
var div = $('<div class="vimeo"></div>');
|
||||
var div = $('<div class="vimeo raw"></div>');
|
||||
setSizebyAttr(div, div);
|
||||
div.attr('videoid', videoid);
|
||||
var icon = '<i class="icon fa fa-vimeo-square fa-5x"></i>';
|
||||
|
@ -298,7 +465,7 @@ var mathjaxPlugin = new Plugin(
|
|||
// this function will be called when something matches
|
||||
function (match, utils) {
|
||||
//var code = $(match).text();
|
||||
return '<span class="mathjax">' + match[0] + '</span>';
|
||||
return '<span class="mathjax raw">' + match[0] + '</span>';
|
||||
}
|
||||
);
|
||||
md.use(youtubePlugin);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue