Commit 931c4b3b authored by techird's avatar techird

context menu and shortcut key

parent 9fee6c1b
......@@ -24,36 +24,42 @@
/* 核心代码 */
'src/core/kityminder.js',
'src/core/utils.js',
'src/core/browser.js',
'src/core/minder.js',
'src/core/option.js',
'src/core/event.js',
'src/core/status.js',
'src/core/paper.js',
'src/core/readonly.js',
'src/core/command.js',
'src/core/node.js',
'src/core/module.js',
'src/core/event.js',
'src/core/minder.js',
'src/core/minder.data.compatibility.js',
'src/core/minder.data.js',
'src/core/minder.event.js',
'src/core/minder.module.js',
'src/core/minder.command.js',
'src/core/minder.node.js',
'src/core/minder.select.js',
'src/core/keymap.js',
'src/core/minder.lang.js',
'src/core/minder.defaultoptions.js',
'src/core/minder.preference.js',
'src/core/browser.js',
'src/core/layout.js',
'src/core/connect.js',
'src/core/data.js',
'src/core/compatibility.js',
'src/core/render.js',
'src/core/connect.js',
'src/core/theme.js',
'src/core/layout.js',
'src/core/template.js',
'src/core/select.js',
'src/core/lang.js',
'src/core/defaultoptions.js',
'src/core/preference.js',
'src/core/keymap.js',
'src/core/key.js',
'src/core/contextmenu.js',
/* 布局 */
'src/layout/default.js',
'src/layout/default.connect.js',
'src/layout/bottom.js',
'src/layout/mind.js',
'src/layout/filetree.js',
'src/layout/left.js',
'src/layout/right.js',
'src/layout/btree.js',
/* 连线 */
'src/connect/bezier.js',
'src/connect/poly.js',
'src/connect/arc.js',
'src/connect/under.js',
'src/connect/l.js',
/* 皮肤 */
'src/theme/default.js',
......@@ -61,7 +67,10 @@
'src/theme/fresh.js',
/* 模板 */
'src/template/default.js',
'src/template/structure.js',
'src/template/filetree.js',
'src/template/right.js',
/* 模块 */
'src/module/node.js',
......@@ -76,7 +85,7 @@
'src/module/resource.js',
'src/module/view.js',
'src/module/dragtree.js',
'src/module/keyboard.js',
'src/module/keynav.js',
'src/module/select.js',
'src/module/history.js',
// 'src/module/editor.js',
......@@ -107,6 +116,7 @@
'ui/fuix.js',
'ui/fiox.js',
'ui/doc.js',
'ui/contextmenu.js',
/* UI 组件 */
'ui/widget/commandbutton.js',
......@@ -116,7 +126,7 @@
'ui/widget/friendlytimespan.js',
'ui/widget/locallist.js',
'ui/widget/netdiskfinder.js',
'ui/widget/menutab',
'ui/widget/menutab.js',
/* UI 菜单 */
'ui/menu/menu.js',
......@@ -165,9 +175,9 @@
'ui/ribbon/appearence/template.js',
'ui/ribbon/appearence/theme.js',
'ui/ribbon/appearence/layout.js',
'ui/ribbon/appearence/style.js',
'ui/ribbon/appearence/font.js',
'ui/ribbon/appearence/color.js',
'ui/ribbon/appearence/style.js',
/* UI Ribbon「视图」面板 */
'ui/ribbon/view/level.js'
......
......@@ -14,10 +14,6 @@ KityMinder.LANG['zh-cn'] = {
'fresh-purple': '浪漫紫',
'fresh-pink': '脑残粉'
},
'insert':{
//'maintopic':'插入中心主题',
'topic':'插入分支主题'
},
'maintopic': '中心主题',
'topic': '分支主题',
'panels': {
......@@ -38,6 +34,16 @@ KityMinder.LANG['zh-cn'] = {
'attachment': '附件'
},
'ui': {
'command': {
'appendsiblingnode': '新建兄弟节点',
'appendchildnode': '新建子节点',
'removenode': '删除',
'editnode': '编辑',
'arrangeup': '上移',
'arrangedown': '下移',
'resetlayout': '整理布局'
},
'back': '返回',
'undo': '撤销',
......
Subproject commit 5e1e032d8537c97a91df533e238436ea9183bc0b
Subproject commit 2100743a23276853658906608e093d1227739084
Subproject commit fee45f69801839d897e5e6245be93eaefafd615a
Subproject commit d3163f9c639510b02bcce2c533072b8ef21bc9a6
KM.registerUI( 'contextmenu', function () {
var me = this;
function getItemByLabel(label){
var result;
utils.each(me.getContextmenu(),function(i,item){
if(item.label == label){
result = item;
return false;
}
});
return result;
}
var $menu = $.kmuidropmenu({
click:function(e,v,l){
var item = getItemByLabel(l);
if(item.exec){
item.exec.apply(me);
}else{
me.execCommand(item.cmdName);
}
this.hide();
}
});
me.$container.append($menu);
me.on('contextmenu', function(e) {
e.preventDefault();
});
me.on('mouseup', function (e) {
//e.preventDefault();
if (me.getStatus() == 'hand' || !e.isRightMB()) return;
var node = e.getTargetNode();
if(node){
this.removeAllSelectedNodes();
this.select(node);
}
var items = me.getContextmenu();
var data = [];
utils.each(items,function(i,item){
if(item.divider){
data.length && data.push(item);
return;
}
if(item.query){
if(item.query.apply(me) != -1)
data.push({
label:item.label,
value:item.cmdName
});
return;
}
if(me.queryCommandState(item.cmdName)!=-1){
data.push({
label:item.label,
value:item.cmdName
});
}
});
if(data.length){
var item = data[data.length-1];
if(item.divider){
data.pop();
}
var pos = e.getPosition('screen');
var offset = $(me.getPaper().container).offset();
pos.y -= offset.top;
pos.x -= offset.left;
$menu.kmui().setData({
data:data
}).position(pos).show();
}
});
me.on('afterclick',function(){
$menu.kmui().hide();
});
me.on('beforemousedown',function(e){
if(e.isRightMB()){
//e.stopPropagationImmediately();
}
});
} );
/**
* @fileOverview
*
*
* 圆弧连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
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');
});
$(document).ready(function(){
KityMinder.registerConnectProvider('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);
});
\ No newline at end of file
......@@ -14,7 +14,7 @@ KityMinder.registerConnectProvider('bezier', function(node, parent, connection)
pi = node.getLayoutVertexIn();
// 连线矢量和方向
var v = node.getLayoutVector().normalize();
var v = parent.getLayoutVector().normalize();
var r = Math.round;
var abs = Math.abs;
......@@ -29,7 +29,7 @@ KityMinder.registerConnectProvider('bezier', function(node, parent, connection)
} else {
// y - direction
var hy = (pi.y + po.y) / 2;
pathData.push('C', po.x, hy, pi.y, hy, pi.x, pi.y);
pathData.push('C', po.x, hy, pi.x, hy, pi.x, pi.y);
}
connection.setMarker(null);
......
/**
* @fileOverview
*
* "L" 连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerConnectProvider('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);
});
\ No newline at end of file
......@@ -7,14 +7,14 @@
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerConnectProvider('poly', function(node, parent, connection) {
KityMinder.registerConnectProvider('poly', function(node, parent, connection, width) {
// 连线起点和终点
var po = parent.getLayoutVertexOut(),
pi = node.getLayoutVertexIn();
// 连线矢量和方向
var v = node.getLayoutVector().normalize();
var v = parent.getLayoutVectorOut().normalize();
var r = Math.round;
var abs = Math.abs;
......@@ -23,29 +23,29 @@ KityMinder.registerConnectProvider('poly', function(node, parent, connection) {
pathData.push('M', r(po.x), r(po.y));
switch (true) {
// left
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;
// right
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;
// top
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;
// bottom
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);
......
/**
* @fileOverview
*
* 下划线连线
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerConnectProvider('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 + 10, startY);
p2 = new kity.Point(box.left, underY);
p3 = new kity.Point(box.right + 10, underY);
} else {
p1 = new kity.Point(pBox.left - 10, startY);
p2 = new kity.Point(box.right, underY);
p3 = new kity.Point(box.left - 10, 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);
});
\ No newline at end of file
/**
* 浏览器判断模块
* @file
* @module UE.browser
* @since 1.2.6.1
*/
/**
* 提供浏览器检测的模块
* @unfile
......
......@@ -34,4 +34,86 @@ var Command = kity.createClass( "Command", {
isNeedUndo: function () {
return true;
}
} );
\ No newline at end of file
} );
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;
},
queryCommandState: function (name) {
return this._queryCommand(name, "State", Utils.argsToArray(1));
},
queryCommandValue: function (name) {
return this._queryCommand(name, "Value", Utils.argsToArray(1));
},
execCommand: function (name) {
name = name.toLowerCase();
var cmdArgs = Utils.argsToArray(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 && cmd.isNeedUndo()) {
this._hasEnterExecCommand = true;
stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true));
if (!stoped) {
//保存场景
this._fire(new MinderEvent('saveScene'));
this._fire(new MinderEvent("preExecCommand", eventParams, false));
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
this._fire(new MinderEvent('execCommand', eventParams, false));
//保存场景
this._fire(new MinderEvent('saveScene'));
if (cmd.isContentChanged()) {
this._firePharse(new MinderEvent('contentchange'));
}
if (cmd.isSelectionChanged()) {
this._firePharse(new MinderEvent('selectionchange'));
}
this._firePharse(new MinderEvent('interactchange'));
}
this._hasEnterExecCommand = false;
} else {
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
if (!this._hasEnterExecCommand) {
if (cmd.isSelectionChanged()) {
this._firePharse(new MinderEvent('selectionchange'));
}
this._firePharse(new MinderEvent('interactchange'));
}
}
return result === undefined ? null : result;
}
});
\ No newline at end of file
Utils.extend(KityMinder, {
compatibility: function(json) {
var version = json.version || '1.1.3';
......@@ -10,6 +11,11 @@ Utils.extend(KityMinder, {
});
}
/* 脑图数据升级 */
function c_120_130(json) {
}
/**
* 脑图数据升级
* v1.1.3 => v1.2.0
......
......@@ -21,7 +21,11 @@ utils.extend(KityMinder, {
kity.extendClass(MinderNode, {
getConnectProvider: function() {
return KityMinder.getConnectProvider();
return KityMinder.getConnectProvider(this.getConnect());
},
getConnect: function() {
return null;
}
});
......@@ -63,7 +67,7 @@ kity.extendClass(Minder, {
}
connection.setVisible(true);
var provider = KityMinder.getConnectProvider(parent.getLayout());
var provider = node.getConnectProvider();
var strokeColor = node.getStyle('connect-color') || 'white',
strokeWidth = node.getStyle('connect-width') || 2;
......@@ -71,6 +75,12 @@ kity.extendClass(Minder, {
connection.stroke(strokeColor, strokeWidth);
provider(node, parent, connection, strokeWidth, strokeColor);
if (strokeWidth % 2 === 0) {
connection.setTranslate(0.5, 0.5);
} else {
connection.setTranslate(0, 0);
}
}
});
......
/**
* @fileOverview
*
* 添加模块上下文菜单支持
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(Minder, {
_initContextMenu: function() {
this.contextmenus = [];
},
addContextMenu: function(item) {
if (utils.isArray(item)) {
this.contextmenus = this.contextmenus.concat(item);
} else {
this.contextmenus.push(item);
}
return this;
},
getContextMenu: function() {
return this.contextmenus;
}
});
\ No newline at end of file
......@@ -91,7 +91,7 @@ kity.extendClass(Minder, {
importNode(this._root, json, this);
this.setTemplate(json.template || null);
this.setTemplate(json.template || 'default');
this.setTheme(json.theme || null);
this.refresh();
......
......@@ -53,4 +53,147 @@ var MinderEvent = kity.createClass('MindEvent', {
isRightMB = this.originEvent.button == 2;
return isRightMB;
}
});
// 事件机制
kity.extendClass(Minder, {
_initEvents: function() {
this._eventCallbacks = {};
},
_bindEvents: function() {
this._bindPaperEvents();
this._bindKeyboardEvents();
},
_resetEvents: function() {
this._initEvents();
this._bindEvents();
},
// TODO: mousemove lazy bind
_bindPaperEvents: function() {
this._paper.on('click dblclick keydown keyup keypress paste mousedown contextmenu mouseup mousemove mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
if (window) {
window.addEventListener('resize', this._firePharse.bind(this));
window.addEventListener('blur', this._firePharse.bind(this));
}
this._renderTarget.onfocus = function() {
console.log('focus');
};
this._renderTarget.onblur = function() {
console.log('blur');
};
},
_bindKeyboardEvents: function() {
if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
//只能在这里做,要不无法触发
Utils.listen(document.body, 'keydown keyup keypress paste', this._firePharse.bind(this));
}
},
_firePharse: function(e) {
// //只读模式下强了所有的事件操作
// if(this.readOnly === true){
// return false;
// }
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);
this._fire(preEvent) ||
this._fire(executeEvent) ||
this._fire(new MinderEvent('after' + e.type, e, false));
if (~'mousedown mouseup keydown keyup'.indexOf(e.type)) {
this._interactChange(e);
}
},
_interactChange: function(e) {
var minder = this;
clearTimeout(this._interactTimeout);
this._interactTimeout = setTimeout(function() {
var stoped = minder._fire(new MinderEvent('beforeinteractchange'));
if (stoped) {
return;
}
minder._fire(new MinderEvent('preinteractchange'));
minder._fire(new MinderEvent('interactchange'));
}, 20);
},
_listen: function(type, callback) {
var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
callbacks.push(callback);
},
_fire: function(e) {
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);
if (this.getStatus() != lastStatus || e.shouldStopPropagationImmediately()) {
break;
}
}
return e.shouldStopPropagation();
},
on: function(name, callback) {
var km = this;
utils.each(name.split(/\s+/), function(i, 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;
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 添加快捷键支持
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
/**
* 计算包含 meta 键的 keycode
*
* @param {String|KeyEvent} unknown
*/
function getMetaKeyCode(unknown) {
var CTRL_MASK = 0x1000;
var ALT_MASK = 0x2000;
var SHIFT_MASK = 0x4000;
var metaKeyCode = 0;
if (typeof(unknown) == 'string') {
// unknown as string
unknown.toLowerCase().split(/\+\s*/).forEach(function(name) {
switch(name) {
case 'ctrl':
case 'cmd':
metaKeyCode |= CTRL_MASK;
break;
case 'alt':
metaKeyCode |= ALT_MASK;
break;
case 'shift':
metaKeyCode |= SHIFT_MASK;
break;
default:
metaKeyCode |= keymap[name];
}
});
} else {
// unknown as key event
if (unknown.ctrlKey || unknown.metaKey) {
metaKeyCode |= CTRL_MASK;
}
if (unknown.altKey) {
metaKeyCode |= ALT_MASK;
}
if (unknown.shiftKey) {
metaKeyCode |= SHIFT_MASK;
}
metaKeyCode |= unknown.keyCode;
}
return metaKeyCode;
}
kity.extendClass(MinderEvent, {
isShortcutKey: function(keyCombine) {
var keyEvent = this.originEvent;
if (!keyEvent) return false;
return getMetaKeyCode(keyCombine) == getMetaKeyCode(keyEvent);
}
});
kity.extendClass(Minder, {
_initShortcutKey: function() {
this._bindShortcutKeys();
},
_bindShortcutKeys: function() {
var map = this._shortcutKeys = {};
var has = 'hasOwnProperty';
this.on('keydown', function(e) {
for (var keys in map) {
if (!map[has](keys)) break;
if (e.isShortcutKey(keys)) {
map[keys]();
e.preventDefault();
}
}
});
},
addShortcut: function(keys, fn) {
var binds = this._shortcutKeys;
keys.split(/\|\s*/).forEach(function(combine) {
binds[combine] = fn;
});
},
addCommandShortcutKeys: function(cmd, keys) {
var binds = this._commandShortcutKeys || (this._commandShortcutKeys = {});
var obj = {},
km = this;
if (keys) {
obj[cmd] = keys;
} else {
obj = cmd;
}
var minder = this;
utils.each(obj, function(command, keys) {
binds[command] = keys;
minder.addShortcut(keys, function execCommandByShortcut() {
if (minder.queryCommandState(command) === 0) {
minder.execCommand(command);
}
});
});
},
getCommandShortcutKey: function(cmd) {
var binds = this._commandShortcutKeys;
return binds && binds[cmd] || null;
}
});
\ No newline at end of file
This diff is collapsed.
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;
},
queryCommandState: function (name) {
return this._queryCommand(name, "State", Utils.argsToArray(1));
},
queryCommandValue: function (name) {
return this._queryCommand(name, "Value", Utils.argsToArray(1));
},
execCommand: function (name) {
name = name.toLowerCase();
var cmdArgs = Utils.argsToArray(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 && cmd.isNeedUndo()) {
this._hasEnterExecCommand = true;
stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true));
if (!stoped) {
//保存场景
this._fire(new MinderEvent('saveScene'));
this._fire(new MinderEvent("preExecCommand", eventParams, false));
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
this._fire(new MinderEvent('execCommand', eventParams, false));
//保存场景
this._fire(new MinderEvent('saveScene'));
if (cmd.isContentChanged()) {
this._firePharse(new MinderEvent('contentchange'));
}
if (cmd.isSelectionChanged()) {
this._firePharse(new MinderEvent('selectionchange'));
}
this._firePharse(new MinderEvent('interactchange'));
}
this._hasEnterExecCommand = false;
} else {
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
if (!this._hasEnterExecCommand) {
if (cmd.isSelectionChanged()) {
this._firePharse(new MinderEvent('selectionchange'));
}
this._firePharse(new MinderEvent('interactchange'));
}
}
return result === undefined ? null : result;
}
});
\ No newline at end of file
// 事件机制
kity.extendClass(Minder, {
_initEvents: function() {
this._eventCallbacks = {};
},
_bindEvents: function() {
this._bindPaperEvents();
this._bindKeyboardEvents();
},
_resetEvents: function() {
this._initEvents();
this._bindEvents();
},
// TODO: mousemove lazy bind
_bindPaperEvents: function() {
this._paper.on('click dblclick keydown keyup keypress paste mousedown contextmenu mouseup mousemove mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
if (window) {
window.addEventListener('resize', this._firePharse.bind(this));
window.addEventListener('blur', this._firePharse.bind(this));
}
this._renderTarget.onfocus = function() {
console.log('focus');
};
this._renderTarget.onblur = function() {
console.log('blur');
};
},
_bindKeyboardEvents: function() {
if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
//只能在这里做,要不无法触发
Utils.listen(document.body, 'keydown keyup keypress paste', this._firePharse.bind(this));
}
},
_firePharse: function(e) {
// //只读模式下强了所有的事件操作
// if(this.readOnly === true){
// return false;
// }
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);
this._fire(preEvent) ||
this._fire(executeEvent) ||
this._fire(new MinderEvent('after' + e.type, e, false));
if (~'mousedown mouseup keydown keyup'.indexOf(e.type)) {
this._interactChange(e);
}
},
_interactChange: function(e) {
var minder = this;
clearTimeout(this._interactTimeout);
this._interactTimeout = setTimeout(function() {
var stoped = minder._fire(new MinderEvent('beforeinteractchange'));
if (stoped) {
return;
}
minder._fire(new MinderEvent('preinteractchange'));
minder._fire(new MinderEvent('interactchange'));
}, 20);
},
_listen: function(type, callback) {
var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
callbacks.push(callback);
},
_fire: function(e) {
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);
if (this.getStatus() != lastStatus || e.shouldStopPropagationImmediately()) {
break;
}
}
return e.shouldStopPropagation();
},
on: function(name, callback) {
var km = this;
utils.each(name.split(/\s+/), function(i, 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;
}
});
\ No newline at end of file
var Minder = KityMinder.Minder = kity.createClass('KityMinder', {
constructor: function(options) {
this._options = Utils.extend(window.KITYMINDER_CONFIG || {}, options);
this.setDefaultOptions(KM.defaultOptions);
this._initEvents(options);
this._initMinder(options);
this._initSelection(options);
this._initStatus(options);
this._initShortcutKey(options);
this._initContextmenu(options);
this._initModules(options);
this._initProtocols(options);
this.setDefaultOptions(KM.defaultOptions); // @see option.js
this._initEvents(options); // @see event.js
this._initStatus(options); // @see status.js
this._initPaper(options); // @see paper.js
this._initSelection(options); // @see select.js
this._initShortcutKey(options); // @see key.js
this._initContextMenu(options); // @see contextmenu.js
this._initModules(options); // @see module.js
this._initProtocols(options); // @see data.js
if (this.getOptions('readOnly') === true) {
this.setDisabled();
this.setDisabled(); // @see readonly.js
}
this.refresh();
this.setTheme();
this.refresh(); // @see layout.js
this.setTheme(); // @see theme.js
this.fire('ready');
},
getOptions: function(key) {
var val;
if (key) {
val = this.getPreferences(key);
return val === null || val === undefined ? this._options[key] : val;
} else {
val = this.getPreferences();
if (val) {
return utils.extend(val, this._options, true);
} else {
return this._options;
}
}
},
setDefaultOptions: function(key, val, cover) {
var obj = {};
if (Utils.isString(key)) {
obj[key] = val;
} else {
obj = key;
}
utils.extend(this._options, obj, !cover);
},
setOptions: function(key, val) {
this.setPreferences(key, val);
},
_initMinder: function() {
this._paper = new kity.Paper();
this._paper.getNode().setAttribute('contenteditable', true);
this._paper.getNode().ondragstart = function(e) {
e.preventDefault();
};
this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
this._addRenderContainer();
this.setRoot(this.createNode(this.getLang().maintopic));
if (this._options.renderTo) {
this.renderTo(this._options.renderTo);
}
},
_addRenderContainer: function() {
this._rc = new kity.Group().setId(KityMinder.uuid('minder'));
this._paper.addShape(this._rc);
},
renderTo: function(target) {
this._paper.renderTo(this._renderTarget = target);
this._bindEvents();
},
getRenderContainer: function() {
return this._rc;
},
getPaper: function() {
return this._paper;
},
getRenderTarget: function() {
return this._renderTarget;
},
_initShortcutKey: function() {
this._shortcutkeys = {};
this._bindshortcutKeys();
},
addShortcutKeys: function(cmd, keys) {
var obj = {},
km = this;
if (keys) {
obj[cmd] = keys;
} else {
obj = cmd;
}
utils.each(obj, function(k, v) {
km._shortcutkeys[k.toLowerCase()] = v;
});
},
getShortcutKey: function(cmdName) {
return this._shortcutkeys[cmdName];
},
_bindshortcutKeys: function() {
var me = this,
shortcutkeys = this._shortcutkeys;
function checkkey(key, keyCode, e) {
switch (key) {
case 'ctrl':
case 'cmd':
if (e.ctrlKey || e.metaKey) {
return true;
}
break;
case 'alt':
if (e.altKey) {
return true;
}
break;
case 'shift':
if (e.shiftKey) {
return true;
}
}
if (keyCode == keymap[key]) {
return true;
}
return false;
}
me.on('keydown', function(e) {
var originEvent = e.originEvent;
var keyCode = originEvent.keyCode || originEvent.which;
for (var i in shortcutkeys) {
var keys = shortcutkeys[i].toLowerCase().split('+');
var current = 0;
utils.each(keys, function(i, k) {
if (checkkey(k, keyCode, originEvent)) {
current++;
}
});
if (current == keys.length) {
if (me.queryCommandState(i) != -1)
me.execCommand(i);
originEvent.preventDefault();
break;
}
}
});
},
_initContextmenu: function() {
this.contextmenus = [];
},
addContextmenu: function(item) {
if (utils.isArray(item)) {
this.contextmenus = this.contextmenus.concat(item);
} else {
this.contextmenus.push(item);
}
return this;
},
getContextmenu: function() {
return this.contextmenus;
},
_initStatus: function() {
this._status = 'normal';
this._rollbackStatus = 'normal';
},
setStatus: (function() {
var sf = ~window.location.href.indexOf('status');
var tf = ~window.location.href.indexOf('trace');
return function(status) {
if (status != this._status) {
this._rollbackStatus = this._status;
this._status = status;
this.fire('statuschange', {
lastStatus: this._rollbackStatus,
currentStatus: this._status
});
if (sf) {
console.log(window.event.type, this._rollbackStatus, '->', this._status);
if (tf) {
console.trace();
}
}
}
return this;
};
})(),
rollbackStatus: function() {
this.setStatus(this._rollbackStatus);
},
getStatus: function() {
return this._status;
},
setDisabled: function() {
var me = this;
//禁用命令
me.bkqueryCommandState = me.queryCommandState;
me.bkqueryCommandValue = me.queryCommandValue;
me.queryCommandState = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
return me.bkqueryCommandState.apply(me, arguments);
}
return -1;
};
me.queryCommandValue = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
return me.bkqueryCommandValue.apply(me, arguments);
}
return null;
};
this.setStatus('readonly');
me.fire('interactchange');
},
setEnabled: function() {
var me = this;
if (me.bkqueryCommandState) {
me.queryCommandState = me.bkqueryCommandState;
delete me.bkqueryCommandState;
}
if (me.bkqueryCommandValue) {
me.queryCommandValue = me.bkqueryCommandValue;
delete me.bkqueryCommandValue;
}
this.rollbackStatus();
me.fire('interactchange');
}
});
\ No newline at end of file
// 模块声明周期维护
kity.extendClass(Minder, {
_initModules: function() {
var modulesPool = KityMinder.getModules();
var modulesToLoad = this._options.modules || Utils.keys(modulesPool);
this._commands = {};
this._query = {};
this._modules = {};
this._rendererClasses = {};
var i, name, type, module, moduleDeals,
dealCommands, dealEvents, dealRenderers;
var me = this;
for (i = 0; i < modulesToLoad.length; i++) {
name = modulesToLoad[i];
if (!modulesPool[name]) continue;
// 执行模块初始化,抛出后续处理对象
if (typeof(modulesPool[name]) == 'function') {
moduleDeals = modulesPool[name].call(me);
} else {
moduleDeals = modulesPool[name];
}
this._modules[name] = moduleDeals;
if (moduleDeals.init) {
moduleDeals.init.call(me, this._options);
}
// command加入命令池子
dealCommands = moduleDeals.commands;
for (name in dealCommands) {
this._commands[name.toLowerCase()] = new dealCommands[name]();
}
// 绑定事件
dealEvents = moduleDeals.events;
if (dealEvents) {
for (type in dealEvents) {
me.on(type, dealEvents[type]);
}
}
// 渲染器
dealRenderers = moduleDeals.renderers;
if (dealRenderers) {
for (type in dealRenderers) {
this._rendererClasses[type] = this._rendererClasses[type] || [];
if (Utils.isArray(dealRenderers[type])) {
this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
} else {
this._rendererClasses[type].push(dealRenderers[type]);
}
}
}
if (moduleDeals.defaultOptions) {
this.setDefaultOptions(moduleDeals.defaultOptions);
}
//添加模块的快捷键
if (moduleDeals.addShortcutKeys) {
this.addShortcutKeys(moduleDeals.addShortcutKeys);
}
//添加邮件菜单
if (moduleDeals.contextmenu) {
this.addContextmenu(moduleDeals.contextmenu);
}
}
},
_garbage: function() {
this.clearSelect();
while (this._root.getChildren().length) {
this._root.removeChild(0);
}
},
destroy: function() {
var modules = this._modules;
this._resetEvents();
this._garbage();
for (var key in modules) {
if (!modules[key].destroy) continue;
modules[key].destroy.call(this);
}
},
reset: function() {
var modules = this._modules;
this._garbage();
for (var key in modules) {
if (!modules[key].reset) continue;
modules[key].reset.call(this);
}
}
});
\ No newline at end of file
kity.extendClass(Minder, {
getRoot: function() {
return this._root;
},
setRoot: function(root) {
this._root = root;
root.minder = this;
},
createNode: function(unknown, parent, index) {
var node = new MinderNode(unknown);
this.fire('nodecreate', { node: node });
this.appendNode(node,parent, index);
return node;
},
appendNode: function(node, parent, index) {
if (parent) parent.insertChild(node, index);
this.attachNode(node);
return this;
},
removeNode: function(node) {
if (node.parent) {
node.parent.removeChild(node);
this.detachNode(node);
this.fire('noderemove', { node: node });
}
},
attachNode: function(node) {
var rc = this._rc;
node.traverse(function(current) {
current.attached = true;
rc.addShape(current.getRenderContainer());
});
rc.addShape(node.getRenderContainer());
this.fire('nodeattach', {
node: node
});
},
detachNode: function(node) {
var rc = this._rc;
node.traverse(function(current) {
current.attached = false;
rc.removeShape(current.getRenderContainer());
});
this.fire('nodedetach', {
node: node
});
},
getMinderTitle: function() {
return this.getRoot().getText();
}
});
kity.extendClass(MinderNode, {
getMinder: function() {
return this.getRoot().minder;
}
});
\ No newline at end of file
......@@ -11,4 +11,115 @@
KityMinder.getModules = function () {
return _modules;
};
} )();
\ No newline at end of file
} )();
// 模块声明周期维护
kity.extendClass(Minder, {
_initModules: function() {
var modulesPool = KityMinder.getModules();
var modulesToLoad = this._options.modules || Utils.keys(modulesPool);
this._commands = {};
this._query = {};
this._modules = {};
this._rendererClasses = {};
var i, name, type, module, moduleDeals,
dealCommands, dealEvents, dealRenderers;
var me = this;
for (i = 0; i < modulesToLoad.length; i++) {
name = modulesToLoad[i];
if (!modulesPool[name]) continue;
// 执行模块初始化,抛出后续处理对象
if (typeof(modulesPool[name]) == 'function') {
moduleDeals = modulesPool[name].call(me);
} else {
moduleDeals = modulesPool[name];
}
this._modules[name] = moduleDeals;
if (moduleDeals.init) {
moduleDeals.init.call(me, this._options);
}
// command加入命令池子
dealCommands = moduleDeals.commands;
for (name in dealCommands) {
this._commands[name.toLowerCase()] = new dealCommands[name]();
}
// 绑定事件
dealEvents = moduleDeals.events;
if (dealEvents) {
for (type in dealEvents) {
me.on(type, dealEvents[type]);
}
}
// 渲染器
dealRenderers = moduleDeals.renderers;
if (dealRenderers) {
for (type in dealRenderers) {
this._rendererClasses[type] = this._rendererClasses[type] || [];
if (Utils.isArray(dealRenderers[type])) {
this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
} else {
this._rendererClasses[type].push(dealRenderers[type]);
}
}
}
if (moduleDeals.defaultOptions) {
this.setDefaultOptions(moduleDeals.defaultOptions);
}
//添加模块的快捷键
if (moduleDeals.commandShortcutKeys) {
this.addCommandShortcutKeys(moduleDeals.commandShortcutKeys);
}
//添加邮件菜单
if (moduleDeals.contextmenu) {
this.addContextMenu(moduleDeals.contextmenu);
}
}
},
_garbage: function() {
this.clearSelect();
while (this._root.getChildren().length) {
this._root.removeChild(0);
}
},
destroy: function() {
var modules = this._modules;
this._resetEvents();
this._garbage();
for (var key in modules) {
if (!modules[key].destroy) continue;
modules[key].destroy.call(this);
}
},
reset: function() {
var modules = this._modules;
this._garbage();
for (var key in modules) {
if (!modules[key].reset) continue;
modules[key].reset.call(this);
}
}
});
\ No newline at end of file
......@@ -372,4 +372,71 @@ MinderNode.getCommonAncestor = function(nodeA, nodeB) {
return MinderNode.getCommonAncestor(prev, current);
}, nodeA);
}
};
\ No newline at end of file
};
kity.extendClass(Minder, {
getRoot: function() {
return this._root;
},
setRoot: function(root) {
this._root = root;
root.minder = this;
},
createNode: function(unknown, parent, index) {
var node = new MinderNode(unknown);
this.fire('nodecreate', { node: node, parent: parent, index: index });
this.appendNode(node, parent, index);
return node;
},
appendNode: function(node, parent, index) {
if (parent) parent.insertChild(node, index);
this.attachNode(node);
return this;
},
removeNode: function(node) {
if (node.parent) {
node.parent.removeChild(node);
this.detachNode(node);
this.fire('noderemove', { node: node });
}
},
attachNode: function(node) {
var rc = this._rc;
node.traverse(function(current) {
current.attached = true;
rc.addShape(current.getRenderContainer());
});
rc.addShape(node.getRenderContainer());
this.fire('nodeattach', {
node: node
});
},
detachNode: function(node) {
var rc = this._rc;
node.traverse(function(current) {
current.attached = false;
rc.removeShape(current.getRenderContainer());
});
this.fire('nodedetach', {
node: node
});
},
getMinderTitle: function() {
return this.getRoot().getText();
}
});
kity.extendClass(MinderNode, {
getMinder: function() {
return this.getRoot().minder;
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 提供脑图选项支持
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(Minder, {
getOptions: function(key) {
var val;
if (key) {
val = this.getPreferences(key);
return val === null || val === undefined ? this._options[key] : val;
} else {
val = this.getPreferences();
if (val) {
return utils.extend(val, this._options, true);
} else {
return this._options;
}
}
},
setDefaultOptions: function(key, val, cover) {
var obj = {};
if (Utils.isString(key)) {
obj[key] = val;
} else {
obj = key;
}
utils.extend(this._options, obj, !cover);
},
setOptions: function(key, val) {
this.setPreferences(key, val);
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 初始化渲染容器
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(Minder, {
_initPaper: function() {
this._paper = new kity.Paper();
this._paper.getNode().setAttribute('contenteditable', true);
this._paper.getNode().ondragstart = function(e) {
e.preventDefault();
};
this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
this._addRenderContainer();
this.setRoot(this.createNode(this.getLang().maintopic));
if (this._options.renderTo) {
this.renderTo(this._options.renderTo);
}
},
_addRenderContainer: function() {
this._rc = new kity.Group().setId(KityMinder.uuid('minder'));
this._paper.addShape(this._rc);
},
renderTo: function(target) {
this._paper.renderTo(this._renderTarget = target);
this._bindEvents();
},
getRenderContainer: function() {
return this._rc;
},
getPaper: function() {
return this._paper;
},
getRenderTarget: function() {
return this._renderTarget;
},
});
\ No newline at end of file
/**
* @fileOverview
*
*
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(Minder, {
disable: function() {
var me = this;
//禁用命令
me.bkqueryCommandState = me.queryCommandState;
me.bkqueryCommandValue = me.queryCommandValue;
me.queryCommandState = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
return me.bkqueryCommandState.apply(me, arguments);
}
return -1;
};
me.queryCommandValue = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
return me.bkqueryCommandValue.apply(me, arguments);
}
return null;
};
this.setStatus('readonly');
me.fire('interactchange');
},
enable: function() {
var me = this;
if (me.bkqueryCommandState) {
me.queryCommandState = me.bkqueryCommandState;
delete me.bkqueryCommandState;
}
if (me.bkqueryCommandValue) {
me.queryCommandValue = me.bkqueryCommandValue;
delete me.bkqueryCommandValue;
}
this.rollbackStatus();
me.fire('interactchange');
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 状态切换控制
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(Minder, {
_initStatus: function() {
this._status = 'normal';
this._rollbackStatus = 'normal';
},
setStatus: (function() {
var sf = ~window.location.href.indexOf('status');
var tf = ~window.location.href.indexOf('trace');
return function(status) {
if (status != this._status) {
this._rollbackStatus = this._status;
this._status = status;
this.fire('statuschange', {
lastStatus: this._rollbackStatus,
currentStatus: this._status
});
if (sf) {
console.log(window.event.type, this._rollbackStatus, '->', this._status);
if (tf) {
console.trace();
}
}
}
return this;
};
})(),
rollbackStatus: function() {
this.setStatus(this._rollbackStatus);
},
getStatus: function() {
return this._status;
}
});
\ No newline at end of file
......@@ -8,8 +8,6 @@ utils.extend(KityMinder, {
}
});
KityMinder.registerTemplate('default', {});
kity.extendClass(Minder, (function() {
var originGetTheme = Minder.prototype.getTheme;
return {
......@@ -26,16 +24,14 @@ kity.extendClass(Minder, (function() {
this._template = name || null;
},
getTemplateSupports: function() {
return KityMinder._templates[this._template] || null;
getTemplateSupport: function(method) {
var supports = KityMinder._templates[this._template];
return supports && supports[method];
},
getTheme: function(node) {
var supports = this.getTemplateSupports();
if (supports && supports.getTheme) {
return supports.getTheme(node);
}
return originGetTheme.call(this, node);
var support = this.getTemplateSupport('getTheme') || originGetTheme;
return support.call(this, node);
}
};
})());
......@@ -43,13 +39,16 @@ kity.extendClass(Minder, (function() {
kity.extendClass(MinderNode, (function() {
var originGetLayout = MinderNode.prototype.getLayout;
var originGetConnect = MinderNode.prototype.getConnect;
return {
getLayout: function() {
var supports = this.getMinder().getTemplateSupports();
if (supports && supports.getLayout) {
return supports.getLayout(this);
}
return originGetLayout.call(this);
var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
return support.call(this, this);
},
getConnect: function() {
var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
return support.call(this, this);
}
};
})());
......
/* global Layout:true */
window.layoutSwitch = true;
KityMinder.registerLayout('bottom', kity.createClass({
base: Layout,
doLayout: function(node) {
var children = node.getChildren();
if (!children.length) {
return false;
}
var nbox = node.getContentBox();
node.setVertexOut(new kity.Point(nbox.cx, nbox.bottom));
node.setLayoutVector(new kity.Vector(0, 1));
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
child.setVertexIn(new kity.Point(cbox.cx, cbox.top));
});
var yDistance = nbox.bottom + node.getStyle('margin-bottom') + children[0].getStyle('margin-top');
this.align(children, 'top', yDistance);
this.stack(children, 'x');
var bbox = this.getBranchBox(children);
this.move(children, nbox.width / 2 + nbox.left - bbox.width / 2, 0);
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = 3;
hint.push({
type: 'up',
node: node,
area: {
x: box.left - node.getStyle('margin-left') - offset,
y: box.top,
width: node.getStyle('margin-left'),
height: box.height
},
path: ['M', box.left - offset, box.top, 'L', box.left - offset, box.bottom]
});
hint.push({
type: 'down',
node: node,
area: {
x: box.right + offset,
y: box.top,
width: node.getStyle('margin-right'),
height: box.height
},
path: ['M', box.right + offset, box.top, 'L', box.right + offset, box.bottom]
});
return hint;
}
}));
KityMinder.registerConnectProvider('bottom', function(node, parent, connection) {
var pout = parent.getLayoutVertexOut(),
pin = node.getLayoutVertexIn();
var pathData = [];
var r = Math.round;
pathData.push('M', new kity.Point(r(pout.x), pout.y));
pathData.push('L', new kity.Point(r(pout.x), pout.y + parent.getStyle('margin-bottom')));
pathData.push('L', new kity.Point(r(pin.x), pout.y + parent.getStyle('margin-bottom')));
pathData.push('L', new kity.Point(r(pin.x), pin.y));
connection.setMarker(null);
connection.setPathData(pathData);
});
\ No newline at end of file
/* global Layout:true */
var layouts = ['left', 'right', 'top', 'bottom'];
layouts.forEach(function(name) {
var axis = (name == 'left' || name == 'right') ? 'x' : 'y';
var dir = (name == 'left' || name == 'top') ? -1 : 1;
var oppsite = {
'left': 'right',
'right': 'left',
'top': 'bottom',
'bottom': 'top',
'x': 'y',
'y': 'x'
};
function getOrderHint(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = 5;
if (axis == 'x') {
hint.push({
type: 'up',
node: node,
area: {
x: box.x,
y: box.top - node.getStyle('margin-top') - offset,
width: box.width,
height: node.getStyle('margin-top')
},
path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
});
hint.push({
type: 'down',
node: node,
area: {
x: box.x,
y: box.bottom + offset,
width: box.width,
height: node.getStyle('margin-bottom')
},
path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
});
} else {
hint.push({
type: 'up',
node: node,
area: {
x: box.left - node.getStyle('margin-left') - offset,
y: box.top,
width: node.getStyle('margin-left'),
height: box.height
},
path: ['M', box.left - offset, box.top, 'L', box.left - offset, box.bottom]
});
hint.push({
type: 'down',
node: node,
area: {
x: box.right + offset,
y: box.top,
width: node.getStyle('margin-right'),
height: box.height
},
path: ['M', box.right + offset, box.top, 'L', box.right + offset, box.bottom]
});
}
return hint;
}
KityMinder.registerLayout(name, kity.createClass({
base: Layout,
doLayout: function(parent, children) {
if (!children.length) {
return false;
}
var pbox = parent.getContentBox();
if (axis == 'x') {
parent.setVertexOut(new kity.Point(pbox[name], pbox.cy));
parent.setLayoutVectorOut(new kity.Vector(dir, 0));
} else {
parent.setVertexOut(new kity.Point(pbox.cx, pbox[name]));
parent.setLayoutVectorOut(new kity.Vector(0, dir));
}
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
if (axis == 'x') {
child.setVertexIn(new kity.Point(cbox[oppsite[name]], cbox.cy));
child.setLayoutVectorIn(new kity.Vector(dir, 0));
} else {
child.setVertexIn(new kity.Point(cbox.cx, cbox[oppsite[name]]));
child.setLayoutVectorIn(new kity.Vector(0, dir));
}
});
this.align(children, oppsite[name]);
this.stack(children, oppsite[axis]);
var bbox = this.getBranchBox(children);
var xAdjust, yAdjust;
if (axis == 'x') {
xAdjust = pbox[name];
xAdjust += dir * parent.getStyle('margin-' + name);
xAdjust += dir * children[0].getStyle('margin-' + oppsite[name]);
yAdjust = pbox.bottom;
yAdjust -= pbox.height / 2;
yAdjust -= bbox.height / 2;
yAdjust -= bbox.y;
} else {
xAdjust = pbox.right;
xAdjust -= pbox.width / 2;
xAdjust -= bbox.width / 2;
xAdjust -= bbox.x;
yAdjust = pbox[name];
yAdjust += dir * parent.getStyle('margin-' + name);
yAdjust += dir * children[0].getStyle('margin-' + oppsite[name]);
}
this.move(children, xAdjust, yAdjust);
},
getOrderHint: getOrderHint
}));
});
\ No newline at end of file
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');
});
KityMinder.registerConnectProvider('default', 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);
switch (node.getType()) {
case 'main':
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);
break;
case 'sub':
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 + 10, startY);
p2 = new kity.Point(box.left, underY);
p3 = new kity.Point(box.right + 10, underY);
} else {
p1 = new kity.Point(pBox.left - 10, startY);
p2 = new kity.Point(box.right, underY);
p3 = new kity.Point(box.left - 10, underY);
}
mx = (p1.x + p2.x) / 2;
if (width % 2 === 0) {
p1.y += 0.5;
p2.y += 0.5;
p3.y += 0.5;
}
pathData.push('M', p1);
pathData.push('C', mx, p1.y, mx, p2.y, p2);
pathData.push('L', p3);
connection.setMarker(null);
break;
}
connection.setPathData(pathData);
});
\ No newline at end of file
/* global Layout:true */
KityMinder.registerLayout('default', kity.createClass({
base: Layout,
doLayout: function(node) {
var layout = this;
if (node.isLayoutRoot()) {
this.doLayoutRoot(node);
} else {
this.arrange(node, node.children, layout.getSide(node));
}
},
getSide: function(node) {
while (!node.parent.isLayoutRoot()) {
node = node.parent;
}
var mainIndex = node.getIndex();
var length = node.parent.children.length;
return mainIndex < length / 2 ? 'right' : 'left';
},
doLayoutRoot: function(root) {
var mains = root.getChildren();
var group = {
left: [],
right: []
};
var _this = this;
mains.forEach(function(main) {
group[_this.getSide(main)].push(main);
});
this.arrange(root, group.left, 'left');
this.arrange(root, group.right, 'right');
},
arrange: function(parent, children, side) {
if (!children.length) return;
var _this = this;
// children 所占的总树高
var totalTreeHeight = 0;
// 计算每个 child 的树所占的矩形区域
var childTreeBoxes = children.map(function(node, index, children) {
var box = _this.getTreeBox([node]);
// 计算总树高,需要把竖直方向上的 margin 加入计算
totalTreeHeight += box.height;
if (index > 0) {
totalTreeHeight += children[index - 1].getStyle('margin-bottom');
totalTreeHeight += node.getStyle('margin-top');
}
return box;
});
var nodeContentBox = parent.getContentBox();
var i, x, y, child, childTreeBox, childContentBox;
var transform, offset;
y = -totalTreeHeight / 2;
if (side != 'left') {
parent.setVertexOut(new kity.Point(nodeContentBox.right, nodeContentBox.cy));
parent.setLayoutVector(new kity.Vector(1, 0));
} else {
parent.setVertexOut(new kity.Point(nodeContentBox.left, nodeContentBox.cy));
parent.setLayoutVector(new kity.Vector(-1, 0));
}
for (i = 0; i < children.length; i++) {
child = children[i];
childTreeBox = childTreeBoxes[i];
childContentBox = child.getContentBox();
if (!childContentBox.height) continue;
// 水平方向上的布局
if (side == 'right') {
x = nodeContentBox.right - childContentBox.left;
x += parent.getStyle('margin-right') + child.getStyle('margin-left');
} else {
x = nodeContentBox.left - childContentBox.right;
x -= parent.getStyle('margin-left') + child.getStyle('margin-right');
}
if (i > 0) {
y += children[i].getStyle('margin-top');
}
// 竖直方向上的布局
y -= childTreeBox.top;
// 设置布局结果
transform = new kity.Matrix().translate(x, y);
child.setLayoutTransform(transform);
y += childTreeBox.bottom + child.getStyle('margin-bottom');
}
if (parent.isRoot()) {
var branchBox = this.getBranchBox(children);
var dy = branchBox.cy - nodeContentBox.cy;
children.forEach(function(child) {
child.getLayoutTransform().translate(0, -dy);
});
}
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = 5;
hint.push({
type: 'up',
node: node,
area: {
x: box.x,
y: box.top - node.getStyle('margin-top') - offset,
width: box.width,
height: node.getStyle('margin-top')
},
path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
});
hint.push({
type: 'down',
node: node,
area: {
x: box.x,
y: box.bottom + offset,
width: box.width,
height: node.getStyle('margin-bottom')
},
path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
});
return hint;
}
}));
\ No newline at end of file
/* global Layout:true */
window.layoutSwitch = true;
KityMinder.registerLayout('filetree', kity.createClass({
base: Layout,
doLayout: function(node) {
var layout = this;
doLayout: function(parent, children) {
var pBox = parent.getContentBox();
var indent = 20;
if (node.isLayoutRoot()) {
this.doLayoutRoot(node);
} else {
this.arrange(node);
}
},
doLayoutRoot: function(root) {
this.arrange(root);
},
arrange: function(node) {
var children = node.getChildren();
var _this = this;
if (!children.length) {
return false;
} else {
// 计算每个 child 的树所占的矩形区域
var childTreeBoxes = children.map(function(node, index, children) {
var box = _this.getTreeBox([node]);
return box;
});
var nodeContentBox = node.getContentBox();
var i, x, y, child, childTreeBox, childContentBox;
var transform = new kity.Matrix();
node.setVertexOut(new kity.Point(0, nodeContentBox.bottom));
node.setLayoutVector(new kity.Vector(0, 1));
y = nodeContentBox.bottom + node.getStyle('margin-bottom');
parent.setVertexOut(new kity.Point(pBox.left + indent, pBox.bottom));
parent.setLayoutVectorOut(new kity.Vector(0, 1));
for (i = 0; i < children.length; i++) {
child = children[i];
childTreeBox = childTreeBoxes[i];
childContentBox = child.getContentBox();
if (!children.length) return;
x = child.getStyle('margin-left') - childContentBox.left;
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
if (!childContentBox.width) continue;
child.setVertexIn(new kity.Point(cbox.left, cbox.cy));
child.setLayoutVectorIn(new kity.Vector(1, 0));
});
y += child.getStyle('margin-top');
y -= childTreeBox.top;
this.align(children, 'left');
this.stack(children, 'y');
// 设置布局结果
transform = new kity.Matrix().translate(x, y);
var xAdjust = 0;
xAdjust += pBox.left;
xAdjust += indent;
xAdjust += children[0].getStyle('margin-left');
var yAdjust = 0;
yAdjust += pBox.bottom;
yAdjust += parent.getStyle('margin-bottom');
yAdjust += children[0].getStyle('margin-top');
child.setLayoutTransform(transform);
this.move(children, xAdjust, yAdjust);
y += childTreeBox.bottom + child.getStyle('margin-bottom');
}
}
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
......@@ -86,16 +65,4 @@ KityMinder.registerLayout('filetree', kity.createClass({
});
return hint;
}
}));
KityMinder.registerConnectProvider('filetree', function(node, parent, connection) {
var box = node.getLayoutBox(),
pBox = parent.getLayoutBox();
var pathData = [];
var left = parent.getLayoutPoint().x;
var r = Math.round;
pathData.push('M', new kity.Point(r(left), r(pBox.bottom)));
pathData.push('L', new kity.Point(r(left), r(box.cy)));
pathData.push('L', new kity.Point(r(box.left), r(box.cy)));
connection.setPathData(pathData);
});
\ No newline at end of file
}));
\ No newline at end of file
/* global Layout:true */
window.layoutSwitch = true;
KityMinder.registerLayout('left', kity.createClass({
KityMinder.registerLayout('mind', kity.createClass({
base: Layout,
doLayout: function(node) {
var children = node.getChildren();
if (!children.length) {
return false;
}
var nbox = node.getContentBox();
node.setVertexOut(new kity.Point(nbox.left, nbox.cy));
node.setLayoutVector(new kity.Vector(-1, 0));
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
doLayout: function(node, children) {
var layout = this;
var half = Math.ceil(children.length / 2);
var right = children.slice(0, half);
var left = children.slice(half);
child.setVertexIn(new kity.Point(cbox.right, cbox.cy));
});
this.align(children, 'right');
this.stack(children, 'y');
var bbox = this.getBranchBox(children);
var xAdjuxt = nbox.left - node.getStyle('margin-left') - children[0].getStyle('margin-right');
var yAdjust = nbox.height / 2 + nbox.top - bbox.height / 2;
var leftLayout = KityMinder.getLayoutInstance('left');
var rightLayout = KityMinder.getLayoutInstance('right');
leftLayout.doLayout(node, left);
rightLayout.doLayout(node, right);
this.move(children, 0, yAdjust);
var box = node.getContentBox();
node.setVertexOut(box.cx, box.cy);
node.setLayoutVectorOut(new kity.Vector(0, 0));
},
getOrderHint: function(node) {
......@@ -65,17 +49,4 @@ KityMinder.registerLayout('left', kity.createClass({
});
return hint;
}
}));
// KityMinder.registerConnectProvider('bottom', function(node, parent, connection) {
// var pout = parent.getLayoutVertexOut(),
// pin = node.getLayoutVertexIn();
// var pathData = [];
// var r = Math.round;
// pathData.push('M', new kity.Point(r(pout.x), pout.y));
// pathData.push('L', new kity.Point(r(pout.x), pout.y + parent.getStyle('margin-bottom')));
// pathData.push('L', new kity.Point(r(pin.x), pout.y + parent.getStyle('margin-bottom')));
// pathData.push('L', new kity.Point(r(pin.x), pin.y));
// connection.setMarker(null);
// connection.setPathData(pathData);
// });
\ No newline at end of file
}));
\ No newline at end of file
/* global Layout:true */
window.layoutSwitch = true;
KityMinder.registerLayout('right', kity.createClass({
base: Layout,
doLayout: function(node) {
var children = node.getChildren();
if (!children.length) {
return false;
}
var nbox = node.getContentBox();
node.setVertexOut(new kity.Point(nbox.right, nbox.cy));
node.setLayoutVector(new kity.Vector(1, 0));
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
child.setVertexIn(new kity.Point(cbox.left, cbox.cy));
});
// 所有子节点左对齐到当前节点的 0 点
this.align(children, 'left');
// 所有子节点在 y 方向堆叠
this.stack(children, 'y');
// 获取子节点对齐并堆叠后所占的空间
var bbox = this.getBranchBox(children);
var xAdjust = nbox.right + node.getStyle('margin-right') + children[0].getStyle('margin-left');
var yAdjust = nbox.height / 2 + nbox.top - bbox.height / 2;
this.move(children, xAdjust, yAdjust);
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = 5;
hint.push({
type: 'up',
node: node,
area: {
x: box.x,
y: box.top - node.getStyle('margin-top') - offset,
width: box.width,
height: node.getStyle('margin-top')
},
path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
});
hint.push({
type: 'down',
node: node,
area: {
x: box.x,
y: box.bottom + offset,
width: box.width,
height: node.getStyle('margin-bottom')
},
path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
});
return hint;
}
}));
// KityMinder.registerConnectProvider('bottom', function(node, parent, connection) {
// var pout = parent.getLayoutVertexOut(),
// pin = node.getLayoutVertexIn();
// var pathData = [];
// var r = Math.round;
// pathData.push('M', new kity.Point(r(pout.x), pout.y));
// pathData.push('L', new kity.Point(r(pout.x), pout.y + parent.getStyle('margin-bottom')));
// pathData.push('L', new kity.Point(r(pin.x), pout.y + parent.getStyle('margin-bottom')));
// pathData.push('L', new kity.Point(r(pin.x), pin.y));
// connection.setMarker(null);
// connection.setPathData(pathData);
// });
\ No newline at end of file
......@@ -109,7 +109,14 @@ KityMinder.registerModule('ArrangeModule', {
'arrangedown': ArrangeDownCommand,
'arrange': ArrangeCommand
},
addShortcutKeys: {
contextmenu: [{
command: 'arrangeup'
}, {
command: 'arrangedown'
}, {
divider: true
}],
commandShortcutKeys: {
'arrangeup': 'alt+Up',
'arrangedown': 'alt+Down'
}
......
......@@ -83,7 +83,7 @@ KityMinder.registerModule('basestylemodule', function() {
}
})
},
addShortcutKeys: {
shortcutKeys: {
'bold': 'ctrl+b', //bold
'italic': 'ctrl+i' //italic
}
......
......@@ -90,6 +90,9 @@ var TreeDragger = kity.createClass('TreeDragger', {
if (!this._startPosition) return;
var movement = kity.Vector.fromPoints(this._dragPosition || this._startPosition, position);
var minder = this._minder;
this._dragPosition = position;
if (!this._dragMode) {
......@@ -102,14 +105,11 @@ var TreeDragger = kity.createClass('TreeDragger', {
}
}
var movement = kity.Vector.fromPoints(this._startPosition, this._dragPosition);
var minder = this._minder;
for (var i = 0; i < this._dragSources.length; i++) {
this._dragSources[i].setLayoutOffset(this._dragSourceOffsets[i].offset(movement));
this._dragSources[i].setLayoutOffset(this._dragSources[i].getLayoutOffset().offset(movement));
minder.applyLayoutResult(this._dragSources[i]);
}
if (!this._dropTest()) {
this._orderTest();
} else {
......@@ -119,6 +119,7 @@ var TreeDragger = kity.createClass('TreeDragger', {
dragEnd: function() {
this._startPosition = null;
this._dragPosition = null;
if (!this._dragMode) {
return;
......@@ -131,6 +132,8 @@ var TreeDragger = kity.createClass('TreeDragger', {
this._dragSources.forEach(function(source) {
source.setLayoutOffset(null);
});
this._minder.layout(-1);
this._minder.execCommand('movetoparent', this._dragSources, this._dropSucceedTarget);
......@@ -158,6 +161,7 @@ var TreeDragger = kity.createClass('TreeDragger', {
} else {
this._minder.fire('savescene');
}
this._minder.layout(300);
this._leaveDragMode();
this._minder.fire('contentchange');
},
......@@ -189,9 +193,6 @@ var TreeDragger = kity.createClass('TreeDragger', {
// 则排除枚举目标作为拖放源,否则加入拖放源
_calcDragSources: function() {
this._dragSources = this._minder.getSelectedAncestors();
this._dragSourceOffsets = this._dragSources.map(function(src) {
return src.getLayoutOffset();
});
},
_fadeDragSources: function(opacity) {
......
......@@ -70,10 +70,33 @@ KityMinder.registerModule('Expand', function() {
};
function setExpandState(node, state, policy) {
var changed = node.isExpanded() ? (state == STATE_COLLAPSE) : (state == STATE_EXPAND);
policy = policy || EXPAND_POLICY.KEEP_STATE;
policy(node, state, policy);
node.renderTree();
node.getMinder().layout(100);
if (!changed) return;
if (state == STATE_EXPAND) {
var m = node.getGlobalLayoutTransform();
node.traverse(function(child) {
child.setGlobalLayoutTransform(m);
child.getRenderContainer().fadeIn();
}, true);
node.renderTree().getMinder().layout(30);
} else {
node.traverse(function(child) {
child.setLayoutTransform(null);
child.getRenderContainer().fadeOut();
}, true);
node.getMinder().applyLayoutResult(node, 30).then(function() {
node.renderTree();
});
}
}
// 将展开的操作和状态读取接口拓展到 MinderNode 上
......@@ -175,7 +198,7 @@ KityMinder.registerModule('Expand', function() {
var pathData = ['M', 1.5 - this.radius, 0, 'L', this.radius - 1.5, 0];
if (state == STATE_COLLAPSE) {
pathData.push(['M', 0, 1.5 - this.radius, 'L', 0, this.radius - 1.5]);
}
}
this.sign.setPathData(pathData);
}
});
......@@ -203,7 +226,7 @@ KityMinder.registerModule('Expand', function() {
expander.setState(visible && node.children.length ? node.getData(EXPAND_STATE_DATA) : 'hide');
var vector = node.getLayoutVector().normalize(expander.radius + node.getStyle('stroke-width'));
var vector = node.getLayoutVectorOut().normalize(expander.radius + node.getStyle('stroke-width'));
var position = node.getVertexOut().offset(vector);
this.expander.setTranslate(position);
......
......@@ -90,7 +90,6 @@ KityMinder.registerModule("HistoryModule", function() {
selectedNodes.push(child);
}
km.appendNode(child, parent);
child._lastLayoutTransform = parent._lastLayoutTransform;
child.render();
var children = utils.cloneArr(child.children);
......@@ -219,9 +218,9 @@ KityMinder.registerModule("HistoryModule", function() {
}
})
},
addShortcutKeys: {
"Undo": "ctrl+z", //undo
"Redo": "ctrl+y" //redo
commandShortcutKeys: {
"undo": "ctrl+z", //undo
"redo": "ctrl+y" //redo
},
"events": {
"saveScene": function(e) {
......@@ -229,7 +228,6 @@ KityMinder.registerModule("HistoryModule", function() {
},
"import": function() {
this.historyManager.reset();
// this.historyManager.saveScene();
}
}
};
......
......@@ -127,6 +127,7 @@ KityMinder.registerModule('KeyboardModule', function() {
km.select(nextNode, true);
}
}
// 稀释用
var lastFrame;
return {
'events': {
......@@ -143,57 +144,12 @@ KityMinder.registerModule('KeyboardModule', function() {
if (keyEvent.shiftKey && keyEvent.keyCode == KityMinder.keymap.Tab) e.preventDefault();
},
'normal.keydown': function(e) {
var keys = KityMinder.keymap;
var node = e.getTargetNode();
var lang = this.getLang();
if (this.receiver) this.receiver.keydownNode = node;
var keyEvent = e.originEvent;
if (keyEvent.altKey || keyEvent.ctrlKey || keyEvent.metaKey || keyEvent.shiftKey) {
if ([keys.Tab].indexOf(keyEvent.keyCode)) e.preventDefault;
return;
}
switch (keyEvent.keyCode) {
case keys.Enter:
this.execCommand('AppendSiblingNode', lang.topic);
e.preventDefault();
break;
case keys.Tab:
this.execCommand('AppendChildNode', lang.topic);
e.preventDefault();
break;
case keys.Backspace:
case keys.Del:
e.preventDefault();
this.execCommand('RemoveNode');
break;
case keys.F2:
e.preventDefault();
this.execCommand('EditNode');
break;
case keys.Left:
navigateTo(this, 'left');
e.preventDefault();
break;
case keys.Up:
navigateTo(this, 'top');
e.preventDefault();
break;
case keys.Right:
navigateTo(this, 'right');
e.preventDefault();
break;
case keys.Down:
navigateTo(this, 'down');
e.preventDefault();
break;
}
var minder = this;
['left', 'right', 'up', 'down'].forEach(function(key) {
if (e.isShortcutKey(key)) {
navigateTo(minder, key == 'up' ? 'top' : key);
}
});
},
'normal.keyup': function(e) {
if (browser.ipad) {
......
......@@ -5,11 +5,11 @@ var AppendChildCommand = kity.createClass('AppendChildCommand', {
if (!parent) {
return null;
}
text = text || km.getLang(parent.isRoot() ? 'maintopic' : 'topic');
parent.expand();
var node = km.createNode(text, parent);
km.select(node, true);
node.render();
node._lastLayoutTransform = parent._lastLayoutTransform;
km.layout(300);
},
queryState: function(km) {
......@@ -26,10 +26,10 @@ var AppendSiblingCommand = kity.createClass('AppendSiblingCommand', {
if (!parent) {
return km.execCommand('AppendChildNode', text);
}
text = text || km.getLang(parent.isRoot() ? 'maintopic' : 'topic');
var node = km.createNode(text, parent, sibling.getIndex() + 1);
km.select(node, true);
node.render();
node._lastLayoutTransform = sibling._lastLayoutTransform;
km.layout(300);
},
queryState: function(km) {
......@@ -82,45 +82,31 @@ var EditNodeCommand = kity.createClass('EditNodeCommand', {
KityMinder.registerModule('NodeModule', function() {
return {
commands: {
'AppendChildNode': AppendChildCommand,
'AppendSiblingNode': AppendSiblingCommand,
'RemoveNode': RemoveNodeCommand,
'EditNode': EditNodeCommand
},
'contextmenu': [{
label: this.getLang('node.appendsiblingnode'),
exec: function() {
this.execCommand('AppendSiblingNode', this.getLang('topic'));
},
cmdName: 'appendsiblingnode'
command: 'appendsiblingnode'
}, {
label: this.getLang('node.appendchildnode'),
exec: function() {
this.execCommand('AppendChildNode', this.getLang('topic'));
},
cmdName: 'appendchildnode'
command: 'appendchildnode'
}, {
label: this.getLang('node.editnode'),
exec: function() {
this.execCommand('EditNode');
},
cmdName: 'editnode'
command: 'editnode'
}, {
label: this.getLang('node.removenode'),
cmdName: 'RemoveNode'
command: 'removenode'
}, {
divider: 1
},{
label: this.getLang('insert.topic'),
exec: function() {
this.select(this.getRoot());
this.execCommand('AppendSiblingNode', this.getLang('topic'));
},
query:function(){
var nodes = this.getSelectedNodes();
return nodes.length === 0 ? 0 : -1;
}
}]
}],
'commandShortcutKeys': {
'appendsiblingnode': 'Enter',
'appendchildnode': 'Insert|Tab',
'editnode': 'F2',
'removenode': 'Delete|Backspace'
}
};
});
\ No newline at end of file
/**
* @fileOverview
*
* 默认模板 - 脑图模板
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerTemplate('default', {
getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout');
var level = node.getLevel();
// 根节点
if (level === 0) {
return 'mind';
}
// 一级节点
if (level === 1) {
return node.getLayoutPointPreview().x > 0 ? 'right': 'left';
}
return node.parent.getLayout();
},
getConnect: function(node) {
if (node.getLevel() == 1) return 'arc';
return 'under';
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 文件夹模板
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerTemplate('filetree', {
getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout');
if (node.isRoot()) return 'bottom';
return 'filetree';
},
getConnect: function(node) {
if (node.getLevel() == 1) {
return 'poly';
}
return 'l';
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 往右布局结构模板
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerTemplate('right', {
getLayout: function(node) {
return node.getData('layout') || 'right';
},
getConnect: function(node) {
if (node.getLevel() == 1) return 'arc';
return 'bezier';
}
});
\ No newline at end of file
/**
* @fileOverview
*
* 组织结构图模板
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerTemplate('structure', {
getLayout: function(node) {
return node.getData('layout') || 'bottom';
}
});
KityMinder.registerTemplate('filetree', {
getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout');
if (node.isRoot()) return 'bottom';
},
return 'filetree';
getConnect: function(node) {
return 'poly';
}
});
\ No newline at end of file
......@@ -33,6 +33,7 @@ KityMinder.registerTheme('classic', {
'connect-color': 'white',
'connect-width': 2,
'main-connect-width': 3,
'connect-radius': 5,
'selected-background': 'rgb(254, 219, 0)',
......
......@@ -32,6 +32,7 @@ KityMinder.registerTheme('snow', {
'connect-color': 'white',
'connect-width': 2,
'main-connect-width': 3,
'connect-radius': 5,
'selected-background': 'rgb(254, 219, 0)',
......
/**
* @fileOverview
*
*
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerUI('contextmenu', function(minder) {
var mac = kity.Browser.mac;
function camel(word) {
return word.charAt(0).toUpperCase() + word.substr(1).toLowerCase();
}
var $menu = $('<ul>')
.addClass('km-context-menu fui-popup-menu')
.appendTo('#content-wrapper');
$menu.delegate('li', 'click', function(e, info) {
var item = $(e.target).data('menu');
if (item.command) {
minder.execCommand(item.command);
}
});
minder.on('contextmenu', function(e) {
e.preventDefault();
});
$('#content-wrapper').on('click', function(e) {
$menu.hide();
});
minder.on('mouseup', function(e) {
//e.preventDefault();
if (minder.getStatus() == 'hand' || !e.isRightMB()) return;
e = e.originEvent;
$menu.empty();
var ctxmenu = minder.getContextMenu();
var lastDivider = true;
ctxmenu.forEach(function(item) {
if (item.command && minder.queryCommandState(item.command) === 0) {
var label = minder.getLang('ui.command.' + item.command);
var $li = $('<li>')
.addClass('fui-item')
.append(label)
.data('menu', item)
.appendTo($menu);
var shortcuts = minder.getCommandShortcutKey(item.command);
if (shortcuts) {
shortcuts.split('|').forEach(function(shortcut) {
var $shortcut = $('<span>').addClass('shortcut').appendTo($li);
shortcut.split('+').forEach(function(key) {
$('<span>').addClass('shortcut-key ' + key.toLowerCase())
.text(camel(key))
.appendTo($shortcut);
});
if (mac) $shortcut.addClass('mac');
});
}
lastDivider = false;
}
if (item.divider && !lastDivider) {
$('<li>').addClass('divider').appendTo($menu);
lastDivider = true;
}
});
if (ctxmenu.length) {
$menu.show();
var x = e.pageX,
y = e.pageY,
width = $menu.outerWidth(),
height = $menu.outerHeight(),
clientWidth = document.body.clientWidth,
clientHeight = document.body.clientHeight;
if (x + width > clientWidth) x -= width;
if (y + height > clientHeight) y -= height;
$menu.offset({
left: x,
top: y
});
}
});
});
\ No newline at end of file
......@@ -53,7 +53,7 @@ KityMinder.registerUI('doc', function(minder) {
})['catch'](function(e) {
current = restore;
throw e;
console.error(e.stack);
}).then(function(doc) {
loading = false;
return doc;
......
......@@ -291,6 +291,7 @@ KityMinder.registerUI('menu/share/share', function(minder) {
function loadShareList() {
return fio.user.check().then(function(user) {
if (!user) return;
$.pajax(BACKEND_URL, {
type: 'GET',
......
......@@ -70,75 +70,6 @@
text-shadow: 0 1px black;
margin: 30px;
}
.shortcuts-key {
display: inline-block;
padding: 3px 8px 5px;
font-size: 14px;
font-weight: normal;
line-height: 14px;
color: hsl(0, 0%, 43%);
/* text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25); */
white-space: nowrap;
vertical-align: baseline;
background-color: hsl(0, 0%, 99%);
border-radius: 3px;
/* border: 1px solid hsl(0, 0%, 60%); */
text-transform: capitalize;
box-shadow: inset 0 -2px hsl(0, 0%, 92%), inset 0 -3px hsl(0, 100%, 100%), 0 1px 2px rgba(255, 255, 255, 0.3);
}
.mac .shortcuts-key.ctrl,
.mac .shortcuts-key.shift,
.mac .shortcuts-key.alt,
.shortcuts-key.up,
.shortcuts-key.down,
.shortcuts-key.left,
.shortcuts-key.right {
text-indent: -1000px;
position: relative;
width: 9px;
}
.mac .shortcuts-key.ctrl:after,
.mac .shortcuts-key.shift:after,
.mac .shortcuts-key.alt:after,
.shortcuts-key.up:after,
.shortcuts-key.down:after,
.shortcuts-key.left:after,
.shortcuts-key.right:after {
display: block;
position: absolute;
text-align: center;
left: 5px;
top: 4px;
width: 16px;
height: 16px;
text-indent: 0;
}
.mac .shortcuts-key.ctrl:after {
content: '⌘';
}
.mac .shortcuts-key.shift:after {
content: '⇧';
}
.mac .shortcuts-key.alt:after {
content: '⌥';
}
.shortcuts-key.up:after {
content: '↑';
top: 2px;
}
.shortcuts-key.down:after {
content: '↓';
top: 2px;
}
.shortcuts-key.left:after {
content: '←';
top: 2px;
}
.shortcuts-key.right:after {
content: '→';
top: 2px;
}
div.right {
float: right;
}
\ No newline at end of file
......@@ -20,6 +20,14 @@ html, body {
overflow: hidden;
.dock;
position: fixed;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none;
cursor: default;
}
#kityminder {
......
......@@ -172,3 +172,70 @@ input[type=url] {
from { opacity: 1; }
to { opacity: 0; }
}
.shortcut-key {
display: inline-block;
padding: 3px 8px 5px;
font-size: 14px;
font-weight: normal;
line-height: 14px;
color: hsl(0, 0%, 43%);
/* text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25); */
white-space: nowrap;
vertical-align: baseline;
background-color: hsl(0, 0%, 99%);
border-radius: 3px;
/* border: 1px solid hsl(0, 0%, 60%); */
text-transform: capitalize;
box-shadow: inset 0 -2px hsl(0, 0%, 92%), inset 0 -3px hsl(0, 100%, 100%), 0 1px 2px rgba(255, 255, 255, 0.3);
.mac &.ctrl,
.mac &.shift,
.mac &.alt,
&.up,
&.down,
&.left,
&.right {
text-indent: -1000px;
position: relative;
width: 9px;
&:after {
display: block;
position: absolute;
text-align: center;
left: 5px;
top: 4px;
width: 16px;
height: 16px;
text-indent: 0;
}
}
.mac &.ctrl:after {
content: '⌘';
}
.mac &.shift:after {
content: '⇧';
}
.mac &.alt:after {
content: '⌥';
}
&.up:after {
content: '↑';
top: 2px;
}
&.down:after {
content: '↓';
top: 2px;
}
&.left:after {
content: '←';
top: 2px;
}
&.right:after {
content: '→';
top: 2px;
}
}
......@@ -348,4 +348,97 @@
border: 1px solid #ccc;
box-shadow: 3px 3px 6px rgba(0, 0, 0, .3);
}
}
.fui-popup-menu {
position: absolute;
z-index: 99999999999;
min-width: 160px;
padding: 5px 0;
font-size: 12px;
list-style: none;
background-color: #ffffff;
border-radius: 0;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
background-clip: padding-box;
font-family: Arial, "Heiti SC", "Microsoft Yahei";
&:empty {
display: none !important;
}
.fui-panel-content, .fui-menu {
border: none;
display: block;
}
.fui-item {
.fui-label, .fui-icon {
height: 25px;
line-height: 25px;
}
display: block;
padding: 2px 15px 2px 30px;
height: 25px;
line-height: 25px;
clear: both;
font-weight: normal;
color: #333333;
white-space: nowrap;
text-decoration: none;
font-size: 12px;
transition: none;
&:hover, :focus {
background: #0099f2; /* Old browsers */
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwOTlmMiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjNDA5NmVlIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwNzZkZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=);
background: -moz-linear-gradient(top, #0099f2 0%, #4096ee 0%, #0076dd 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#0099f2), color-stop(0%,#4096ee), color-stop(100%,#0076dd)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #0099f2 0%,#4096ee 0%,#0076dd 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #0099f2 0%,#4096ee 0%,#0076dd 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #0099f2 0%,#4096ee 0%,#0076dd 100%); /* IE10+ */
background: hsl(222, 14%, 41%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0099f2', endColorstr='#0076dd',GradientType=0 ); /* IE6-8 */
color: white;
.fui-label {
color: white;
}
}
.shortcut {
float: right;
margin-left: 20px;
.shortcut-key {
font-size: 12px;
border: 1px solid #CCC;
height: 10px;
line-height: 10px;
margin-left: 3px;
}
+ .shortcut:after {
content: 'or';
position: relative;
left: 10px;
}
}
}
.divider, .fui-spliter {
height: 1px;
margin: 5px 0;
overflow: hidden;
background-color: #e5e5e5;
padding: 0;
&:first-child, &:last-child {
display: none;
}
}
}
\ No newline at end of file
......@@ -754,6 +754,74 @@ input[type=url]:focus {
opacity: 0;
}
}
.shortcut-key {
display: inline-block;
padding: 3px 8px 5px;
font-size: 14px;
font-weight: normal;
line-height: 14px;
color: #6e6e6e;
/* text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25); */
white-space: nowrap;
vertical-align: baseline;
background-color: #fcfcfc;
border-radius: 3px;
/* border: 1px solid hsl(0, 0%, 60%); */
text-transform: capitalize;
box-shadow: inset 0 -2px #ebebeb, inset 0 -3px #ffffff, 0 1px 2px rgba(255, 255, 255, 0.3);
}
.mac .shortcut-key.ctrl,
.mac .shortcut-key.shift,
.mac .shortcut-key.alt,
.shortcut-key.up,
.shortcut-key.down,
.shortcut-key.left,
.shortcut-key.right {
text-indent: -1000px;
position: relative;
width: 9px;
}
.mac .shortcut-key.ctrl:after,
.mac .shortcut-key.shift:after,
.mac .shortcut-key.alt:after,
.shortcut-key.up:after,
.shortcut-key.down:after,
.shortcut-key.left:after,
.shortcut-key.right:after {
display: block;
position: absolute;
text-align: center;
left: 5px;
top: 4px;
width: 16px;
height: 16px;
text-indent: 0;
}
.mac .shortcut-key.ctrl:after {
content: '⌘';
}
.mac .shortcut-key.shift:after {
content: '⇧';
}
.mac .shortcut-key.alt:after {
content: '⌥';
}
.shortcut-key.up:after {
content: '↑';
top: 2px;
}
.shortcut-key.down:after {
content: '↓';
top: 2px;
}
.shortcut-key.left:after {
content: '←';
top: 2px;
}
.shortcut-key.right:after {
content: '→';
top: 2px;
}
.triangle {
content: ' ';
display: block;
......@@ -1133,6 +1201,101 @@ li {
border: 1px solid #ccc;
box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.3);
}
.fui-popup-menu {
position: absolute;
z-index: 99999999999;
min-width: 160px;
padding: 5px 0;
font-size: 12px;
list-style: none;
background-color: #ffffff;
border-radius: 0;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);
background-clip: padding-box;
font-family: Arial, "Heiti SC", "Microsoft Yahei";
}
.fui-popup-menu:empty {
display: none !important;
}
.fui-popup-menu .fui-panel-content,
.fui-popup-menu .fui-menu {
border: none;
display: block;
}
.fui-popup-menu .fui-item {
display: block;
padding: 2px 15px 2px 30px;
height: 25px;
line-height: 25px;
clear: both;
font-weight: normal;
color: #333333;
white-space: nowrap;
text-decoration: none;
font-size: 12px;
transition: none;
}
.fui-popup-menu .fui-item .fui-label,
.fui-popup-menu .fui-item .fui-icon {
height: 25px;
line-height: 25px;
}
.fui-popup-menu .fui-item:hover,
.fui-popup-menu .fui-item :focus {
background: #0099f2;
/* Old browsers */
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwOTlmMiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjNDA5NmVlIiBzdG9wLW9wYWNpdHk9IjEiLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwNzZkZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgPC9saW5lYXJHcmFkaWVudD4KICA8cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSJ1cmwoI2dyYWQtdWNnZy1nZW5lcmF0ZWQpIiAvPgo8L3N2Zz4=);
background: -moz-linear-gradient(top, #0099f2 0%, #4096ee 0%, #0076dd 100%);
/* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #0099f2), color-stop(0%, #4096ee), color-stop(100%, #0076dd));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #0099f2 0%, #4096ee 0%, #0076dd 100%);
/* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #0099f2 0%, #4096ee 0%, #0076dd 100%);
/* Opera 11.10+ */
background: -ms-linear-gradient(top, #0099f2 0%, #4096ee 0%, #0076dd 100%);
/* IE10+ */
background: #5a6377;
/* W3C */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0099f2', endColorstr='#0076dd', GradientType=0);
/* IE6-8 */
color: white;
}
.fui-popup-menu .fui-item:hover .fui-label,
.fui-popup-menu .fui-item :focus .fui-label {
color: white;
}
.fui-popup-menu .fui-item .shortcut {
float: right;
margin-left: 20px;
}
.fui-popup-menu .fui-item .shortcut .shortcut-key {
font-size: 12px;
border: 1px solid #CCC;
height: 10px;
line-height: 10px;
margin-left: 3px;
}
.fui-popup-menu .fui-item .shortcut + .shortcut:after {
content: 'or';
position: relative;
left: 10px;
}
.fui-popup-menu .divider,
.fui-popup-menu .fui-spliter {
height: 1px;
margin: 5px 0;
overflow: hidden;
background-color: #e5e5e5;
padding: 0;
}
.fui-popup-menu .divider:first-child,
.fui-popup-menu .fui-spliter:first-child,
.fui-popup-menu .divider:last-child,
.fui-popup-menu .fui-spliter:last-child {
display: none;
}
/**
* 基本页面样式
*/
......@@ -1159,6 +1322,13 @@ body {
bottom: 0;
left: 0;
position: fixed;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-user-drag: none;
cursor: default;
}
#kityminder {
position: absolute;
......@@ -1194,7 +1364,7 @@ body {
line-height: 40px;
padding: 0 30px 0 15px;
z-index: 11;
background-color: hsl(0, 95%, 75%);
background-color: #fc8383;
}
#main-menu-btn:hover {
background-color: #fc9c9c !important;
......@@ -2646,74 +2816,6 @@ ul.resource-list li {
text-shadow: 0 1px black;
margin: 30px;
}
.shortcuts-key {
display: inline-block;
padding: 3px 8px 5px;
font-size: 14px;
font-weight: normal;
line-height: 14px;
color: #6e6e6e;
/* text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.25); */
white-space: nowrap;
vertical-align: baseline;
background-color: #fcfcfc;
border-radius: 3px;
/* border: 1px solid hsl(0, 0%, 60%); */
text-transform: capitalize;
box-shadow: inset 0 -2px #ebebeb, inset 0 -3px #ffffff, 0 1px 2px rgba(255, 255, 255, 0.3);
}
.mac .shortcuts-key.ctrl,
.mac .shortcuts-key.shift,
.mac .shortcuts-key.alt,
.shortcuts-key.up,
.shortcuts-key.down,
.shortcuts-key.left,
.shortcuts-key.right {
text-indent: -1000px;
position: relative;
width: 9px;
}
.mac .shortcuts-key.ctrl:after,
.mac .shortcuts-key.shift:after,
.mac .shortcuts-key.alt:after,
.shortcuts-key.up:after,
.shortcuts-key.down:after,
.shortcuts-key.left:after,
.shortcuts-key.right:after {
display: block;
position: absolute;
text-align: center;
left: 5px;
top: 4px;
width: 16px;
height: 16px;
text-indent: 0;
}
.mac .shortcuts-key.ctrl:after {
content: '⌘';
}
.mac .shortcuts-key.shift:after {
content: '⇧';
}
.mac .shortcuts-key.alt:after {
content: '⌥';
}
.shortcuts-key.up:after {
content: '↑';
top: 2px;
}
.shortcuts-key.down:after {
content: '↓';
top: 2px;
}
.shortcuts-key.left:after {
content: '←';
top: 2px;
}
.shortcuts-key.right:after {
content: '→';
top: 2px;
}
div.right {
float: right;
}
......
This diff is collapsed.
......@@ -47,6 +47,12 @@ KityMinder.registerUI('topbar/user', function(minder) {
$userButton.on('click', function() {
$userMenu.open();
var $dom = $($userMenu.getElement());
var $button = $($userButton.getElement());
$dom.offset({
left: $button.offset().left - $dom.outerWidth() + $button.outerWidth() - 10,
top: $button.offset().top + $button.outerHeight() + 10
});
});
menu.on('select', function(e, info) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment