Browse Source

Use browserify to build demo

pull/104/head
Vitaly Puzrin 10 years ago
parent
commit
858475af7a
  1. 13
      Makefile
  2. 10
      support/demo_template/index.jade
  3. 680
      support/demo_template/index.js

13
Makefile

@ -24,19 +24,8 @@ demo: lint
> ./demo/index.css > ./demo/index.css
rm -rf ./support/demo_template/sample.json rm -rf ./support/demo_template/sample.json
browserify ./ -s markdownit > ./demo/markdown-it.js browserify ./ -s markdownit > ./demo/markdown-it.js
#cp ./dist/markdown-it.js ./demo/ browserify ./support/demo_template/index.js > ./demo/index.js
cp ./support/demo_template/index.js ./demo/
cp ./support/demo_template/README.md ./demo/ cp ./support/demo_template/README.md ./demo/
mkdir ./demo/plugins
cp ./node_modules/markdown-it-abbr/dist/* ./demo/plugins
cp ./node_modules/markdown-it-container/dist/* ./demo/plugins
cp ./node_modules/markdown-it-deflist/dist/* ./demo/plugins
cp ./node_modules/markdown-it-emoji/dist/* ./demo/plugins
cp ./node_modules/markdown-it-footnote/dist/* ./demo/plugins
cp ./node_modules/markdown-it-ins/dist/* ./demo/plugins
cp ./node_modules/markdown-it-mark/dist/* ./demo/plugins
cp ./node_modules/markdown-it-sub/dist/* ./demo/plugins
cp ./node_modules/markdown-it-sup/dist/* ./demo/plugins
gh-demo: demo gh-demo: demo
touch ./demo/.nojekyll touch ./demo/.nojekyll

10
support/demo_template/index.jade

@ -20,16 +20,6 @@ html
script(src='markdown-it.js') script(src='markdown-it.js')
script(src='https://twemoji.maxcdn.com/twemoji.min.js') script(src='https://twemoji.maxcdn.com/twemoji.min.js')
script(src='plugins/markdown-it-abbr.js')
script(src='plugins/markdown-it-container.js')
script(src='plugins/markdown-it-deflist.js')
script(src='plugins/markdown-it-emoji.js')
script(src='plugins/markdown-it-footnote.js')
script(src='plugins/markdown-it-ins.js')
script(src='plugins/markdown-it-mark.js')
script(src='plugins/markdown-it-sub.js')
script(src='plugins/markdown-it-sup.js')
link(rel='stylesheet' href='index.css') link(rel='stylesheet' href='index.css')
script(src='index.js') script(src='index.js')

680
support/demo_template/index.js

@ -1,407 +1,405 @@
(function () { 'use strict';
'use strict';
/*eslint-env browser*/
/*global $, _*/
var mdHtml, mdSrc, permalink, scrollMap;
var defaults = {
html: false, // Enable HTML tags in source
xhtmlOut: false, // Use '/' to close single tags (<br />)
breaks: false, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: true, // autoconvert URL-like texts to links
typographer: true, // Enable smartypants and other sweet transforms
// options below are for demo only
_highlight: true,
_strict: false,
_view: 'html' // html / src / debug
};
defaults.highlight = function (str, lang) { /*eslint-env browser*/
if (!defaults._highlight || !window.hljs) { return ''; } /*global $, _*/
var hljs = window.hljs; var mdHtml, mdSrc, permalink, scrollMap;
if (lang && hljs.getLanguage(lang)) {
try { var defaults = {
return hljs.highlight(lang, str).value; html: false, // Enable HTML tags in source
} catch (__) {} xhtmlOut: false, // Use '/' to close single tags (<br />)
} breaks: false, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: true, // autoconvert URL-like texts to links
typographer: true, // Enable smartypants and other sweet transforms
// options below are for demo only
_highlight: true,
_strict: false,
_view: 'html' // html / src / debug
};
defaults.highlight = function (str, lang) {
if (!defaults._highlight || !window.hljs) { return ''; }
var hljs = window.hljs;
if (lang && hljs.getLanguage(lang)) {
try { try {
return hljs.highlightAuto(str).value; return hljs.highlight(lang, str).value;
} catch (__) {} } catch (__) {}
}
return ''; try {
}; return hljs.highlightAuto(str).value;
} catch (__) {}
function setOptionClass(name, val) { return '';
if (val) { };
$('body').addClass('opt_' + name);
} else {
$('body').removeClass('opt_' + name);
}
}
function setResultView(val) { function setOptionClass(name, val) {
$('body').removeClass('result-as-html'); if (val) {
$('body').removeClass('result-as-src'); $('body').addClass('opt_' + name);
$('body').removeClass('result-as-debug'); } else {
$('body').addClass('result-as-' + val); $('body').removeClass('opt_' + name);
defaults._view = val; }
}
function setResultView(val) {
$('body').removeClass('result-as-html');
$('body').removeClass('result-as-src');
$('body').removeClass('result-as-debug');
$('body').addClass('result-as-' + val);
defaults._view = val;
}
function mdInit() {
if (defaults._strict) {
mdHtml = window.markdownit('commonmark');
mdSrc = window.markdownit('commonmark');
} else {
mdHtml = window.markdownit(defaults)
.use(require('markdown-it-abbr'))
.use(require('markdown-it-container'), 'warning')
.use(require('markdown-it-deflist'))
.use(require('markdown-it-emoji'))
.use(require('markdown-it-footnote'))
.use(require('markdown-it-ins'))
.use(require('markdown-it-mark'))
.use(require('markdown-it-sub'))
.use(require('markdown-it-sup'));
mdSrc = window.markdownit(defaults)
.use(require('markdown-it-abbr'))
.use(require('markdown-it-container'), 'warning')
.use(require('markdown-it-deflist'))
.use(require('markdown-it-emoji'))
.use(require('markdown-it-footnote'))
.use(require('markdown-it-ins'))
.use(require('markdown-it-mark'))
.use(require('markdown-it-sub'))
.use(require('markdown-it-sup'));
} }
function mdInit() { // Beautify output of parser for html content
if (defaults._strict) { mdHtml.renderer.rules.table_open = function () {
mdHtml = window.markdownit('commonmark'); return '<table class="table table-striped">\n';
mdSrc = window.markdownit('commonmark'); };
} else { // Replace emoji codes with images
mdHtml = window.markdownit(defaults) mdHtml.renderer.rules.emoji = function(token, idx) {
.use(window.markdownitAbbr) return window.twemoji.parse(token[idx].content);
.use(window.markdownitContainer, 'warning') };
.use(window.markdownitDeflist)
.use(window.markdownitEmoji)
.use(window.markdownitFootnote)
.use(window.markdownitIns)
.use(window.markdownitMark)
.use(window.markdownitSub)
.use(window.markdownitSup);
mdSrc = window.markdownit(defaults)
.use(window.markdownitAbbr)
.use(window.markdownitContainer, 'warning')
.use(window.markdownitDeflist)
.use(window.markdownitEmoji)
.use(window.markdownitFootnote)
.use(window.markdownitIns)
.use(window.markdownitMark)
.use(window.markdownitSub)
.use(window.markdownitSup);
}
// Beautify output of parser for html content //
mdHtml.renderer.rules.table_open = function () { // Inject line numbers for sync scroll. Notes:
return '<table class="table table-striped">\n'; //
}; // - We track only headings and paragraphs on first level. That's enough.
// Replace emoji codes with images // - Footnotes content causes jumps. Level limit filter it automatically.
mdHtml.renderer.rules.emoji = function(token, idx) { function injectLineNumbers(tokens, idx, options, env, self) {
return window.twemoji.parse(token[idx].content); var line;
}; if (tokens[idx].map && tokens[idx].level === 0) {
line = tokens[idx].map[0];
// tokens[idx].attrPush([ 'class', 'line' ]);
// Inject line numbers for sync scroll. Notes: tokens[idx].attrPush([ 'data-line', String(line) ]);
//
// - We track only headings and paragraphs on first level. That's enough.
// - Footnotes content causes jumps. Level limit filter it automatically.
function injectLineNumbers(tokens, idx, options, env, self) {
var line;
if (tokens[idx].map && tokens[idx].level === 0) {
line = tokens[idx].map[0];
tokens[idx].attrPush([ 'class', 'line' ]);
tokens[idx].attrPush([ 'data-line', String(line) ]);
}
return self.renderToken(tokens, idx, options, env, self);
} }
return self.renderToken(tokens, idx, options, env, self);
mdHtml.renderer.rules.paragraph_open = mdHtml.renderer.rules.heading_open = injectLineNumbers;
} }
function setHighlightedlContent(selector, content, lang) { mdHtml.renderer.rules.paragraph_open = mdHtml.renderer.rules.heading_open = injectLineNumbers;
if (window.hljs) { }
$(selector).html(window.hljs.highlight(lang, content).value);
} else { function setHighlightedlContent(selector, content, lang) {
$(selector).text(content); if (window.hljs) {
} $(selector).html(window.hljs.highlight(lang, content).value);
} else {
$(selector).text(content);
} }
}
function updateResult() { function updateResult() {
var source = $('.source').val(); var source = $('.source').val();
// Update only active view to avoid slowdowns // Update only active view to avoid slowdowns
// (debug & src view with highlighting are a bit slow) // (debug & src view with highlighting are a bit slow)
if (defaults._view === 'src') { if (defaults._view === 'src') {
setHighlightedlContent('.result-src-content', mdSrc.render(source), 'html'); setHighlightedlContent('.result-src-content', mdSrc.render(source), 'html');
} else if (defaults._view === 'debug') { } else if (defaults._view === 'debug') {
setHighlightedlContent( setHighlightedlContent(
'.result-debug-content', '.result-debug-content',
JSON.stringify(mdSrc.parse(source, { references: {} }), null, 2), JSON.stringify(mdSrc.parse(source, { references: {} }), null, 2),
'json' 'json'
); );
} else { /*defaults._view === 'html'*/ } else { /*defaults._view === 'html'*/
$('.result-html').html(mdHtml.render(source)); $('.result-html').html(mdHtml.render(source));
} }
// reset lines mapping cache on content update // reset lines mapping cache on content update
scrollMap = null; scrollMap = null;
try { try {
if (source) { if (source) {
// serialize state - source and options // serialize state - source and options
permalink.href = '#md64=' + window.btoa(JSON.stringify({ permalink.href = '#md64=' + window.btoa(JSON.stringify({
source: source, source: source,
defaults: _.omit(defaults, 'highlight') defaults: _.omit(defaults, 'highlight')
})); }));
} else { } else {
permalink.href = '';
}
} catch (__) {
permalink.href = ''; permalink.href = '';
} }
} catch (__) {
permalink.href = '';
} }
}
// Build offsets for each line (lines can be wrapped)
// That's a bit dirty to process each line everytime, but ok for demo.
// Optimizations are required only for big texts.
function buildScrollMap() {
var i, offset, nonEmptyList, pos, a, b, lineHeightMap, linesCount,
acc, sourceLikeDiv, textarea = $('.source'),
_scrollMap;
sourceLikeDiv = $('<div />').css({
position: 'absolute',
visibility: 'hidden',
height: 'auto',
width: textarea[0].clientWidth,
'font-size': textarea.css('font-size'),
'font-family': textarea.css('font-family'),
'line-height': textarea.css('line-height'),
'white-space': textarea.css('white-space')
}).appendTo('body');
offset = $('.result-html').scrollTop() - $('.result-html').offset().top;
_scrollMap = [];
nonEmptyList = [];
lineHeightMap = [];
acc = 0;
textarea.val().split('\n').forEach(function(str) {
var h, lh;
// Build offsets for each line (lines can be wrapped)
// That's a bit dirty to process each line everytime, but ok for demo.
// Optimizations are required only for big texts.
function buildScrollMap() {
var i, offset, nonEmptyList, pos, a, b, lineHeightMap, linesCount,
acc, sourceLikeDiv, textarea = $('.source'),
_scrollMap;
sourceLikeDiv = $('<div />').css({
position: 'absolute',
visibility: 'hidden',
height: 'auto',
width: textarea[0].clientWidth,
'font-size': textarea.css('font-size'),
'font-family': textarea.css('font-family'),
'line-height': textarea.css('line-height'),
'white-space': textarea.css('white-space')
}).appendTo('body');
offset = $('.result-html').scrollTop() - $('.result-html').offset().top;
_scrollMap = [];
nonEmptyList = [];
lineHeightMap = [];
acc = 0;
textarea.val().split('\n').forEach(function(str) {
var h, lh;
lineHeightMap.push(acc);
if (str.length === 0) {
acc++;
return;
}
sourceLikeDiv.text(str);
h = parseFloat(sourceLikeDiv.css('height'));
lh = parseFloat(sourceLikeDiv.css('line-height'));
acc += Math.round(h / lh);
});
sourceLikeDiv.remove();
lineHeightMap.push(acc); lineHeightMap.push(acc);
linesCount = acc;
for (i = 0; i < linesCount; i++) { _scrollMap.push(-1); } if (str.length === 0) {
acc++;
return;
}
nonEmptyList.push(0); sourceLikeDiv.text(str);
_scrollMap[0] = 0; h = parseFloat(sourceLikeDiv.css('height'));
lh = parseFloat(sourceLikeDiv.css('line-height'));
acc += Math.round(h / lh);
});
sourceLikeDiv.remove();
lineHeightMap.push(acc);
linesCount = acc;
$('.line').each(function(n, el) { for (i = 0; i < linesCount; i++) { _scrollMap.push(-1); }
var $el = $(el), t = $el.data('line');
if (t === '') { return; }
t = lineHeightMap[t];
if (t !== 0) { nonEmptyList.push(t); }
_scrollMap[t] = Math.round($el.offset().top + offset);
});
nonEmptyList.push(linesCount); nonEmptyList.push(0);
_scrollMap[linesCount] = $('.result-html')[0].scrollHeight; _scrollMap[0] = 0;
pos = 0; $('.line').each(function(n, el) {
for (i = 1; i < linesCount; i++) { var $el = $(el), t = $el.data('line');
if (_scrollMap[i] !== -1) { if (t === '') { return; }
pos++; t = lineHeightMap[t];
continue; if (t !== 0) { nonEmptyList.push(t); }
} _scrollMap[t] = Math.round($el.offset().top + offset);
});
a = nonEmptyList[pos]; nonEmptyList.push(linesCount);
b = nonEmptyList[pos + 1]; _scrollMap[linesCount] = $('.result-html')[0].scrollHeight;
_scrollMap[i] = Math.round((_scrollMap[b] * (i - a) + _scrollMap[a] * (b - i)) / (b - a));
pos = 0;
for (i = 1; i < linesCount; i++) {
if (_scrollMap[i] !== -1) {
pos++;
continue;
} }
return _scrollMap; a = nonEmptyList[pos];
b = nonEmptyList[pos + 1];
_scrollMap[i] = Math.round((_scrollMap[b] * (i - a) + _scrollMap[a] * (b - i)) / (b - a));
} }
// Synchronize scroll position from source to result return _scrollMap;
var syncResultScroll = _.debounce(function () { }
var textarea = $('.source'),
lineHeight = parseFloat(textarea.css('line-height')), // Synchronize scroll position from source to result
lineNo, posTo; var syncResultScroll = _.debounce(function () {
var textarea = $('.source'),
lineNo = Math.floor(textarea.scrollTop() / lineHeight); lineHeight = parseFloat(textarea.css('line-height')),
if (!scrollMap) { scrollMap = buildScrollMap(); } lineNo, posTo;
posTo = scrollMap[lineNo];
$('.result-html').stop(true).animate({ lineNo = Math.floor(textarea.scrollTop() / lineHeight);
scrollTop: posTo if (!scrollMap) { scrollMap = buildScrollMap(); }
}, 100, 'linear'); posTo = scrollMap[lineNo];
}, 50, { maxWait: 50 }); $('.result-html').stop(true).animate({
scrollTop: posTo
// Synchronize scroll position from result to source }, 100, 'linear');
var syncSrcScroll = _.debounce(function () { }, 50, { maxWait: 50 });
var resultHtml = $('.result-html'),
scrollTop = resultHtml.scrollTop(), // Synchronize scroll position from result to source
textarea = $('.source'), var syncSrcScroll = _.debounce(function () {
lineHeight = parseFloat(textarea.css('line-height')), var resultHtml = $('.result-html'),
lines, scrollTop = resultHtml.scrollTop(),
i, textarea = $('.source'),
line; lineHeight = parseFloat(textarea.css('line-height')),
lines,
if (!scrollMap) { scrollMap = buildScrollMap(); } i,
line;
lines = Object.keys(scrollMap);
if (!scrollMap) { scrollMap = buildScrollMap(); }
if (lines.length < 1) {
return; lines = Object.keys(scrollMap);
}
if (lines.length < 1) {
line = lines[0]; return;
}
for (i = 1; i < lines.length; i++) { line = lines[0];
if (scrollMap[lines[i]] < scrollTop) {
line = lines[i];
continue;
}
break; for (i = 1; i < lines.length; i++) {
if (scrollMap[lines[i]] < scrollTop) {
line = lines[i];
continue;
} }
textarea.stop(true).animate({ break;
scrollTop: lineHeight * line }
}, 100, 'linear');
}, 50, { maxWait: 50 });
////////////////////////////////////////////////////////////////////////////// textarea.stop(true).animate({
// Init on page load scrollTop: lineHeight * line
// }, 100, 'linear');
$(function() { }, 50, { maxWait: 50 });
// highlight snippet
if (window.hljs) { //////////////////////////////////////////////////////////////////////////////
$('pre.code-sample code').each(function(i, block) { // Init on page load
window.hljs.highlightBlock(block); //
}); $(function() {
} // highlight snippet
if (window.hljs) {
$('pre.code-sample code').each(function(i, block) {
window.hljs.highlightBlock(block);
});
}
// Restore content if opened by permalink // Restore content if opened by permalink
if (location.hash && /^(#md=|#md64=)/.test(location.hash)) { if (location.hash && /^(#md=|#md64=)/.test(location.hash)) {
try { try {
var cfg; var cfg;
if (/^#md64=/.test(location.hash)) {
cfg = JSON.parse(window.atob(location.hash.slice(6)));
} else {
// Legacy mode for old links. Those become broken in github posts,
// so we switched to base64 encoding.
cfg = JSON.parse(decodeURIComponent(location.hash.slice(4)));
}
if (_.isString(cfg.source)) { if (/^#md64=/.test(location.hash)) {
$('.source').val(cfg.source); cfg = JSON.parse(window.atob(location.hash.slice(6)));
} } else {
// Legacy mode for old links. Those become broken in github posts,
// so we switched to base64 encoding.
cfg = JSON.parse(decodeURIComponent(location.hash.slice(4)));
}
var opts = _.isObject(cfg.defaults) ? cfg.defaults : {}; if (_.isString(cfg.source)) {
$('.source').val(cfg.source);
}
// copy config to defaults, but only if key exists var opts = _.isObject(cfg.defaults) ? cfg.defaults : {};
// and value has the same type
_.forOwn(opts, function (val, key) {
if (!_.has(defaults, key)) { return; }
// Legacy, for old links // copy config to defaults, but only if key exists
if (key === '_src') { // and value has the same type
defaults._view = val ? 'src' : 'html'; _.forOwn(opts, function (val, key) {
return; if (!_.has(defaults, key)) { return; }
}
if ((_.isBoolean(defaults[key]) && _.isBoolean(val)) || // Legacy, for old links
(_.isString(defaults[key]) && _.isString(val))) { if (key === '_src') {
defaults[key] = val; defaults._view = val ? 'src' : 'html';
} return;
}); }
// sanitize for sure if ((_.isBoolean(defaults[key]) && _.isBoolean(val)) ||
if ([ 'html', 'src', 'debug' ].indexOf(defaults._view) === -1) { (_.isString(defaults[key]) && _.isString(val))) {
defaults._view = 'html'; defaults[key] = val;
} }
} catch (__) {} });
}
// Activate tooltips // sanitize for sure
$('._tip').tooltip({ container: 'body' }); if ([ 'html', 'src', 'debug' ].indexOf(defaults._view) === -1) {
defaults._view = 'html';
}
} catch (__) {}
}
// Set default option values and option listeners // Activate tooltips
_.forOwn(defaults, function (val, key) { $('._tip').tooltip({ container: 'body' });
if (key === 'highlight') { return; }
var el = document.getElementById(key); // Set default option values and option listeners
_.forOwn(defaults, function (val, key) {
if (key === 'highlight') { return; }
if (!el) { return; } var el = document.getElementById(key);
var $el = $(el); if (!el) { return; }
if (_.isBoolean(val)) { var $el = $(el);
$el.prop('checked', val);
$el.on('change', function () {
var value = Boolean($el.prop('checked'));
setOptionClass(key, value);
defaults[key] = value;
mdInit();
updateResult();
});
setOptionClass(key, val);
} else { if (_.isBoolean(val)) {
$(el).val(val); $el.prop('checked', val);
$el.on('change update keyup', function () { $el.on('change', function () {
defaults[key] = String($(el).val()); var value = Boolean($el.prop('checked'));
mdInit(); setOptionClass(key, value);
updateResult(); defaults[key] = value;
}); mdInit();
} updateResult();
}); });
setOptionClass(key, val);
} else {
$(el).val(val);
$el.on('change update keyup', function () {
defaults[key] = String($(el).val());
mdInit();
updateResult();
});
}
});
setResultView(defaults._view); setResultView(defaults._view);
mdInit(); mdInit();
permalink = document.getElementById('permalink'); permalink = document.getElementById('permalink');
// Setup listeners // Setup listeners
$('.source').on('keyup paste cut mouseup', _.debounce(updateResult, 300, { maxWait: 500 })); $('.source').on('keyup paste cut mouseup', _.debounce(updateResult, 300, { maxWait: 500 }));
$('.source').on('touchstart mouseover', function () { $('.source').on('touchstart mouseover', function () {
$('.result-html').off('scroll'); $('.result-html').off('scroll');
$('.source').on('scroll', syncResultScroll); $('.source').on('scroll', syncResultScroll);
}); });
$('.result-html').on('touchstart mouseover', function () { $('.result-html').on('touchstart mouseover', function () {
$('.source').off('scroll'); $('.source').off('scroll');
$('.result-html').on('scroll', syncSrcScroll); $('.result-html').on('scroll', syncSrcScroll);
}); });
$('.source-clear').on('click', function (event) {
$('.source').val('');
updateResult();
event.preventDefault();
});
$('.source-clear').on('click', function (event) { $(document).on('click', '[data-result-as]', function (event) {
$('.source').val(''); var view = $(this).data('resultAs');
if (view) {
setResultView(view);
// only to update permalink
updateResult(); updateResult();
event.preventDefault(); event.preventDefault();
}); }
});
$(document).on('click', '[data-result-as]', function (event) {
var view = $(this).data('resultAs');
if (view) {
setResultView(view);
// only to update permalink
updateResult();
event.preventDefault();
}
});
// Need to recalculate line positions on window resize
$(window).on('resize', function () {
scrollMap = null;
});
updateResult(); // Need to recalculate line positions on window resize
$(window).on('resize', function () {
scrollMap = null;
}); });
})();
updateResult();
});

Loading…
Cancel
Save