markmap-lib
Advanced tools
Comparing version 0.6.3 to 0.7.0
@@ -13,2 +13,3 @@ #!/usr/bin/env node | ||
.option('--enable-mathjax', 'enable MathJax support') | ||
.option('--enable-prism', 'enable PrismJS support') | ||
.option('--no-open', 'do not open the output file after generation') | ||
@@ -21,2 +22,3 @@ .action((input, cmd) => { | ||
mathJax: cmd.enableMathjax, | ||
prism: cmd.enablePrism, | ||
}); | ||
@@ -23,0 +25,0 @@ }); |
@@ -1,187 +0,24 @@ | ||
/*! markmap-lib v0.6.3 | MIT License */ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
exports.__esModule = true; | ||
exports.createMarkmap = createMarkmap; | ||
var fs = require('fs'); | ||
var open = _interopDefault(require('open')); | ||
var remarkable = require('remarkable'); | ||
var util = require('./util'); | ||
var template = require('./template'); | ||
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); | ||
const md = new remarkable.Remarkable(); | ||
md.block.ruler.enable(['deflist']); | ||
var _fs = require("fs"); | ||
function extractInline(token) { | ||
const html = []; | ||
let style = {}; | ||
var _open = _interopRequireDefault(require("open")); | ||
for (const child of token.children) { | ||
if (child.type === 'text') { | ||
html.push(util.wrapStyle(util.escapeHtml(child.content), style)); | ||
} else if (child.type === 'code') { | ||
html.push(util.wrapHtml('code', util.wrapStyle(util.escapeHtml(child.content), style))); | ||
} else if (child.type === 'softbreak') { | ||
html.push('<br/>'); | ||
} else if (child.type.endsWith('_open')) { | ||
const type = child.type.slice(0, -5); | ||
var _transform = require("./transform"); | ||
if (type === 'link') { | ||
html.push(util.htmlOpen('a', { | ||
href: child.href, | ||
title: child.title, | ||
target: '_blank', | ||
rel: 'noopener noreferrer' | ||
})); | ||
} else { | ||
style = Object.assign({}, style, { | ||
[type]: true | ||
}); | ||
} | ||
} else if (child.type.endsWith('_close')) { | ||
const type = child.type.slice(0, -6); | ||
var _template = require("./template"); | ||
if (type === 'link') { | ||
html.push(util.htmlClose('a')); | ||
} else { | ||
style = Object.assign({}, style, { | ||
[type]: false | ||
}); | ||
} | ||
} | ||
} | ||
return html.join(''); | ||
} | ||
function cleanNode(node, depth = 0) { | ||
if (node.t === 'heading') { | ||
// drop all paragraphs | ||
node.c = node.c.filter(item => item.t !== 'paragraph'); | ||
} else if (node.t === 'list_item') { | ||
var _node$p; | ||
// keep first paragraph as content of list_item, drop others | ||
node.c = node.c.filter(item => { | ||
if (item.t === 'paragraph') { | ||
if (!node.v) node.v = item.v; | ||
return false; | ||
} | ||
return true; | ||
}); | ||
if (((_node$p = node.p) == null ? void 0 : _node$p.index) != null) { | ||
node.v = `${node.p.index}. ${node.v}`; | ||
} | ||
} else if (node.t === 'ordered_list') { | ||
var _node$p$start, _node$p2; | ||
let index = (_node$p$start = (_node$p2 = node.p) == null ? void 0 : _node$p2.start) != null ? _node$p$start : 1; | ||
node.c.forEach(item => { | ||
if (item.t === 'list_item') { | ||
item.p = Object.assign({}, item.p, { | ||
index: index | ||
}); | ||
index += 1; | ||
} | ||
}); | ||
} | ||
if (node.c.length === 0) { | ||
delete node.c; | ||
} else { | ||
if (node.c.length === 1 && !node.c[0].v) { | ||
node.c = node.c[0].c; | ||
} | ||
node.c.forEach(child => cleanNode(child, depth + 1)); | ||
} | ||
node.d = depth; | ||
delete node.p; | ||
} | ||
function buildTree(tokens) { | ||
// TODO deal with <dl><dt> | ||
const root = { | ||
t: 'root', | ||
d: 0, | ||
v: '', | ||
c: [] | ||
}; | ||
const stack = [root]; | ||
let depth = 0; | ||
for (const token of tokens) { | ||
let current = stack[stack.length - 1]; | ||
if (token.type.endsWith('_open')) { | ||
const type = token.type.slice(0, -5); | ||
const payload = {}; | ||
if (type === 'heading') { | ||
depth = token.hLevel; | ||
while (((_current = current) == null ? void 0 : _current.d) >= depth) { | ||
var _current; | ||
stack.pop(); | ||
current = stack[stack.length - 1]; | ||
} | ||
} else { | ||
var _current2; | ||
depth = Math.max(depth, ((_current2 = current) == null ? void 0 : _current2.d) || 0) + 1; | ||
if (type === 'ordered_list') { | ||
payload.start = token.order; | ||
} | ||
} | ||
const item = { | ||
t: type, | ||
d: depth, | ||
p: payload, | ||
v: '', | ||
c: [] | ||
}; | ||
current.c.push(item); | ||
stack.push(item); | ||
} else if (!current) { | ||
continue; | ||
} else if (token.type === `${current.t}_close`) { | ||
if (current.t === 'heading') { | ||
depth = current.d; | ||
} else { | ||
stack.pop(); | ||
depth = 0; | ||
} | ||
} else if (token.type === 'inline') { | ||
current.v = `${current.v || ''}${extractInline(token)}`; | ||
} else if (token.type === 'fence') { | ||
current.v = `<pre><code class="language-${token.params}">${util.escapeHtml(token.content)}</code></pre>`; | ||
} | ||
} | ||
return root; | ||
} | ||
function transform(content) { | ||
var _root$c; | ||
const tokens = md.parse(content || '', {}); | ||
let root = buildTree(tokens); | ||
cleanNode(root); | ||
if (((_root$c = root.c) == null ? void 0 : _root$c.length) === 1) root = root.c[0]; | ||
return root; | ||
} | ||
async function createMarkmap(options = {}) { | ||
const { | ||
input, | ||
open: openFile = true, | ||
mathJax = false | ||
} = options; | ||
open: openFile = true | ||
} = options, | ||
rest = (0, _objectWithoutPropertiesLoose2.default)(options, ["input", "open"]); | ||
let { | ||
@@ -193,3 +30,3 @@ content, | ||
if (input) { | ||
content = await fs.promises.readFile(input, 'utf8'); | ||
content = await _fs.promises.readFile(input, 'utf8'); | ||
} | ||
@@ -201,10 +38,8 @@ | ||
const root = transform(content || ''); | ||
const html = template.fillTemplate(root, { | ||
mathJax | ||
}); | ||
fs.promises.writeFile(output, html, 'utf8'); | ||
if (openFile) open(output); | ||
} | ||
const root = (0, _transform.transform)(content || ''); | ||
const html = (0, _template.fillTemplate)(root, rest); | ||
exports.createMarkmap = createMarkmap; | ||
_fs.promises.writeFile(output, html, 'utf8'); | ||
if (openFile) (0, _open.default)(output); | ||
} |
@@ -1,50 +0,45 @@ | ||
/*! markmap-lib v0.6.3 | MIT License */ | ||
'use strict'; | ||
"use strict"; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.__esModule = true; | ||
exports.fillTemplate = fillTemplate; | ||
var util = require('./util'); | ||
var _util = require("./util"); | ||
const template = "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n<title>Markmap</title>\n<style>\n* {\n margin: 0;\n padding: 0;\n}\n#mindmap {\n display: block;\n width: 100vw;\n height: 100vh;\n}\n</style>\n<!--JS-->\n</head>\n<body>\n<svg id=\"mindmap\"></svg>\n<script>markmap.markmap('svg#mindmap',{/*extra*/}).fit()</script>\n</body>\n</html>\n"; | ||
const js = [{ | ||
src: 'https://cdn.jsdelivr.net/npm/d3@5' | ||
}, { | ||
src: 'https://cdn.jsdelivr.net/npm/markmap-lib@0.6.3/dist/view.min.js' | ||
}]; | ||
var _plugins = require("./plugins"); | ||
function buildCode(fn, ...args) { | ||
const params = args.map(arg => JSON.stringify(arg != null ? arg : null)).join(','); | ||
return `(${fn.toString()})(${params})`; | ||
} | ||
const template = "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n<title>Markmap</title>\n<style>\n* {\n margin: 0;\n padding: 0;\n}\n#mindmap {\n display: block;\n width: 100vw;\n height: 100vh;\n}\n</style>\n<!--CSS-->\n</head>\n<body>\n<svg id=\"mindmap\"></svg>\n<!--JS-->\n</body>\n</html>\n"; | ||
const baseJs = ['https://cdn.jsdelivr.net/npm/d3@5', 'https://cdn.jsdelivr.net/npm/markmap-lib@0.7.0/dist/browser/view.min.js'].map(src => ({ | ||
type: 'script', | ||
data: { | ||
src | ||
} | ||
})); | ||
function fillTemplate(data, opts) { | ||
const jsList = [...js]; | ||
const extra = [JSON.stringify(data)]; | ||
if (opts == null ? void 0 : opts.mathJax) { | ||
jsList.push(buildCode(mathJax => { | ||
mathJax = Object.assign({}, mathJax); | ||
mathJax.options = Object.assign({}, mathJax.options, { | ||
skipHtmlTags: { | ||
'[-]': ['code', 'pre'] | ||
} | ||
}); | ||
window.MathJax = mathJax; | ||
}, opts.mathJax), { | ||
src: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js' | ||
}); | ||
extra.push(buildCode(() => ({ | ||
processHtml: nodes => { | ||
var _MathJax$typeset, _MathJax; | ||
(_MathJax$typeset = (_MathJax = window.MathJax).typeset) == null ? void 0 : _MathJax$typeset.call(_MathJax, nodes); | ||
} | ||
}))); | ||
} | ||
const jsStr = jsList.map(data => util.wrapHtml('script', typeof data === 'string' ? data : '', typeof data === 'string' ? null : data)).join(''); | ||
const html = template.replace('<!--JS-->', jsStr).replace('{/*extra*/}', extra.join(',')); | ||
const { | ||
js, | ||
css, | ||
processors | ||
} = (0, _util.persistPlugins)([(opts == null ? void 0 : opts.mathJax) && _plugins.mathJax, (opts == null ? void 0 : opts.prism) && _plugins.prism].filter(Boolean), opts); | ||
const jsList = [...(0, _util.persistJS)(baseJs), js, ...(0, _util.persistJS)([{ | ||
type: 'iife', | ||
data: { | ||
fn: (data, ...processors) => { | ||
const { | ||
markmap | ||
} = window; | ||
markmap.processors = processors; | ||
markmap.markmap('svg#mindmap', data); | ||
}, | ||
getParams: ({ | ||
data, | ||
processors | ||
}) => [data, ...processors] | ||
} | ||
}], { | ||
data, | ||
processors | ||
})]; | ||
const html = template.replace('<!--CSS-->', css).replace('<!--JS-->', jsList.join('')); | ||
return html; | ||
} | ||
exports.fillTemplate = fillTemplate; | ||
} |
618
dist/view.js
@@ -1,560 +0,18 @@ | ||
/*! markmap-lib v0.6.3 | MIT License */ | ||
(function (exports, d3) { | ||
'use strict'; | ||
"use strict"; | ||
function count(node) { | ||
var sum = 0, | ||
children = node.children, | ||
i = children && children.length; | ||
if (!i) sum = 1; | ||
else while (--i >= 0) sum += children[i].value; | ||
node.value = sum; | ||
} | ||
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); | ||
function node_count() { | ||
return this.eachAfter(count); | ||
} | ||
exports.__esModule = true; | ||
exports.loadPlugins = loadPlugins; | ||
exports.plugins = exports.markmap = void 0; | ||
function node_each(callback) { | ||
var node = this, current, next = [node], children, i, n; | ||
do { | ||
current = next.reverse(), next = []; | ||
while (node = current.pop()) { | ||
callback(node), children = node.children; | ||
if (children) for (i = 0, n = children.length; i < n; ++i) { | ||
next.push(children[i]); | ||
} | ||
} | ||
} while (next.length); | ||
return this; | ||
} | ||
var d3 = _interopRequireWildcard(require("d3")); | ||
function node_eachBefore(callback) { | ||
var node = this, nodes = [node], children, i; | ||
while (node = nodes.pop()) { | ||
callback(node), children = node.children; | ||
if (children) for (i = children.length - 1; i >= 0; --i) { | ||
nodes.push(children[i]); | ||
} | ||
} | ||
return this; | ||
} | ||
var _d3Flextree = require("d3-flextree"); | ||
function node_eachAfter(callback) { | ||
var node = this, nodes = [node], next = [], children, i, n; | ||
while (node = nodes.pop()) { | ||
next.push(node), children = node.children; | ||
if (children) for (i = 0, n = children.length; i < n; ++i) { | ||
nodes.push(children[i]); | ||
} | ||
} | ||
while (node = next.pop()) { | ||
callback(node); | ||
} | ||
return this; | ||
} | ||
var _util = require("./util"); | ||
function node_sum(value) { | ||
return this.eachAfter(function(node) { | ||
var sum = +value(node.data) || 0, | ||
children = node.children, | ||
i = children && children.length; | ||
while (--i >= 0) sum += children[i].value; | ||
node.value = sum; | ||
}); | ||
} | ||
var plugins = _interopRequireWildcard(require("./plugins")); | ||
function node_sort(compare) { | ||
return this.eachBefore(function(node) { | ||
if (node.children) { | ||
node.children.sort(compare); | ||
} | ||
}); | ||
} | ||
function node_path(end) { | ||
var start = this, | ||
ancestor = leastCommonAncestor(start, end), | ||
nodes = [start]; | ||
while (start !== ancestor) { | ||
start = start.parent; | ||
nodes.push(start); | ||
} | ||
var k = nodes.length; | ||
while (end !== ancestor) { | ||
nodes.splice(k, 0, end); | ||
end = end.parent; | ||
} | ||
return nodes; | ||
} | ||
function leastCommonAncestor(a, b) { | ||
if (a === b) return a; | ||
var aNodes = a.ancestors(), | ||
bNodes = b.ancestors(), | ||
c = null; | ||
a = aNodes.pop(); | ||
b = bNodes.pop(); | ||
while (a === b) { | ||
c = a; | ||
a = aNodes.pop(); | ||
b = bNodes.pop(); | ||
} | ||
return c; | ||
} | ||
function node_ancestors() { | ||
var node = this, nodes = [node]; | ||
while (node = node.parent) { | ||
nodes.push(node); | ||
} | ||
return nodes; | ||
} | ||
function node_descendants() { | ||
var nodes = []; | ||
this.each(function(node) { | ||
nodes.push(node); | ||
}); | ||
return nodes; | ||
} | ||
function node_leaves() { | ||
var leaves = []; | ||
this.eachBefore(function(node) { | ||
if (!node.children) { | ||
leaves.push(node); | ||
} | ||
}); | ||
return leaves; | ||
} | ||
function node_links() { | ||
var root = this, links = []; | ||
root.each(function(node) { | ||
if (node !== root) { // Don’t include the root’s parent, if any. | ||
links.push({source: node.parent, target: node}); | ||
} | ||
}); | ||
return links; | ||
} | ||
function hierarchy(data, children) { | ||
var root = new Node(data), | ||
valued = +data.value && (root.value = data.value), | ||
node, | ||
nodes = [root], | ||
child, | ||
childs, | ||
i, | ||
n; | ||
if (children == null) children = defaultChildren; | ||
while (node = nodes.pop()) { | ||
if (valued) node.value = +node.data.value; | ||
if ((childs = children(node.data)) && (n = childs.length)) { | ||
node.children = new Array(n); | ||
for (i = n - 1; i >= 0; --i) { | ||
nodes.push(child = node.children[i] = new Node(childs[i])); | ||
child.parent = node; | ||
child.depth = node.depth + 1; | ||
} | ||
} | ||
} | ||
return root.eachBefore(computeHeight); | ||
} | ||
function node_copy() { | ||
return hierarchy(this).eachBefore(copyData); | ||
} | ||
function defaultChildren(d) { | ||
return d.children; | ||
} | ||
function copyData(node) { | ||
node.data = node.data.data; | ||
} | ||
function computeHeight(node) { | ||
var height = 0; | ||
do node.height = height; | ||
while ((node = node.parent) && (node.height < ++height)); | ||
} | ||
function Node(data) { | ||
this.data = data; | ||
this.depth = | ||
this.height = 0; | ||
this.parent = null; | ||
} | ||
Node.prototype = hierarchy.prototype = { | ||
constructor: Node, | ||
count: node_count, | ||
each: node_each, | ||
eachAfter: node_eachAfter, | ||
eachBefore: node_eachBefore, | ||
sum: node_sum, | ||
sort: node_sort, | ||
path: node_path, | ||
ancestors: node_ancestors, | ||
descendants: node_descendants, | ||
leaves: node_leaves, | ||
links: node_links, | ||
copy: node_copy | ||
}; | ||
var version = "2.1.1"; | ||
const defaults = Object.freeze({ | ||
children: data => data.children, | ||
nodeSize: node => node.data.size, | ||
spacing: 0, | ||
}); | ||
// Create a layout function with customizable options. Per D3-style, the | ||
// options can be set at any time using setter methods. The layout function | ||
// will compute the tree node positions based on the options in effect at the | ||
// time it is called. | ||
function flextree(options) { | ||
const opts = Object.assign({}, defaults, options); | ||
function accessor(name) { | ||
const opt = opts[name]; | ||
return typeof opt === 'function' ? opt : () => opt; | ||
} | ||
function layout(tree) { | ||
const wtree = wrap(getWrapper(), tree, node=>node.children); | ||
wtree.update(); | ||
return wtree.data; | ||
} | ||
function getFlexNode() { | ||
const nodeSize = accessor('nodeSize'); | ||
const spacing = accessor('spacing'); | ||
return class FlexNode extends hierarchy.prototype.constructor { | ||
constructor(data) { | ||
super(data); | ||
} | ||
copy() { | ||
const c = wrap(this.constructor, this, node=>node.children); | ||
c.each(node => node.data = node.data.data); | ||
return c; | ||
} | ||
get size() { return nodeSize(this); } | ||
spacing(oNode) { return spacing(this, oNode); } | ||
get nodes() { return this.descendants(); } | ||
get xSize() { return this.size[0]; } | ||
get ySize() { return this.size[1]; } | ||
get top() { return this.y; } | ||
get bottom() { return this.y + this.ySize; } | ||
get left() { return this.x - this.xSize / 2; } | ||
get right() { return this.x + this.xSize / 2; } | ||
get root() { | ||
const ancs = this.ancestors(); | ||
return ancs[ancs.length - 1]; | ||
} | ||
get numChildren() { | ||
return this.hasChildren ? this.children.length : 0; | ||
} | ||
get hasChildren() { return !this.noChildren; } | ||
get noChildren() { return this.children === null; } | ||
get firstChild() { | ||
return this.hasChildren ? this.children[0] : null; | ||
} | ||
get lastChild() { | ||
return this.hasChildren ? this.children[this.numChildren - 1] : null; | ||
} | ||
get extents() { | ||
return (this.children || []).reduce( | ||
(acc, kid) => FlexNode.maxExtents(acc, kid.extents), | ||
this.nodeExtents); | ||
} | ||
get nodeExtents() { | ||
return { | ||
top: this.top, | ||
bottom: this.bottom, | ||
left: this.left, | ||
right: this.right, | ||
}; | ||
} | ||
static maxExtents(e0, e1) { | ||
return { | ||
top: Math.min(e0.top, e1.top), | ||
bottom: Math.max(e0.bottom, e1.bottom), | ||
left: Math.min(e0.left, e1.left), | ||
right: Math.max(e0.right, e1.right), | ||
}; | ||
} | ||
}; | ||
} | ||
function getWrapper() { | ||
const FlexNode = getFlexNode(); | ||
const nodeSize = accessor('nodeSize'); | ||
const spacing = accessor('spacing'); | ||
return class extends FlexNode { | ||
constructor(data) { | ||
super(data); | ||
Object.assign(this, { | ||
x: 0, y: 0, | ||
relX: 0, prelim: 0, shift: 0, change: 0, | ||
lExt: this, lExtRelX: 0, lThr: null, | ||
rExt: this, rExtRelX: 0, rThr: null, | ||
}); | ||
} | ||
get size() { return nodeSize(this.data); } | ||
spacing(oNode) { return spacing(this.data, oNode.data); } | ||
get x() { return this.data.x; } | ||
set x(v) { this.data.x = v; } | ||
get y() { return this.data.y; } | ||
set y(v) { this.data.y = v; } | ||
update() { | ||
layoutChildren(this); | ||
resolveX(this); | ||
return this; | ||
} | ||
}; | ||
} | ||
function wrap(FlexClass, treeData, children) { | ||
const _wrap = (data, parent) => { | ||
const node = new FlexClass(data); | ||
Object.assign(node, { | ||
parent, | ||
depth: parent === null ? 0 : parent.depth + 1, | ||
height: 0, | ||
length: 1, | ||
}); | ||
const kidsData = children(data) || []; | ||
node.children = kidsData.length === 0 ? null | ||
: kidsData.map(kd => _wrap(kd, node)); | ||
if (node.children) { | ||
Object.assign(node, node.children.reduce( | ||
(hl, kid) => ({ | ||
height: Math.max(hl.height, kid.height + 1), | ||
length: hl.length + kid.length, | ||
}), node | ||
)); | ||
} | ||
return node; | ||
}; | ||
return _wrap(treeData, null); | ||
} | ||
Object.assign(layout, { | ||
nodeSize(arg) { | ||
return arguments.length ? (opts.nodeSize = arg, layout) : opts.nodeSize; | ||
}, | ||
spacing(arg) { | ||
return arguments.length ? (opts.spacing = arg, layout) : opts.spacing; | ||
}, | ||
children(arg) { | ||
return arguments.length ? (opts.children = arg, layout) : opts.children; | ||
}, | ||
hierarchy(treeData, children) { | ||
const kids = typeof children === 'undefined' ? opts.children : children; | ||
return wrap(getFlexNode(), treeData, kids); | ||
}, | ||
dump(tree) { | ||
const nodeSize = accessor('nodeSize'); | ||
const _dump = i0 => node => { | ||
const i1 = i0 + ' '; | ||
const i2 = i0 + ' '; | ||
const {x, y} = node; | ||
const size = nodeSize(node); | ||
const kids = (node.children || []); | ||
const kdumps = (kids.length === 0) ? ' ' : | ||
`,${i1}children: [${i2}${kids.map(_dump(i2)).join(i2)}${i1}],${i0}`; | ||
return `{ size: [${size.join(', ')}],${i1}x: ${x}, y: ${y}${kdumps}},`; | ||
}; | ||
return _dump('\n')(tree); | ||
}, | ||
}); | ||
return layout; | ||
} | ||
flextree.version = version; | ||
const layoutChildren = (w, y = 0) => { | ||
w.y = y; | ||
(w.children || []).reduce((acc, kid) => { | ||
const [i, lastLows] = acc; | ||
layoutChildren(kid, w.y + w.ySize); | ||
// The lowest vertical coordinate while extreme nodes still point | ||
// in current subtree. | ||
const lowY = (i === 0 ? kid.lExt : kid.rExt).bottom; | ||
if (i !== 0) separate(w, i, lastLows); | ||
const lows = updateLows(lowY, i, lastLows); | ||
return [i + 1, lows]; | ||
}, [0, null]); | ||
shiftChange(w); | ||
positionRoot(w); | ||
return w; | ||
}; | ||
// Resolves the relative coordinate properties - relX and prelim -- | ||
// to set the final, absolute x coordinate for each node. This also sets | ||
// `prelim` to 0, so that `relX` for each node is its x-coordinate relative | ||
// to its parent. | ||
const resolveX = (w, prevSum, parentX) => { | ||
// A call to resolveX without arguments is assumed to be for the root of | ||
// the tree. This will set the root's x-coord to zero. | ||
if (typeof prevSum === 'undefined') { | ||
prevSum = -w.relX - w.prelim; | ||
parentX = 0; | ||
} | ||
const sum = prevSum + w.relX; | ||
w.relX = sum + w.prelim - parentX; | ||
w.prelim = 0; | ||
w.x = parentX + w.relX; | ||
(w.children || []).forEach(k => resolveX(k, sum, w.x)); | ||
return w; | ||
}; | ||
// Process shift and change for all children, to add intermediate spacing to | ||
// each child's modifier. | ||
const shiftChange = w => { | ||
(w.children || []).reduce((acc, child) => { | ||
const [lastShiftSum, lastChangeSum] = acc; | ||
const shiftSum = lastShiftSum + child.shift; | ||
const changeSum = lastChangeSum + shiftSum + child.change; | ||
child.relX += changeSum; | ||
return [shiftSum, changeSum]; | ||
}, [0, 0]); | ||
}; | ||
// Separates the latest child from its previous sibling | ||
/* eslint-disable complexity */ | ||
const separate = (w, i, lows) => { | ||
const lSib = w.children[i - 1]; | ||
const curSubtree = w.children[i]; | ||
let rContour = lSib; | ||
let rSumMods = lSib.relX; | ||
let lContour = curSubtree; | ||
let lSumMods = curSubtree.relX; | ||
let isFirst = true; | ||
while (rContour && lContour) { | ||
if (rContour.bottom > lows.lowY) lows = lows.next; | ||
// How far to the left of the right side of rContour is the left side | ||
// of lContour? First compute the center-to-center distance, then add | ||
// the "spacing" | ||
const dist = | ||
(rSumMods + rContour.prelim) - (lSumMods + lContour.prelim) + | ||
rContour.xSize / 2 + lContour.xSize / 2 + | ||
rContour.spacing(lContour); | ||
if (dist > 0 || (dist < 0 && isFirst)) { | ||
lSumMods += dist; | ||
// Move subtree by changing relX. | ||
moveSubtree(curSubtree, dist); | ||
distributeExtra(w, i, lows.index, dist); | ||
} | ||
isFirst = false; | ||
// Advance highest node(s) and sum(s) of modifiers | ||
const rightBottom = rContour.bottom; | ||
const leftBottom = lContour.bottom; | ||
if (rightBottom <= leftBottom) { | ||
rContour = nextRContour(rContour); | ||
if (rContour) rSumMods += rContour.relX; | ||
} | ||
if (rightBottom >= leftBottom) { | ||
lContour = nextLContour(lContour); | ||
if (lContour) lSumMods += lContour.relX; | ||
} | ||
} | ||
// Set threads and update extreme nodes. In the first case, the | ||
// current subtree is taller than the left siblings. | ||
if (!rContour && lContour) setLThr(w, i, lContour, lSumMods); | ||
// In the next case, the left siblings are taller than the current subtree | ||
else if (rContour && !lContour) setRThr(w, i, rContour, rSumMods); | ||
}; | ||
/* eslint-enable complexity */ | ||
// Move subtree by changing relX. | ||
const moveSubtree = (subtree, distance) => { | ||
subtree.relX += distance; | ||
subtree.lExtRelX += distance; | ||
subtree.rExtRelX += distance; | ||
}; | ||
const distributeExtra = (w, curSubtreeI, leftSibI, dist) => { | ||
const curSubtree = w.children[curSubtreeI]; | ||
const n = curSubtreeI - leftSibI; | ||
// Are there intermediate children? | ||
if (n > 1) { | ||
const delta = dist / n; | ||
w.children[leftSibI + 1].shift += delta; | ||
curSubtree.shift -= delta; | ||
curSubtree.change -= dist - delta; | ||
} | ||
}; | ||
const nextLContour = w => { | ||
return w.hasChildren ? w.firstChild : w.lThr; | ||
}; | ||
const nextRContour = w => { | ||
return w.hasChildren ? w.lastChild : w.rThr; | ||
}; | ||
const setLThr = (w, i, lContour, lSumMods) => { | ||
const firstChild = w.firstChild; | ||
const lExt = firstChild.lExt; | ||
const curSubtree = w.children[i]; | ||
lExt.lThr = lContour; | ||
// Change relX so that the sum of modifier after following thread is correct. | ||
const diff = lSumMods - lContour.relX - firstChild.lExtRelX; | ||
lExt.relX += diff; | ||
// Change preliminary x coordinate so that the node does not move. | ||
lExt.prelim -= diff; | ||
// Update extreme node and its sum of modifiers. | ||
firstChild.lExt = curSubtree.lExt; | ||
firstChild.lExtRelX = curSubtree.lExtRelX; | ||
}; | ||
// Mirror image of setLThr. | ||
const setRThr = (w, i, rContour, rSumMods) => { | ||
const curSubtree = w.children[i]; | ||
const rExt = curSubtree.rExt; | ||
const lSib = w.children[i - 1]; | ||
rExt.rThr = rContour; | ||
const diff = rSumMods - rContour.relX - curSubtree.rExtRelX; | ||
rExt.relX += diff; | ||
rExt.prelim -= diff; | ||
curSubtree.rExt = lSib.rExt; | ||
curSubtree.rExtRelX = lSib.rExtRelX; | ||
}; | ||
// Position root between children, taking into account their modifiers | ||
const positionRoot = w => { | ||
if (w.hasChildren) { | ||
const k0 = w.firstChild; | ||
const kf = w.lastChild; | ||
const prelim = (k0.prelim + k0.relX - k0.xSize / 2 + | ||
kf.relX + kf.prelim + kf.xSize / 2 ) / 2; | ||
Object.assign(w, { | ||
prelim, | ||
lExt: k0.lExt, lExtRelX: k0.lExtRelX, | ||
rExt: kf.rExt, rExtRelX: kf.rExtRelX, | ||
}); | ||
} | ||
}; | ||
// Make/maintain a linked list of the indexes of left siblings and their | ||
// lowest vertical coordinate. | ||
const updateLows = (lowY, index, lastLows) => { | ||
// Remove siblings that are hidden by the new subtree. | ||
while (lastLows !== null && lowY >= lastLows.lowY) | ||
lastLows = lastLows.next; | ||
// Prepend the new subtree. | ||
return { | ||
lowY, | ||
index, | ||
next: lastLows, | ||
}; | ||
}; | ||
exports.plugins = plugins; | ||
const uniqId = Math.random().toString(36).slice(2, 8); | ||
@@ -626,3 +84,8 @@ let globalIndex = 0; | ||
function markmap(svg, data, opts) { | ||
const markmap = Object.assign(markmapCreate, { | ||
processors: [] | ||
}); | ||
exports.markmap = markmap; | ||
function markmapCreate(svg, data, opts) { | ||
svg = svg.datum ? svg : d3.select(svg); | ||
@@ -656,3 +119,3 @@ const styleNode = svg.append('style'); | ||
svg.call(zoom); | ||
return { | ||
const mm = { | ||
setData, | ||
@@ -662,2 +125,3 @@ setOptions, | ||
}; | ||
return mm; | ||
@@ -678,2 +142,3 @@ function getStyleContent() { | ||
.${state.id}-fo pre { margin: 0; } | ||
.${state.id}-fo pre[class*=language-] { padding: 0; } | ||
.${state.id}-g > g { cursor: pointer; } | ||
@@ -698,2 +163,4 @@ ${style ? style(state.id) : ''} | ||
function initializeData(node) { | ||
var _markmap$processors; | ||
let i = 0; | ||
@@ -725,2 +192,5 @@ let c = 0; | ||
walkTree(node, (item, next) => { | ||
var _item$c; | ||
item.c = (_item$c = item.c) == null ? void 0 : _item$c.map(child => Object.assign({}, child)); | ||
i += 1; | ||
@@ -732,3 +202,3 @@ options.color(`${c}`); // preload colors | ||
container.append(el); | ||
item.p = Object.assign({ | ||
item.p = Object.assign(Object.assign({}, item.p), {}, { | ||
// unique ID | ||
@@ -739,7 +209,14 @@ i, | ||
el | ||
}, item.p); | ||
}); | ||
next(); | ||
if (!colorDepth || item.d === colorDepth) c += 1; | ||
}); | ||
if (options.processHtml) options.processHtml(arrayFrom(container.childNodes)); | ||
if ((_markmap$processors = markmap.processors) == null ? void 0 : _markmap$processors.length) { | ||
const nodes = arrayFrom(container.childNodes); | ||
markmap.processors.forEach(processor => { | ||
processor(nodes, mm); | ||
}); | ||
} | ||
walkTree(node, (item, next, parent) => { | ||
@@ -765,6 +242,7 @@ var _parent$p; | ||
function setData(data, opts) { | ||
if (!data) data = Object.assign({}, state.data); | ||
state.data = data; | ||
initializeData(data); | ||
state.data = data; | ||
if (opts) setOptions(opts); | ||
renderData(data); | ||
renderData(); | ||
} | ||
@@ -804,3 +282,3 @@ | ||
} = d; | ||
data.p = Object.assign({}, data.p, { | ||
data.p = Object.assign(Object.assign({}, data.p), {}, { | ||
f: !((_data$p = data.p) == null ? void 0 : _data$p.f) | ||
@@ -818,3 +296,3 @@ }); | ||
} = options; | ||
const layout = flextree().children(d => { | ||
const layout = (0, _d3Flextree.flextree)().children(d => { | ||
var _d$p; | ||
@@ -844,3 +322,3 @@ | ||
if (options.autoFit) fit(); | ||
const origin = originData ? descendants.find(item => item.data === originData) : tree; | ||
const origin = originData && descendants.find(item => item.data === originData) || tree; | ||
const x0 = (_origin$data$x = origin.data.x0) != null ? _origin$data$x : origin.x; | ||
@@ -908,4 +386,16 @@ const y0 = (_origin$data$y = origin.data.y0) != null ? _origin$data$y : origin.y; // Update the nodes | ||
exports.markmap = markmap; | ||
async function loadPlugins(items, options) { | ||
items = items.map(item => { | ||
if (typeof item === 'string') { | ||
const name = item; | ||
item = plugins[name]; | ||
}(this.markmap = this.markmap || {}, d3)); | ||
if (!item) { | ||
console.warn(`[markmap] Unknown plugin: ${name}`); | ||
} | ||
} | ||
return item; | ||
}).filter(Boolean); | ||
markmap.processors = [...markmap.processors, ...(await (0, _util.initializePlugins)(items, options))]; | ||
} |
{ | ||
"name": "markmap-lib", | ||
"version": "0.6.3", | ||
"version": "0.7.0", | ||
"description": "Visualize your Markdown as mindmaps with Markmap", | ||
"author": "Gerald <i@gerald.top>", | ||
"license": "MIT", | ||
"husky": { | ||
"hooks": { | ||
"pre-push": "npm run lint" | ||
} | ||
}, | ||
"bin": { | ||
@@ -13,11 +18,6 @@ "markmap": "bin/cli.js" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-push": "npm run lint" | ||
} | ||
}, | ||
"scripts": { | ||
"dev": "rollup -wc rollup.conf.js", | ||
"clean": "del dist types", | ||
"build:js": "rollup -c rollup.conf.js", | ||
"dev": "gulp dev", | ||
"clean": "gulp clean", | ||
"build:js": "gulp build", | ||
"prebuild": "npm run ci && npm run clean", | ||
@@ -33,4 +33,4 @@ "prepublishOnly": "npm run build", | ||
"main": "dist/index.js", | ||
"unpkg": "dist/view.min.js", | ||
"jsdelivr": "dist/view.min.js", | ||
"unpkg": "dist/browser/view.min.js", | ||
"jsdelivr": "dist/browser/view.min.js", | ||
"files": [ | ||
@@ -47,19 +47,15 @@ "bin", | ||
"typings": "types/index.d.ts", | ||
"repository": "git@github.com:gera2ld/markmap-lib.git", | ||
"devDependencies": { | ||
"@babel/preset-typescript": "^7.9.0", | ||
"@gera2ld/plaid": "~1.5.0", | ||
"@rollup/plugin-alias": "^3.0.1", | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
"@rollup/plugin-json": "^4.0.2", | ||
"@rollup/plugin-node-resolve": "^7.1.1", | ||
"@rollup/plugin-replace": "^2.3.1", | ||
"@typescript-eslint/eslint-plugin": "^2.26.0", | ||
"@typescript-eslint/parser": "^2.26.0", | ||
"cross-env": "^7.0.2", | ||
"cssnano": "^4.1.10", | ||
"del-cli": "^3.0.0", | ||
"eslint": "^6.8.0", | ||
"husky": "^4.2.3", | ||
"rollup": "^2.3.1", | ||
"rollup-plugin-babel": "^4.4.0", | ||
"@gera2ld/plaid": "~2.0.0", | ||
"@gera2ld/plaid-rollup": "~2.0.0", | ||
"@typescript-eslint/eslint-plugin": "^2.30.0", | ||
"@typescript-eslint/parser": "^2.30.0", | ||
"del": "^5.1.0", | ||
"fancy-log": "^1.3.3", | ||
"gulp": "^4.0.2", | ||
"gulp-babel": "^8.0.0", | ||
"gulp-replace": "^1.0.0", | ||
"husky": "^4.2.5", | ||
"rollup-plugin-terser": "^5.3.0", | ||
@@ -69,11 +65,10 @@ "typescript": "^3.8.3" | ||
"dependencies": { | ||
"@babel/runtime": "^7.9.2", | ||
"@babel/runtime": "^7.9.6", | ||
"@types/d3": "^5.7.2", | ||
"commander": "^5.0.0", | ||
"d3": "^5.15.0", | ||
"commander": "^5.1.0", | ||
"d3": "^5.16.0", | ||
"d3-flextree": "^2.1.1", | ||
"open": "^7.0.3", | ||
"remarkable": "^2.0.0" | ||
}, | ||
"repository": "git@github.com:gera2ld/markmap-lib.git" | ||
} | ||
} |
@@ -11,5 +11,5 @@ # markmap-lib | ||
See [online demo](https://markmap.js.org/repl). | ||
[Try it out](https://markmap.js.org/repl). | ||
Requires Node.js >= 10. | ||
Node.js >= 10 is required. | ||
@@ -47,2 +47,3 @@ ## Usage | ||
--enable-mathjax enable MathJax support | ||
--enable-prism enable PrismJS support | ||
--no-open do not open the output file after generation | ||
@@ -52,3 +53,3 @@ -h, --help display help for command | ||
Suppose you have a Markdown file named `note.md`. | ||
Suppose we have a Markdown file named `note.md`. | ||
@@ -64,12 +65,4 @@ Run the following command to get an interactive mindmap: | ||
Then you will get a `note.html` in the same directory, and hopefully it will be open in your default browser. | ||
Then we get `note.html` in the same directory, and hopefully it will be open in your default browser. | ||
#### MathJax | ||
To enable MathJax support for your Markdown, pass `--enable-mathjax`: | ||
```sh | ||
$ markmap --enable-mathjax note.md | ||
``` | ||
### API | ||
@@ -90,3 +83,3 @@ | ||
```js | ||
import { transform } from 'markmap-lib/dist/transform.common'; | ||
import { transform } from 'markmap-lib/dist/transform'; | ||
@@ -111,3 +104,3 @@ const data = transform(markdown); | ||
```js | ||
import { markmap } from 'markmap-lib/dist/view.common'; | ||
import { markmap } from 'markmap-lib/dist/view'; | ||
@@ -121,36 +114,31 @@ markmap('#markmap', data); | ||
#### MathJax | ||
### Plugins | ||
To enable MathJax, you need to load MathJax before rendering markmap: | ||
- MathJax | ||
- PrismJS | ||
```html | ||
<script> | ||
window.MathJax = { | ||
options: { | ||
skipHtmlTags: { | ||
'[-]': ['code', 'pre'] | ||
} | ||
} | ||
}; | ||
</script> | ||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script> | ||
#### Command-line | ||
To enable plugins in command line, just add the related option, for example: | ||
```sh | ||
$ markmap note.md --enable-mathjax --enable-prism | ||
``` | ||
and process Html with MathJax in `options.processHtml`: | ||
#### API | ||
`loadPlugins` loads necessary CSS and JavaScript files. | ||
```js | ||
import { markmap } from 'markmap-lib/dist/view.common'; | ||
import { markmap, loadPlugins } from 'markmap-lib/dist/view'; | ||
markmap('#markmap', data, { | ||
processHtml: nodes => { | ||
if (window.MathJax.typeset) MathJax.typeset(nodes); | ||
}, | ||
loadPlugins([ | ||
'mathJax', | ||
'prism', | ||
]) | ||
.then(() => { | ||
markmap('#markmap', data); | ||
}); | ||
``` | ||
**Note**: | ||
- The `skipHtmlTags` option is required because inline code generated from Markdown is always wrapped in `<code>`, which is ignored by MathJax by default. | ||
- The MathJax library should better be loaded synchronously so that we can just use it in `options.processHtml` without a flash. | ||
## Related | ||
@@ -157,0 +145,0 @@ |
@@ -30,3 +30,2 @@ export interface IHierachy<T> { | ||
style?: (id: string) => string; | ||
processHtml?: (container: Node[]) => void; | ||
} | ||
@@ -41,1 +40,14 @@ export interface IMarkmapState { | ||
} | ||
export declare type JSItem = { | ||
type: 'script' | 'iife'; | ||
data: any; | ||
}; | ||
export declare type CSSItem = { | ||
type: 'style' | 'stylesheet'; | ||
data: any; | ||
}; | ||
export interface IMarkmapPlugin { | ||
styles: CSSItem[]; | ||
scripts: JSItem[]; | ||
transform: (nodes: any, mm: any) => void; | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
338907
13
29
8852
141
1
Updated@babel/runtime@^7.9.6
Updatedcommander@^5.1.0
Updatedd3@^5.16.0