@7polo/kityminder-core
Version:
KityMinder Core Implement
1,423 lines (1,401 loc) • 379 kB
JavaScript
/*!
* ====================================================
* Kity Minder Core - v1.4.54 - 2023-06-04
* https://github.com/fex-team/kityminder-core
* GitHub: https://github.com/fex-team/kityminder-core.git
* Copyright (c) 2023 Baidu FEX; Licensed BSD-3-Clause
* ====================================================
*/
(function () {
var _p = {
r: function(index) {
if (_p[index].inited) {
return _p[index].value;
}
if (typeof _p[index].value === "function") {
var module = {
exports: {}
}, returnValue = _p[index].value(null, module.exports, module);
_p[index].inited = true;
_p[index].value = returnValue;
if (returnValue !== undefined) {
return returnValue;
} else {
for (var key in module.exports) {
if (module.exports.hasOwnProperty(key)) {
_p[index].inited = true;
_p[index].value = module.exports;
return module.exports;
}
}
}
} else {
_p[index].inited = true;
return _p[index].value;
}
}
};
//src/connect/arc.js
/**
* @fileOverview
*
* 圆弧连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[0] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
var connectMarker = new kity.Marker().pipe(function() {
var r = 7;
var dot = new kity.Circle(r - 1);
this.addShape(dot);
this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
this.dot = dot;
this.node.setAttribute("markerUnits", "userSpaceOnUse");
});
connect.register("arc", function(node, parent, connection, width, color) {
var box = node.getLayoutBox(), pBox = parent.getLayoutBox();
var start, end, vector;
var abs = Math.abs;
var pathData = [];
var side = box.x > pBox.x ? "right" : "left";
node.getMinder().getPaper().addResource(connectMarker);
start = new kity.Point(pBox.cx, pBox.cy);
end = side == "left" ? new kity.Point(box.right + 2, box.cy) : new kity.Point(box.left - 2, box.cy);
vector = kity.Vector.fromPoints(start, end);
pathData.push("M", start);
pathData.push("A", abs(vector.x), abs(vector.y), 0, 0, vector.x * vector.y > 0 ? 0 : 1, end);
connection.setMarker(connectMarker);
connectMarker.dot.fill(color);
connection.setPathData(pathData);
});
}
};
//src/connect/arc_tp.js
/**
*
* 圆弧连线
*
* @author: along
* @copyright: bpd729@163.com , 2015
*/
_p[1] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
var connectMarker = new kity.Marker().pipe(function() {
var r = 7;
var dot = new kity.Circle(r - 1);
this.addShape(dot);
this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
this.dot = dot;
this.node.setAttribute("markerUnits", "userSpaceOnUse");
});
/**
* 天盘图连线除了连接当前节点和前一个节点外, 还需要渲染当前节点和后一个节点的连接, 防止样式上的断线
* 这是天盘图与其余的模板不同的地方
*/
connect.register("arc_tp", function(node, parent, connection, width, color) {
var end_box = node.getLayoutBox(), start_box = parent.getLayoutBox();
var index = node.getIndex();
var nextNode = parent.getChildren()[index + 1];
if (node.getIndex() > 0) {
start_box = parent.getChildren()[index - 1].getLayoutBox();
}
var start, end, vector;
var abs = Math.abs;
var pathData = [];
var side = end_box.x > start_box.x ? "right" : "left";
node.getMinder().getPaper().addResource(connectMarker);
start = new kity.Point(start_box.cx, start_box.cy);
end = new kity.Point(end_box.cx, end_box.cy);
var jl = Math.sqrt(Math.pow(start.x - end.x, 2) + Math.pow(start.y - end.y, 2));
//两圆中心点距离
jl = node.getIndex() == 0 ? jl * .4 : jl;
vector = kity.Vector.fromPoints(start, end);
pathData.push("M", start);
pathData.push("A", jl, jl, 0, 0, 1, end);
connection.setMarker(connectMarker);
connectMarker.dot.fill(color);
connection.setPathData(pathData);
// 设置下一个的节点的连接线
if (nextNode && nextNode.getConnection()) {
var nextConnection = nextNode.getConnection();
var next_end_box = nextNode.getLayoutBox();
var next_end = new kity.Point(next_end_box.cx, next_end_box.cy);
var jl2 = Math.sqrt(Math.pow(end.x - next_end.x, 2) + Math.pow(end.y - next_end.y, 2));
//两圆中心点距离
pathData = [];
pathData.push("M", end);
pathData.push("A", jl2, jl2, 0, 0, 1, next_end);
nextConnection.setMarker(connectMarker);
connectMarker.dot.fill(color);
nextConnection.setPathData(pathData);
}
});
}
};
//src/connect/bezier.js
/**
* @fileOverview
*
* 提供折线相连的方法
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[2] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
connect.register("bezier", function(node, parent, connection) {
// 连线起点和终点
var po = parent.getLayoutVertexOut(), pi = node.getLayoutVertexIn();
// 连线矢量和方向
var v = parent.getLayoutVectorOut().normalize();
var r = Math.round;
var abs = Math.abs;
var pathData = [];
pathData.push("M", r(po.x), r(po.y));
if (abs(v.x) > abs(v.y)) {
// x - direction
var hx = (pi.x + po.x) / 2;
pathData.push("C", hx, po.y, hx, pi.y, pi.x, pi.y);
} else {
// y - direction
var hy = (pi.y + po.y) / 2;
pathData.push("C", po.x, hy, pi.x, hy, pi.x, pi.y);
}
connection.setMarker(null);
connection.setPathData(pathData);
});
}
};
//src/connect/fish-bone-master.js
/**
* @fileOverview
*
* 鱼骨头主干连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[3] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
connect.register("fish-bone-master", function(node, parent, connection) {
var pout = parent.getLayoutVertexOut(), pin = node.getLayoutVertexIn();
var abs = Math.abs;
var dy = abs(pout.y - pin.y), dx = abs(pout.x - pin.x);
var pathData = [];
pathData.push("M", pout.x, pout.y);
pathData.push("h", dx - dy);
pathData.push("L", pin.x, pin.y);
connection.setMarker(null);
connection.setPathData(pathData);
});
}
};
//src/connect/l.js
/**
* @fileOverview
*
* "L" 连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[4] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
connect.register("l", function(node, parent, connection) {
var po = parent.getLayoutVertexOut();
var pi = node.getLayoutVertexIn();
var vo = parent.getLayoutVectorOut();
var pathData = [];
var r = Math.round, abs = Math.abs;
pathData.push("M", po.round());
if (abs(vo.x) > abs(vo.y)) {
pathData.push("H", r(pi.x));
} else {
pathData.push("V", pi.y);
}
pathData.push("L", pi);
connection.setPathData(pathData);
});
}
};
//src/connect/poly.js
/**
* @fileOverview
*
* 提供折线相连的方法
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[5] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
connect.register("poly", function(node, parent, connection, width) {
// 连线起点和终点
var po = parent.getLayoutVertexOut(), pi = node.getLayoutVertexIn();
// 连线矢量和方向
var v = parent.getLayoutVectorOut().normalize();
var r = Math.round;
var abs = Math.abs;
var pathData = [];
pathData.push("M", r(po.x), r(po.y));
switch (true) {
case abs(v.x) > abs(v.y) && v.x < 0:
// left
pathData.push("h", -parent.getStyle("margin-left"));
pathData.push("v", pi.y - po.y);
pathData.push("H", pi.x);
break;
case abs(v.x) > abs(v.y) && v.x >= 0:
// right
pathData.push("h", parent.getStyle("margin-right"));
pathData.push("v", pi.y - po.y);
pathData.push("H", pi.x);
break;
case abs(v.x) <= abs(v.y) && v.y < 0:
// top
pathData.push("v", -parent.getStyle("margin-top"));
pathData.push("h", pi.x - po.x);
pathData.push("V", pi.y);
break;
case abs(v.x) <= abs(v.y) && v.y >= 0:
// bottom
pathData.push("v", parent.getStyle("margin-bottom"));
pathData.push("h", pi.x - po.x);
pathData.push("V", pi.y);
break;
}
connection.setMarker(null);
connection.setPathData(pathData);
});
}
};
//src/connect/under.js
/**
* @fileOverview
*
* 下划线连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[6] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var connect = _p.r(11);
connect.register("under", function(node, parent, connection, width, color) {
var box = node.getLayoutBox(), pBox = parent.getLayoutBox();
var start, end, vector;
var abs = Math.abs;
var pathData = [];
var side = box.x > pBox.x ? "right" : "left";
var radius = node.getStyle("connect-radius");
var underY = box.bottom + 3;
var startY = parent.getType() == "sub" ? pBox.bottom + 3 : pBox.cy;
var p1, p2, p3, mx;
if (side == "right") {
p1 = new kity.Point(pBox.right, startY);
p2 = new kity.Point(box.left - 10, underY);
p3 = new kity.Point(box.right, underY);
} else {
p1 = new kity.Point(pBox.left, startY);
p2 = new kity.Point(box.right + 10, underY);
p3 = new kity.Point(box.left, underY);
}
mx = (p1.x + p2.x) / 2;
pathData.push("M", p1);
pathData.push("C", mx, p1.y, mx, p2.y, p2);
pathData.push("L", p3);
connection.setMarker(null);
connection.setPathData(pathData);
});
}
};
//src/core/_boxv.js
/**
* @fileOverview
*
* 调试工具:为 kity.Box 提供一个可视化的渲染
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[7] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var Minder = _p.r(19);
if (location.href.indexOf("boxv") != -1) {
var vrect;
Object.defineProperty(kity.Box.prototype, "visualization", {
get: function() {
if (!vrect) return null;
return vrect.setBox(this);
}
});
Minder.registerInitHook(function() {
this.on("paperrender", function() {
vrect = new kity.Rect();
vrect.fill("rgba(200, 200, 200, .5)");
vrect.stroke("orange");
this.getRenderContainer().addShape(vrect);
});
});
}
}
};
//src/core/animate.js
/**
* @fileOverview
*
* 动画控制
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
_p[8] = {
value: function(require, exports, module) {
var Minder = _p.r(19);
var animateDefaultOptions = {
enableAnimation: true,
layoutAnimationDuration: 300,
viewAnimationDuration: 100,
zoomAnimationDuration: 300
};
var resoredAnimationOptions = {};
Minder.registerInitHook(function() {
this.setDefaultOptions(animateDefaultOptions);
if (!this.getOption("enableAnimation")) {
this.disableAnimation();
}
});
Minder.prototype.enableAnimation = function() {
for (var name in animateDefaultOptions) {
if (animateDefaultOptions.hasOwnProperty(name)) {
this.setOption(resoredAnimationOptions[name]);
}
}
};
Minder.prototype.disableAnimation = function() {
for (var name in animateDefaultOptions) {
if (animateDefaultOptions.hasOwnProperty(name)) {
resoredAnimationOptions[name] = this.getOption(name);
this.setOption(name, 0);
}
}
};
}
};
//src/core/command.js
_p[9] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var utils = _p.r(33);
var Minder = _p.r(19);
var MinderNode = _p.r(21);
var MinderEvent = _p.r(13);
var COMMAND_STATE_NORMAL = 0;
var COMMAND_STATE_DISABLED = -1;
var COMMAND_STATE_ACTIVED = 1;
/**
* 表示一个命令,包含命令的查询及执行
*/
var Command = kity.createClass("Command", {
constructor: function() {
this._isContentChange = true;
this._isSelectionChange = false;
},
execute: function(minder, args) {
throw new Error("Not Implement: Command.execute()");
},
setContentChanged: function(val) {
this._isContentChange = !!val;
},
isContentChanged: function() {
return this._isContentChange;
},
setSelectionChanged: function(val) {
this._isSelectionChange = !!val;
},
isSelectionChanged: function() {
return this._isContentChange;
},
queryState: function(km) {
return COMMAND_STATE_NORMAL;
},
queryValue: function(km) {
return 0;
},
isNeedUndo: function() {
return true;
}
});
Command.STATE_NORMAL = COMMAND_STATE_NORMAL;
Command.STATE_ACTIVE = COMMAND_STATE_ACTIVED;
Command.STATE_DISABLED = COMMAND_STATE_DISABLED;
kity.extendClass(Minder, {
_getCommand: function(name) {
return this._commands[name.toLowerCase()];
},
_queryCommand: function(name, type, args) {
var cmd = this._getCommand(name);
if (cmd) {
var queryCmd = cmd["query" + type];
if (queryCmd) return queryCmd.apply(cmd, [ this ].concat(args));
}
return 0;
},
/**
* @method queryCommandState()
* @for Minder
* @description 查询指定命令的状态
*
* @grammar queryCommandName(name) => {number}
*
* @param {string} name 要查询的命令名称
*
* @return {number}
* -1: 命令不存在或命令当前不可用
* 0: 命令可用
* 1: 命令当前可用并且已经执行过
*/
queryCommandState: function(name) {
return this._queryCommand(name, "State", [].slice.call(arguments, 1));
},
/**
* @method queryCommandValue()
* @for Minder
* @description 查询指定命令当前的执行值
*
* @grammar queryCommandValue(name) => {any}
*
* @param {string} name 要查询的命令名称
*
* @return {any}
* 如果命令不存在,返回 undefined
* 不同命令具有不同返回值,具体请查看 [Command](command) 章节
*/
queryCommandValue: function(name) {
return this._queryCommand(name, "Value", [].slice.call(arguments, 1));
},
/**
* @method execCommand()
* @for Minder
* @description 执行指定的命令。
*
* @grammar execCommand(name, args...)
*
* @param {string} name 要执行的命令名称
* @param {argument} args 要传递给命令的其它参数
*/
execCommand: function(name) {
if (!name) return null;
name = name.toLowerCase();
var cmdArgs = [].slice.call(arguments, 1), cmd, stoped, result, eventParams;
var me = this;
cmd = this._getCommand(name);
eventParams = {
command: cmd,
commandName: name.toLowerCase(),
commandArgs: cmdArgs
};
if (!cmd || !~this.queryCommandState(name)) {
return false;
}
if (!this._hasEnterExecCommand) {
this._hasEnterExecCommand = true;
stoped = this._fire(new MinderEvent("beforeExecCommand", eventParams, true));
if (!stoped) {
this._fire(new MinderEvent("preExecCommand", eventParams, false));
result = cmd.execute.apply(cmd, [ me ].concat(cmdArgs));
this._fire(new MinderEvent("execCommand", eventParams, false));
if (cmd.isContentChanged()) {
this._firePharse(new MinderEvent("contentchange"));
}
this._interactChange();
}
this._hasEnterExecCommand = false;
} else {
result = cmd.execute.apply(cmd, [ me ].concat(cmdArgs));
if (!this._hasEnterExecCommand) {
this._interactChange();
}
}
return result === undefined ? null : result;
}
});
module.exports = Command;
}
};
//src/core/compatibility.js
_p[10] = {
value: function(require, exports, module) {
var utils = _p.r(33);
function compatibility(json) {
var version = json.version || (json.root ? "1.4.0" : "1.1.3");
switch (version) {
case "1.1.3":
c_113_120(json);
/* falls through */
case "1.2.0":
case "1.2.1":
c_120_130(json);
/* falls through */
case "1.3.0":
case "1.3.1":
case "1.3.2":
case "1.3.3":
case "1.3.4":
case "1.3.5":
/* falls through */
c_130_140(json);
}
return json;
}
function traverse(node, fn) {
fn(node);
if (node.children) node.children.forEach(function(child) {
traverse(child, fn);
});
}
/* 脑图数据升级 */
function c_120_130(json) {
traverse(json, function(node) {
var data = node.data;
delete data.layout_bottom_offset;
delete data.layout_default_offset;
delete data.layout_filetree_offset;
});
}
/**
* 脑图数据升级
* v1.1.3 => v1.2.0
* */
function c_113_120(json) {
// 原本的布局风格
var ocs = json.data.currentstyle;
delete json.data.currentstyle;
// 为 1.2 选择模板,同时保留老版本文件的皮肤
if (ocs == "bottom") {
json.template = "structure";
json.theme = "snow";
} else if (ocs == "default") {
json.template = "default";
json.theme = "classic";
}
traverse(json, function(node) {
var data = node.data;
// 升级优先级、进度图标
if ("PriorityIcon" in data) {
data.priority = data.PriorityIcon;
delete data.PriorityIcon;
}
if ("ProgressIcon" in data) {
data.progress = 1 + (data.ProgressIcon - 1 << 1);
delete data.ProgressIcon;
}
// 删除过时属性
delete data.point;
delete data.layout;
});
}
function c_130_140(json) {
json.root = {
data: json.data,
children: json.children
};
delete json.data;
delete json.children;
}
return compatibility;
}
};
//src/core/connect.js
_p[11] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var utils = _p.r(33);
var Module = _p.r(20);
var Minder = _p.r(19);
var MinderNode = _p.r(21);
// 连线提供方
var _connectProviders = {};
function register(name, provider) {
_connectProviders[name] = provider;
}
register("default", function(node, parent, connection) {
connection.setPathData([ "M", parent.getLayoutVertexOut(), "L", node.getLayoutVertexIn() ]);
});
kity.extendClass(MinderNode, {
/**
* @private
* @method getConnect()
* @for MinderNode
* @description 获取当前节点的连线类型
*
* @grammar getConnect() => {string}
*/
getConnect: function() {
return this.data.connect || "default";
},
getConnectProvider: function() {
return _connectProviders[this.getConnect()] || _connectProviders["default"];
},
/**
* @private
* @method getConnection()
* @for MinderNode
* @description 获取当前节点的连线对象
*
* @grammar getConnection() => {kity.Path}
*/
getConnection: function() {
return this._connection || null;
}
});
kity.extendClass(Minder, {
getConnectContainer: function() {
return this._connectContainer;
},
createConnect: function(node) {
if (node.isRoot()) return;
var connection = new kity.Path();
node._connection = connection;
this._connectContainer.addShape(connection);
this.updateConnect(node);
},
removeConnect: function(node) {
var me = this;
node.traverse(function(node) {
me._connectContainer.removeShape(node._connection);
node._connection = null;
});
},
updateConnect: function(node) {
var connection = node._connection;
var parent = node.parent;
if (!parent || !connection) return;
if (parent.isCollapsed()) {
connection.setVisible(false);
return;
}
connection.setVisible(true);
var provider = node.getConnectProvider();
var strokeColor = node.getStyle("connect-color") || "white", strokeWidth = node.getStyle("connect-width") || 2;
connection.stroke(strokeColor, strokeWidth);
provider(node, parent, connection, strokeWidth, strokeColor);
if (strokeWidth % 2 === 0) {
connection.setTranslate(.5, .5);
} else {
connection.setTranslate(0, 0);
}
}
});
Module.register("Connect", {
init: function() {
this._connectContainer = new kity.Group().setId(utils.uuid("minder_connect_group"));
this.getRenderContainer().prependShape(this._connectContainer);
},
events: {
nodeattach: function(e) {
this.createConnect(e.node);
},
nodedetach: function(e) {
this.removeConnect(e.node);
},
"layoutapply layoutfinish noderender": function(e) {
this.updateConnect(e.node);
}
}
});
exports.register = register;
}
};
//src/core/data.js
_p[12] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var utils = _p.r(33);
var Minder = _p.r(19);
var MinderNode = _p.r(21);
var MinderEvent = _p.r(13);
var compatibility = _p.r(10);
var Promise = _p.r(25);
var protocols = {};
function registerProtocol(name, protocol) {
protocols[name] = protocol;
for (var pname in protocols) {
if (protocols.hasOwnProperty(pname)) {
protocols[pname] = protocols[pname];
protocols[pname].name = pname;
}
}
}
function getRegisterProtocol(name) {
return name === undefined ? protocols : protocols[name] || null;
}
exports.registerProtocol = registerProtocol;
exports.getRegisterProtocol = getRegisterProtocol;
// 导入导出
kity.extendClass(Minder, {
// 自动导入
setup: function(target) {
if (typeof target == "string") {
target = document.querySelector(target);
}
if (!target) return;
var protocol = target.getAttribute("minder-data-type");
if (protocol in protocols) {
var data = target.textContent;
target.textContent = null;
this.renderTo(target);
this.importData(protocol, data);
}
return this;
},
/**
* @method exportJson()
* @for Minder
* @description
* 导出当前脑图数据为 JSON 对象,导出的数据格式请参考 [Data](data) 章节。
* @grammar exportJson() => {plain}
*/
exportJson: function() {
/* 导出 node 上整棵树的数据为 JSON */
function exportNode(node) {
var exported = {};
exported.data = node.getData();
var childNodes = node.getChildren();
exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
exported.children.push(exportNode(childNodes[i]));
}
return exported;
}
var json = {
root: exportNode(this.getRoot())
};
json.template = this.getTemplate();
json.theme = this.getTheme();
json.version = Minder.version;
return JSON.parse(JSON.stringify(json));
},
/**
* function Text2Children(MinderNode, String)
* @param {MinderNode} node 要导入数据的节点
* @param {String} text 导入的text数据
* @Desc: 用于批量插入子节点,并不会修改被插入的父节点
* @Editor: Naixor
* @Date: 2015.9.21
* @example: 用于批量导入如下类型的节点
* 234
* 3456346 asadf
* 12312414
* wereww
* 12314
* 1231412
* 13123
*/
Text2Children: function(node, text) {
if (!(node instanceof kityminder.Node)) {
return;
}
var children = [], jsonMap = {}, level = 0;
var LINE_SPLITTER = /\r|\n|\r\n/, TAB_REGEXP = /^(\t|\x20{4})/;
var lines = text.split(LINE_SPLITTER), line = "", jsonNode, i = 0;
var minder = this;
function isEmpty(line) {
return line === "" && !/\S/.test(line);
}
function getNode(line) {
return {
data: {
text: line.replace(/^(\t|\x20{4})+/, "").replace(/(\t|\x20{4})+$/, "")
},
children: []
};
}
function getLevel(text) {
var level = 0;
while (TAB_REGEXP.test(text)) {
text = text.replace(TAB_REGEXP, "");
level++;
}
return level;
}
function addChild(parent, node) {
parent.children.push(node);
}
function importChildren(node, children) {
for (var i = 0, l = children.length; i < l; i++) {
var childNode = minder.createNode(null, node);
childNode.setData("text", children[i].data.text || "");
importChildren(childNode, children[i].children);
}
}
while ((line = lines[i++]) !== undefined) {
line = line.replace(/ /g, "");
if (isEmpty(line)) continue;
level = getLevel(line);
jsonNode = getNode(line);
if (level === 0) {
jsonMap = {};
children.push(jsonNode);
jsonMap[0] = children[children.length - 1];
} else {
if (!jsonMap[level - 1]) {
throw new Error("Invalid local format");
}
addChild(jsonMap[level - 1], jsonNode);
jsonMap[level] = jsonNode;
}
}
importChildren(node, children);
minder.refresh();
},
/**
* @method exportNode(MinderNode)
* @param {MinderNode} node 当前要被导出的节点
* @return {Object} 返回只含有data和children的Object
* @Editor: Naixor
* @Date: 2015.9.22
*/
exportNode: function(node) {
var exported = {};
exported.data = node.getData();
var childNodes = node.getChildren();
exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
exported.children.push(this.exportNode(childNodes[i]));
}
return exported;
},
/**
* @method importNode()
* @description 根据纯json {data, children}数据转换成为脑图节点
* @Editor: Naixor
* @Date: 2015.9.20
*/
importNode: function(node, json) {
var data = json.data;
node.data = {};
for (var field in data) {
node.setData(field, data[field]);
}
var childrenTreeData = json.children || [];
for (var i = 0; i < childrenTreeData.length; i++) {
var childNode = this.createNode(null, node);
this.importNode(childNode, childrenTreeData[i]);
}
return node;
},
/**
* @method importJson()
* @for Minder
* @description 导入脑图数据,数据为 JSON 对象,具体的数据字段形式请参考 [Data](data) 章节。
*
* @grammar importJson(json) => {this}
*
* @param {plain} json 要导入的数据
*/
importJson: function(json) {
if (!json) return;
/**
* @event preimport
* @for Minder
* @when 导入数据之前
*/
this._fire(new MinderEvent("preimport", null, false));
// 删除当前所有节点
while (this._root.getChildren().length) {
this.removeNode(this._root.getChildren()[0]);
}
json = compatibility(json);
this.importNode(this._root, json.root);
this.setTemplate(json.template || "default");
this.setTheme(json.theme || null);
this.refresh();
/**
* @event import,contentchange,interactchange
* @for Minder
* @when 导入数据之后
*/
this.fire("import");
this._firePharse({
type: "contentchange"
});
this._interactChange();
return this;
},
/**
* @method exportData()
* @for Minder
* @description 使用指定使用的数据协议,导入脑图数据
*
* @grammar exportData(protocol) => Promise<data>
*
* @param {string} protocol 指定的数据协议(默认内置五种数据协议 `json`、`text`、`markdown`、`svg` 和 `png`)
*/
exportData: function(protocolName, option) {
var json, protocol;
json = this.exportJson();
// 指定了协议进行导出,需要检测协议是否支持
if (protocolName) {
protocol = protocols[protocolName];
if (!protocol || !protocol.encode) {
return Promise.reject(new Error("Not supported protocol:" + protocolName));
}
}
// 导出前抛个事件
this._fire(new MinderEvent("beforeexport", {
json: json,
protocolName: protocolName,
protocol: protocol
}));
return Promise.resolve(protocol.encode(json, this, option));
},
/**
* @method importData()
* @for Minder
* @description 使用指定的数据协议,导入脑图数据,覆盖当前实例的脑图
*
* @grammar importData(protocol, callback) => Promise<json>
*
* @param {string} protocol 指定的用于解析数据的数据协议(默认内置三种数据协议 `json`、`text` 和 `markdown` 的支持)
* @param {any} data 要导入的数据
*/
importData: function(protocolName, data, option) {
var json, protocol;
var minder = this;
// 指定了协议进行导入,需要检测协议是否支持
if (protocolName) {
protocol = protocols[protocolName];
if (!protocol || !protocol.decode) {
return Promise.reject(new Error("Not supported protocol:" + protocolName));
}
}
var params = {
local: data,
protocolName: protocolName,
protocol: protocol
};
// 导入前抛事件
this._fire(new MinderEvent("beforeimport", params));
return Promise.resolve(protocol.decode(data, this, option)).then(function(json) {
minder.importJson(json);
return json;
});
},
/**
* @method decodeData()
* @for Minder
* @description 使用指定的数据协议,解析为脑图数据,与 importData 的区别在于:不覆盖当前实例的脑图
*
* @grammar decodeData(protocol, callback) => Promise<json>
*
* @param {string} protocol 指定的用于解析数据的数据协议(默认内置三种数据协议 `json`、`text` 和 `markdown` 的支持)
* @param {any} data 要导入的数据
*/
decodeData: function(protocolName, data, option) {
var json, protocol;
var minder = this;
// 指定了协议进行导入,需要检测协议是否支持
if (protocolName) {
protocol = protocols[protocolName];
if (!protocol || !protocol.decode) {
return Promise.reject(new Error("Not supported protocol:" + protocolName));
}
}
var params = {
local: data,
protocolName: protocolName,
protocol: protocol
};
// 导入前抛事件
this._fire(new MinderEvent("beforeimport", params));
return Promise.resolve(protocol.decode(data, this, option));
}
});
}
};
//src/core/event.js
_p[13] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var utils = _p.r(33);
var Minder = _p.r(19);
/**
* @class MinderEvent
* @description 表示一个脑图中发生的事件
*/
var MinderEvent = kity.createClass("MindEvent", {
constructor: function(type, params, canstop) {
params = params || {};
if (params.getType && params.getType() == "ShapeEvent") {
/**
* @property kityEvent
* @for MinderEvent
* @description 如果事件是从一个 kity 的事件派生的,会有 kityEvent 属性指向原来的 kity 事件
* @type {KityEvent}
*/
this.kityEvent = params;
/**
* @property originEvent
* @for MinderEvent
* @description 如果事件是从原声 Dom 事件派生的(如 click、mousemove 等),会有 originEvent 指向原来的 Dom 事件
* @type {DomEvent}
*/
this.originEvent = params.originEvent;
} else if (params.target && params.preventDefault) {
this.originEvent = params;
} else {
kity.Utils.extend(this, params);
}
/**
* @property type
* @for MinderEvent
* @description 事件的类型,如 `click`、`contentchange` 等
* @type {string}
*/
this.type = type;
this._canstop = canstop || false;
},
/**
* @method getPosition()
* @for MinderEvent
* @description 如果事件是从一个 kity 事件派生的,会有 `getPosition()` 获取事件发生的坐标
*
* @grammar getPosition(refer) => {kity.Point}
*
* @param {string|kity.Shape} refer
* 参照的坐标系,
* `"screen"` - 以浏览器屏幕为参照坐标系
* `"minder"` - (默认)以脑图画布为参照坐标系
* `{kity.Shape}` - 指定以某个 kity 图形为参照坐标系
*/
getPosition: function(refer) {
if (!this.kityEvent) return;
if (!refer || refer == "minder") {
return this.kityEvent.getPosition(this.minder.getRenderContainer());
}
return this.kityEvent.getPosition.call(this.kityEvent, refer);
},
/**
* @method getTargetNode()
* @for MinderEvent
* @description 当发生的事件是鼠标事件时,获取事件位置命中的脑图节点
*
* @grammar getTargetNode() => {MinderNode}
*/
getTargetNode: function() {
var findShape = this.kityEvent && this.kityEvent.targetShape;
if (!findShape) return null;
while (!findShape.minderNode && findShape.container) {
findShape = findShape.container;
}
var node = findShape.minderNode;
if (node && findShape.getOpacity() < 1) return null;
return node || null;
},
/**
* @method stopPropagation()
* @for MinderEvent
* @description 当发生的事件是鼠标事件时,获取事件位置命中的脑图节点
*
* @grammar getTargetNode() => {MinderNode}
*/
stopPropagation: function() {
this._stoped = true;
},
stopPropagationImmediately: function() {
this._immediatelyStoped = true;
this._stoped = true;
},
shouldStopPropagation: function() {
return this._canstop && this._stoped;
},
shouldStopPropagationImmediately: function() {
return this._canstop && this._immediatelyStoped;
},
preventDefault: function() {
this.originEvent.preventDefault();
},
isRightMB: function() {
var isRightMB = false;
if (!this.originEvent) {
return false;
}
if ("which" in this.originEvent) isRightMB = this.originEvent.which == 3; else if ("button" in this.originEvent) isRightMB = this.originEvent.button == 2;
return isRightMB;
},
getKeyCode: function() {
var evt = this.originEvent;
return evt.keyCode || evt.which;
}
});
Minder.registerInitHook(function(option) {
this._initEvents();
});
kity.extendClass(Minder, {
_initEvents: function() {
this._eventCallbacks = {};
},
_resetEvents: function() {
this._initEvents();
this._bindEvents();
},
_bindEvents: function() {
/* jscs:disable maximumLineLength */
this._paper.on("click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop", this._firePharse.bind(this));
if (window) {
window.addEventListener("resize", this._firePharse.bind(this));
}
},
/**
* @method dispatchKeyEvent
* @description 派发键盘(相关)事件到脑图实例上,让实例的模块处理
* @grammar dispatchKeyEvent(e) => {this}
* @param {Event} e 原生的 Dom 事件对象
*/
dispatchKeyEvent: function(e) {
this._firePharse(e);
},
_firePharse: function(e) {
var beforeEvent, preEvent, executeEvent;
if (e.type == "DOMMouseScroll") {
e.type = "mousewheel";
e.wheelDelta = e.originEvent.wheelDelta = e.originEvent.detail * -10;
e.wheelDeltaX = e.originEvent.mozMovementX;
e.wheelDeltaY = e.originEvent.mozMovementY;
}
beforeEvent = new MinderEvent("before" + e.type, e, true);
if (this._fire(beforeEvent)) {
return;
}
preEvent = new MinderEvent("pre" + e.type, e, true);
executeEvent = new MinderEvent(e.type, e, true);
if (this._fire(preEvent) || this._fire(executeEvent)) this._fire(new MinderEvent("after" + e.type, e, false));
},
_interactChange: function(e) {
var me = this;
if (me._interactScheduled) return;
setTimeout(function() {
me._fire(new MinderEvent("interactchange"));
me._interactScheduled = false;
}, 100);
me._interactScheduled = true;
},
_listen: function(type, callback) {
var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
callbacks.push(callback);
},
_fire: function(e) {
/**
* @property minder
* @description 产生事件的 Minder 对象
* @for MinderShape
* @type {Minder}
*/
e.minder = this;
var status = this.getStatus();
var callbacks = this._eventCallbacks[e.type.toLowerCase()] || [];
if (status) {
callbacks = callbacks.concat(this._eventCallbacks[status + "." + e.type.toLowerCase()] || []);
}
if (callbacks.length === 0) {
return;
}
var lastStatus = this.getStatus();
for (var i = 0; i < callbacks.length; i++) {
callbacks[i].call(this, e);
/* this.getStatus() != lastStatus ||*/
if (e.shouldStopPropagationImmediately()) {
break;
}
}
return e.shouldStopPropagation();
},
on: function(name, callback) {
var km = this;
name.split(/\s+/).forEach(function(n) {
km._listen(n.toLowerCase(), callback);
});
return this;
},
off: function(name, callback) {
var types = name.split(/\s+/);
var i, j, callbacks, removeIndex;
for (i = 0; i < types.length; i++) {
callbacks = this._eventCallbacks[types[i].toLowerCase()];
if (callbacks) {
removeIndex = null;
for (j = 0; j < callbacks.length; j++) {
if (callbacks[j] == callback) {
removeIndex = j;
}
}
if (removeIndex !== null) {
callbacks.splice(removeIndex, 1);
}
}
}
},
fire: function(type, params) {
var e = new MinderEvent(type, params);
this._fire(e);
return this;
}
});
module.exports = MinderEvent;
}
};
//src/core/focus.js
_p[14] = {
value: function(require, exports, module) {
var kity = _p.r(17);
var Minder = _p.r(19);
Minder.registerInitHook(function() {
this.on("beforemousedown", function(e) {
this.focus();
e.preventDefault();
});
this.on("paperrender", function() {
this.focus();
});
});
kity.extendClass(Minder, {
focus: function() {
if (!this.isFocused()) {
var renderTarget = this._renderTarget;
renderTarget.classList.add("focus");
this.renderNodeBatch(this.getSelectedNodes());
}
this.fire("focus");
return this;
},
blur: function() {
if (this.isFocused()) {
var renderTarget = this._renderTarget;
renderTarget.classList.remove("focus");
this.renderNodeBatch(this.getSelectedNodes());
}
this.fire("blur");
return this;
},
isFocused: function() {
var renderTarget = this._renderTarget;
return renderTarget && renderTarget.classList.contains("focus");
}
});
}
};
//src/core/keymap.js
_p[15] = {
value: function(require, exports, module) {
var keymap = {
Backspace: 8,
Tab: 9,
Enter: 13,
Shift: 16,
Control: 17,
Alt: 18,
CapsLock: 20,
Esc: 27,
Spacebar: 32,
PageUp: 33,
PageDown: 34,
End: 35,
Home: 36,
Insert: 45,
Left: 37,
Up: 38,
Right: 39,
Down: 40,
direction: {
37: 1,
38: 1,
39: 1,
40: 1
},
Del: 46,
NumLock: 144,
Cmd: 91,
CmdFF: 224,
F1: 112,
F2: 113,
F3: 114,
F4: 115,
F5: 116,
F6: 117,
F7: 118,
F8: 119,
F9: 120,
F10: 121,
F11: 122,
F12: 123,
"`": 192,
"=": 187,
"-": 189,
"/": 191,
".": 190,
controlKeys: {
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
224: 1
},
notContentChange: {
13: 1,
9: 1,
33: 1,
34: 1,
35: 1,
36: 1,
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
113: 1,
114: 1,
115: 1,
144: 1,
27: 1
},
isSelectedNodeKey: {
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
13: 1,
9: 1
}
};
// 小写适配
for (var key in keymap) {
if (keymap.hasOwnProperty(key)) {
keymap[key.toLowerCase()] = keymap[key];
}
}
var aKeyCode = 65;
var aCharCode = "a".charCodeAt(0);