From 10c9811fc534a2738c19d8f74a447ed500b730a2 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Thu, 2 Jul 2015 00:10:20 +0800 Subject: Jump to 0.3.1 --- public/js/extra.js | 293 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 230 insertions(+), 63 deletions(-) (limited to 'public/js/extra.js') diff --git a/public/js/extra.js b/public/js/extra.js index 495c5677..f6d47647 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -1,43 +1,75 @@ +//auto update last change +var lastchangetime = null; +var lastchangeui = null; + +function updateLastChange() { + if (lastchangetime && lastchangeui) { + lastchangeui.html('  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 = $(''); + 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, ''); + html = html.replace(nameandtimeregex, ' $1 $2'); + html = html.replace(nameregex, ' $1'); + html = html.replace(timeregex, ' $1'); + $(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 = $('
' + code + '
'); @@ -125,30 +169,105 @@ function postProcess(code) { return "" + $(this).html() + "" }); //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*/, '') - .replace(/^\s*\[x\]\s*/, ''); + 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*/, '') + .replace(/^\s*\[x\]\s*/, ''); 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, ''); - html = html.replace(nameandtimeregex, ' $1 $2'); - html = html.replace(nameregex, ' $1'); - html = html.replace(timeregex, ' $1'); - $(value).html(html); + 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; }); - var blockquotecolor = result.find("blockquote .color"); - blockquotecolor.each(function (key, value) { - $(value).closest("blockquote").css('border-left-color', $(value).attr('data-color')); + 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 }); - return result; + if(target.text() == 'undefined') + target.html(''); + var backtotop = $('
Back to top'); + var gotobottom = $('Go to bottom'); + 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) { @@ -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 = "Permalink"; - anchor.title = "Permalink"; + anchor.innerHTML = ""; + 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 '
' + code + '
'; - } else if(lang == 'flow') { - return '
' + code + '
'; + if (lang == 'sequence') { + return '
' + code + '
'; + } else if (lang == 'flow') { + return '
' + code + '
'; } 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 '
  • '; +}; +md.renderer.rules.blockquote_open = function (tokens, idx /*, options, env */ ) { + return '
    \n'; +}; +md.renderer.rules.hardbreak = function (tokens, idx, options /*, env */ ) { + return md.options.xhtmlOut ? '

    ' : '

    '; +}; +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 '
    ' + highlighted + '
    ' + 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 = $('
    '); + var div = $('
    '); setSizebyAttr(div, div); div.attr('videoid', videoid); var icon = ''; @@ -270,7 +437,7 @@ var vimeoPlugin = new Plugin( function (match, utils) { var videoid = match[1]; if (!videoid) return; - var div = $('
    '); + var div = $('
    '); setSizebyAttr(div, div); div.attr('videoid', videoid); var icon = ''; @@ -298,7 +465,7 @@ var mathjaxPlugin = new Plugin( // this function will be called when something matches function (match, utils) { //var code = $(match).text(); - return '' + match[0] + ''; + return '' + match[0] + ''; } ); md.use(youtubePlugin); -- cgit v1.2.3