Commit 3b10eca2 authored by techird's avatar techird

残暴的更新

parent 24909964
......@@ -10,7 +10,6 @@
"browser": true,
"boss": true,
"predef" : [
"define",
"Promise"
"define"
]
}
\ No newline at end of file
......@@ -8,10 +8,13 @@ module.exports = function(grunt) {
// These plugins provide necessary tasks.
/* [Build plugin & task ] ------------------------------------*/
grunt.loadNpmTasks('grunt-module-dependence');
grunt.loadNpmTasks('grunt-replace');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
var pkg = grunt.file.readJSON('package.json');
var banner = '/*!\n' +
' * ====================================================\n' +
' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
......@@ -29,7 +32,7 @@ module.exports = function(grunt) {
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
pkg: pkg,
clean: {
last: 'release'
......
......@@ -10,7 +10,7 @@ KityMinder 是一款强大的脑图可视化/编辑工具,由百度 FEX 团队
* 包括脑图数据的可视化展示(Json 格式)
* 包括简单的编辑功能(节点创建、编辑、删除)。更加强大编辑功能的 KityMinder 编辑器请移步 [kityminder-editor](https://github.com/fex-team/kityminder-editor)
* 不包含第三方格式(FreeMind、XMind、MindManager、纯文本、Markdown 等)的支持,可以加载 [kityminder-protocol](https://github.com/fex-team/kityminder-protocol) 来扩展第三方格式支持。
* 不包含文件存储的支持,需要自行实现存储。可参照[百度脑图](https://github.com/fex-team/naotu.baidu.com) 中的开源的 fio + 百度网盘方案进行实现。
* 不包含文件存储的支持,需要自行实现存储。可参照[百度脑图](https://github.com/fex-team/naotu.baidu.com)中的开源的 fio + 百度网盘方案进行实现。
## 使用
......
......@@ -5,6 +5,8 @@
<title>KityMinder Example</title>
<link href="favicon.ico" type="image/x-icon" rel="shortcut icon">
<link rel="stylesheet" href="src/kityminder.css" rel="stylesheet">
<style type="text/css">
body {
margin: 0;
......@@ -12,11 +14,6 @@
height: 100%;
}
.km_receiver {
background: white;
border: 1px solid #999;
}
#minder-view {
position: absolute;
border: 1px solid #ccc;
......@@ -30,7 +27,29 @@
<script type="text/javascript" src="lib/kity/dist/kity.min.js"></script>
</head>
<body>
<div id="minder-view"></div>
<script id="minder-view" type="application/kityminder" minder-data-type="json">
{
"root": {
"data": {
"text": "百度产品",
"image": "https://ss0.bdstatic.com/5a21bjqh_Q23odCf/static/superplus/img/logo_white.png?v=md5",
"imageSize": { "width": 270, "height": 129 }
},
"children": [
{ "data": { "text": "新闻" } },
{ "data": { "text": "网页", "priority": 1 } },
{ "data": { "text": "贴吧", "priority": 2 } },
{ "data": { "text": "知道", "priority": 2 } },
{ "data": { "text": "音乐", "priority": 3 } },
{ "data": { "text": "图片", "priority": 3 } },
{ "data": { "text": "视频", "priority": 3 } },
{ "data": { "text": "地图", "priority": 3 } },
{ "data": { "text": "百科", "priority": 3 } },
{ "data": { "text": "更多", "hyperlink": "http://www.baidu.com/more" } }
]
}
}
</script>
</body>
<!-- *************************** Module 形式加载引入 **************************** -->
......@@ -44,21 +63,20 @@ define('start', function(require) {
var Minder = require('kityminder').Minder;
// 创建 km 实例
var km = window.km = new Minder({
renderTo: 'minder-view'
});
var km = window.km = new Minder();
km.setup('#minder-view');
});
seajs.use('start');
</script>
<!-- *********************** 打包文件引入(需要先 grunt 发布) ************************* -->
<!--
<script type="text/javascript" src="../release/kityminder.core.min.js"></script>
<!-- <script type="text/javascript" src="release/kityminder.core.js"></script>
<script type="text/javascript">
// 创建 km 实例
window.km = new kityminder.Minder({
renderTo: 'minder-view'
});
/* global kityminder */
var km = window.km = new kityminder.Minder();
km.setup('#minder-view');
</script>
-->
-->
</html>
\ No newline at end of file
0 info it worked if it ends with ok
1 verbose cli [ 'node', '/usr/local/bin/npm', 'install', '-g', 'api-doc' ]
2 info using npm@2.1.11
3 info using node@v0.10.33
4 verbose node symlink /usr/local/bin/node
5 silly cache add args [ 'api-doc', null ]
6 verbose cache add spec api-doc
7 silly cache add parsed spec { raw: 'api-doc',
7 silly cache add scope: null,
7 silly cache add name: 'api-doc',
7 silly cache add rawSpec: '',
7 silly cache add spec: '*',
7 silly cache add type: 'range' }
8 verbose addNamed api-doc@*
9 silly addNamed semver.valid null
10 silly addNamed semver.validRange *
11 silly addNameRange { name: 'api-doc', range: '*', hasData: false }
12 silly mapToRegistry name api-doc
13 silly mapToRegistry using default registry
14 silly mapToRegistry registry https://registry.npmjs.org/
15 silly mapToRegistry uri https://registry.npmjs.org/api-doc
16 verbose addNameRange registry:https://registry.npmjs.org/api-doc not in flight; fetching
17 verbose request uri https://registry.npmjs.org/api-doc
18 verbose request no auth needed
19 info attempt registry request try #1 at 14:28:41
20 verbose request id 0fc1298b3ee5a6d7
21 http request GET https://registry.npmjs.org/api-doc
22 http 404 https://registry.npmjs.org/api-doc
23 verbose headers { date: 'Fri, 12 Dec 2014 06:28:42 GMT',
23 verbose headers server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)',
23 verbose headers 'content-type': 'application/json',
23 verbose headers 'cache-control': 'max-age=0',
23 verbose headers 'content-length': '52',
23 verbose headers 'accept-ranges': 'bytes',
23 verbose headers via: '1.1 varnish',
23 verbose headers 'x-served-by': 'cache-ty67-TYO',
23 verbose headers 'x-cache': 'MISS',
23 verbose headers 'x-cache-hits': '0',
23 verbose headers 'x-timer': 'S1418365722.046844,VS0,VE182',
23 verbose headers 'keep-alive': 'timeout=10, max=50',
23 verbose headers connection: 'Keep-Alive' }
24 silly get cb [ 404,
24 silly get { date: 'Fri, 12 Dec 2014 06:28:42 GMT',
24 silly get server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)',
24 silly get 'content-type': 'application/json',
24 silly get 'cache-control': 'max-age=0',
24 silly get 'content-length': '52',
24 silly get 'accept-ranges': 'bytes',
24 silly get via: '1.1 varnish',
24 silly get 'x-served-by': 'cache-ty67-TYO',
24 silly get 'x-cache': 'MISS',
24 silly get 'x-cache-hits': '0',
24 silly get 'x-timer': 'S1418365722.046844,VS0,VE182',
24 silly get 'keep-alive': 'timeout=10, max=50',
24 silly get connection: 'Keep-Alive' } ]
25 verbose stack Error: 404 Not Found: api-doc
25 verbose stack at CachingRegistryClient.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:239:14)
25 verbose stack at Request._callback (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:172:14)
25 verbose stack at Request.self.callback (/usr/local/lib/node_modules/npm/node_modules/request/request.js:372:22)
25 verbose stack at Request.emit (events.js:98:17)
25 verbose stack at Request.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1317:14)
25 verbose stack at Request.emit (events.js:117:20)
25 verbose stack at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1265:12)
25 verbose stack at IncomingMessage.emit (events.js:117:20)
25 verbose stack at _stream_readable.js:943:16
25 verbose stack at process._tickCallback (node.js:419:13)
26 verbose statusCode 404
27 verbose pkgid api-doc
28 verbose cwd /Users/techird/prj/km-core
29 error Darwin 14.0.0
30 error argv "node" "/usr/local/bin/npm" "install" "-g" "api-doc"
31 error node v0.10.33
32 error npm v2.1.11
33 error code E404
34 error 404 Not Found: api-doc
34 error 404
34 error 404 'api-doc' is not in the npm registry.
34 error 404 You should bug the author to publish it (or use the name yourself!)
34 error 404
34 error 404 Note that you can also install from a
34 error 404 tarball, folder, http url, or git url.
35 verbose exit [ 1, true ]
{
"name": "kityminder",
"title": "kityminder",
"description": "Kity Minder",
"version": "1.3.5",
"description": "KityMinder Core Implement",
"version": "1.4.0",
"homepage": "https://github.com/fex-team/kityminder-core",
"author": {
"name": "f-cube @ FEX",
"name": "Baidu FEX",
"url": "http://fex.baidu.com"
},
"repository": {
......@@ -30,10 +30,11 @@
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-module-dependence": "~0.1.4",
"grunt-module-dependence": "~0.2.0",
"grunt-contrib-concat": "~0.5.0",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-replace": "~0.8.0",
"grunt-contrib-clean": "~0.5.0"
}
......
......@@ -3,7 +3,7 @@ define(function(require, exports, module) {
function compatibility(json) {
var version = json.version || '1.1.3';
var version = json.version || (json.root ? '1.4.0' : '1.1.3');
switch (version) {
case '1.1.3':
......@@ -13,6 +13,14 @@ define(function(require, exports, module) {
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;
}
......@@ -71,5 +79,14 @@ define(function(require, exports, module) {
});
}
module.exports = compatibility;
function c_130_140(json) {
json.root = {
data: json.data,
children: json.children
};
delete json.data;
delete json.children;
}
return compatibility;
});
\ No newline at end of file
......@@ -5,10 +5,34 @@ define(function(require, exports, module) {
var MinderNode = require('./node');
var MinderEvent = require('./event');
var compatibility = require('./compatibility');
var Promise = require('./promise');
var protocols = {};
function registerProtocol(name, protocol) {
protocols[name] = protocol;
}
exports.registerProtocol = registerProtocol;
// 导入导出
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
......@@ -31,7 +55,9 @@ define(function(require, exports, module) {
return exported;
}
var json = exportNode(this.getRoot());
var json = {
root: exportNode(this.getRoot())
};
json.template = this.getTemplate();
json.theme = this.getTheme();
......@@ -43,7 +69,7 @@ define(function(require, exports, module) {
/**
* @method importJson()
* @for Minder
* @description 导入脑图数据,数据格式为 JSON,具体的数据字段形式请参考 [Data](data) 章节。
* @description 导入脑图数据,数据为 JSON 对象,具体的数据字段形式请参考 [Data](data) 章节。
*
* @grammar importJson(json) => {this}
*
......@@ -54,12 +80,11 @@ define(function(require, exports, module) {
function importNode(node, json, km) {
var data = json.data;
node.data = {};
for (var field in data) {
node.setData(field, data[field]);
}
node.setData('text', data.text);
var childrenTreeData = json.children || [];
for (var i = 0; i < childrenTreeData.length; i++) {
var childNode = km.createNode(null, node);
......@@ -82,9 +107,9 @@ define(function(require, exports, module) {
this.removeNode(this._root.getChildren()[0]);
}
json = Minder.compatibility(json);
json = compatibility(json);
importNode(this._root, json, this);
importNode(this._root, json.root, this);
this.setTemplate(json.template || 'default');
this.setTheme(json.theme || null);
......@@ -104,6 +129,77 @@ define(function(require, exports, module) {
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) {
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));
},
/**
* @method importData()
* @for Minder
* @description 使用指定的数据协议,导出脑图数据
*
* @grammar importData(protocol, callback) => Promise<json>
*
* @param {string} protocol 指定的用于解析数据的数据协议(默认内置三种数据协议 `json`、`text` 和 `markdown` 的支持)
* @param {any} data 要导入的数据
*/
importData: function(protocolName, data) {
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)).then(function(json) {
minder.importJson(json);
return json;
});
}
});
});
\ No newline at end of file
......@@ -159,15 +159,64 @@ define(function(require, exports, module) {
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));
window.addEventListener('blur', this._firePharse.bind(this));
}
},
_bindKeyboardEvents: function() {
if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
//只能在这里做,要不无法触发
listen(document.body, 'keydown keyup keypress paste', this._firePharse.bind(this));
}
if (this._keyboardReceiver) return;
var receiver = this._keyboardReceiver = document.createElement('input');
receiver.classList.add('km-receiver');
var renderTarget = this._renderTarget;
renderTarget.appendChild(receiver);
var minder = this;
listen(receiver, 'keydown keyup keypress copy paste blur focus input', function(e) {
switch (e.type) {
case 'blur':
minder.blur();
break;
case 'focus':
minder.focus();
break;
case 'input':
receiver.value = null;
break;
}
minder._firePharse(e);
e.preventDefault();
});
this.on('beforemousedown', function(e) {
this.focus();
e.preventDefault();
});
this.focus = function() {
if (!this.isFocused()) {
renderTarget.classList.add('focus');
receiver.select();
receiver.focus();
this.renderNodeBatch(this.getSelectedNodes());
}
return this;
};
this.blur = function() {
if (this.isFocused()) {
renderTarget.classList.remove('focus');
receiver.blur();
this.renderNodeBatch(this.getSelectedNodes());
}
return this;
};
this.focus();
},
isFocused: function() {
var renderTarget = this._renderTarget;
return renderTarget && renderTarget.classList.contains('focus');
},
_firePharse: function(e) {
......
......@@ -8,7 +8,7 @@
*/
define(function(require, exports, module) {
var kity = require('./kity.js');
var kity = require('./kity');
var utils = require('./utils');
var keymap = require('./keymap');
var Minder = require('./minder');
......
......@@ -30,7 +30,7 @@ define(function(require, exports, module) {
}
});
Minder.version = '1.3.6';
Minder.version = '1.4.0';
Minder.registerInitHook = function(hook) {
_initHooks.push(hook);
......
......@@ -46,6 +46,10 @@ define(function(require, exports, module) {
if (!moduleDeals) continue;
if (moduleDeals.defaultOptions) {
me.addDefaultOption(moduleDeals.defaultOptions);
}
if (moduleDeals.init) {
moduleDeals.init.call(me, this._options);
}
......
......@@ -8,14 +8,23 @@
*/
define(function(require, exports, module) {
var kity = require('./kity');
var utils = require('./utils');
var Minder = require('./minder');
Minder.registerInitHook(function(options) {
this._defaultOptions = {};
});
kity.extendClass(Minder, {
addDefaultOption: function(options) {
utils.extend(this._defaultOptions, options);
return this;
},
getOption: function(key) {
if (key) {
return this._options[key];
return this._options[key] || this._defaultOptions[key];
} else {
return this._options;
return utils.extend({}, this._defaultOptions, this._options);
}
}
});
......
......@@ -45,6 +45,15 @@ define(function(require, exports, module) {
target = document.getElementById(target);
}
if (target) {
if (target.tagName.toLowerCase() == 'script') {
var newTarget = document.createElement('div');
newTarget.id = target.id;
newTarget.class = target.class;
target.parentNode.insertBefore(newTarget, target);
target.parentNode.removeChild(target);
target = newTarget;
}
target.classList.add('km-view');
this._paper.renderTo(this._renderTarget = target);
this._bindEvents();
this.fire('paperrender');
......
define(function(require, exports, module) {
/*!
** Thenable -- Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable
** Copyright (c) 2013-2014 Ralf S. Engelschall <http://engelschall.com>
** Licensed under The MIT License <http://opensource.org/licenses/MIT>
** Source-Code distributed on <http://github.com/rse/thenable>
*/
/* promise states [Promises/A+ 2.1] */
var STATE_PENDING = 0; /* [Promises/A+ 2.1.1] */
var STATE_FULFILLED = 1; /* [Promises/A+ 2.1.2] */
var STATE_REJECTED = 2; /* [Promises/A+ 2.1.3] */
/* promise object constructor */
var Promise = function(executor) {
/* optionally support non-constructor/plain-function call */
if (!(this instanceof Promise))
return new Promise(executor);
/* initialize object */
this.id = 'Thenable/1.0.7';
this.state = STATE_PENDING; /* initial state */
this.fulfillValue = undefined; /* initial value */ /* [Promises/A+ 1.3, 2.1.2.2] */
this.rejectReason = undefined; /* initial reason */ /* [Promises/A+ 1.5, 2.1.3.2] */
this.onFulfilled = []; /* initial handlers */
this.onRejected = []; /* initial handlers */
/* support optional executor function */
if (typeof executor === 'function')
executor.call(this, this.fulfill.bind(this), this.reject.bind(this));
};
/* Promise API methods */
Promise.prototype = {
/* promise resolving methods */
fulfill: function(value) { return deliver(this, STATE_FULFILLED, 'fulfillValue', value); },
reject: function(value) { return deliver(this, STATE_REJECTED, 'rejectReason', value); },
/* 'The then Method' [Promises/A+ 1.1, 1.2, 2.2] */
then: function(onFulfilled, onRejected) {
var curr = this;
var next = new Promise(); /* [Promises/A+ 2.2.7] */
curr.onFulfilled.push(
resolver(onFulfilled, next, 'fulfill')); /* [Promises/A+ 2.2.2/2.2.6] */
curr.onRejected.push(
resolver(onRejected, next, 'reject')); /* [Promises/A+ 2.2.3/2.2.6] */
execute(curr);
return next; /* [Promises/A+ 2.2.7, 3.3] */
}
};
/* deliver an action */
var deliver = function(curr, state, name, value) {
if (curr.state === STATE_PENDING) {
curr.state = state; /* [Promises/A+ 2.1.2.1, 2.1.3.1] */
curr[name] = value; /* [Promises/A+ 2.1.2.2, 2.1.3.2] */
execute(curr);
}
return curr;
};
/* execute all handlers */
var execute = function(curr) {
if (curr.state === STATE_FULFILLED)
execute_handlers(curr, 'onFulfilled', curr.fulfillValue);
else if (curr.state === STATE_REJECTED)
execute_handlers(curr, 'onRejected', curr.rejectReason);
};
/* execute particular set of handlers */
var execute_handlers = function(curr, name, value) {
/* global process: true */
/* global setImmediate: true */
/* global setTimeout: true */
/* short-circuit processing */
if (curr[name].length === 0)
return;
/* iterate over all handlers, exactly once */
var handlers = curr[name];
curr[name] = []; /* [Promises/A+ 2.2.2.3, 2.2.3.3] */
var func = function() {
for (var i = 0; i < handlers.length; i++)
handlers[i](value); /* [Promises/A+ 2.2.5] */
};
/* execute procedure asynchronously */ /* [Promises/A+ 2.2.4, 3.1] */
if (typeof process === 'object' && typeof process.nextTick === 'function')
process.nextTick(func);
else if (typeof setImmediate === 'function')
setImmediate(func);
else
setTimeout(func, 0);
};
/* generate a resolver function */
var resolver = function(cb, next, method) {
return function(value) {
if (typeof cb !== 'function') /* [Promises/A+ 2.2.1, 2.2.7.3, 2.2.7.4] */
next[method].call(next, value); /* [Promises/A+ 2.2.7.3, 2.2.7.4] */
else {
var result;
try {
if (value instanceof Promise) {
result = value.then(cb);
}
else result = cb(value);
} /* [Promises/A+ 2.2.2.1, 2.2.3.1, 2.2.5, 3.2] */
catch (e) {
next.reject(e); /* [Promises/A+ 2.2.7.2] */
return;
}
resolve(next, result); /* [Promises/A+ 2.2.7.1] */
}
};
};
/* 'Promise Resolution Procedure' */ /* [Promises/A+ 2.3] */
var resolve = function(promise, x) {
/* sanity check arguments */ /* [Promises/A+ 2.3.1] */
if (promise === x) {
promise.reject(new TypeError('cannot resolve promise with itself'));
return;
}
/* surgically check for a 'then' method
(mainly to just call the 'getter' of 'then' only once) */
var then;
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try { then = x.then; } /* [Promises/A+ 2.3.3.1, 3.5] */
catch (e) {
promise.reject(e); /* [Promises/A+ 2.3.3.2] */
return;
}
}
/* handle own Thenables [Promises/A+ 2.3.2]
and similar 'thenables' [Promises/A+ 2.3.3] */
if (typeof then === 'function') {
var resolved = false;
try {
/* call retrieved 'then' method */ /* [Promises/A+ 2.3.3.3] */
then.call(x,
/* resolvePromise */ /* [Promises/A+ 2.3.3.3.1] */
function(y) {
if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
if (y === x) /* [Promises/A+ 3.6] */
promise.reject(new TypeError('circular thenable chain'));
else
resolve(promise, y);
},
/* rejectPromise */ /* [Promises/A+ 2.3.3.3.2] */
function(r) {
if (resolved) return; resolved = true; /* [Promises/A+ 2.3.3.3.3] */
promise.reject(r);
}
);
}
catch (e) {
if (!resolved) /* [Promises/A+ 2.3.3.3.3] */
promise.reject(e); /* [Promises/A+ 2.3.3.3.4] */
}
return;
}
/* handle other values */
promise.fulfill(x); /* [Promises/A+ 2.3.4, 2.3.3.4] */
};
Promise.resolve = function(value) {
return new Promise(function(resolve) {
resolve(value);
});
};
Promise.reject = function(reason) {
return new Promise(function(resolve, reject) {
reject(reason);
});
};
/* export API */
module.exports = Promise;
});
\ No newline at end of file
......@@ -64,8 +64,16 @@ define(function(require, exports, module) {
},
setTheme: function(name) {
var lastTheme = this._theme;
this._theme = name || null;
this.getRenderTarget().style.background = this.getStyle('background');
var container = this.getRenderTarget();
if (container) {
container.classList.remove('km-theme-' + lastTheme);
if (name) {
container.classList.add('km-theme-' + name);
}
container.style.background = this.getStyle('background');
}
this.fire('themechange', {
theme: name
});
......
define(function(require, exports) {
var kity = require('./kity.js');
var kity = require('./kity');
var uuidMap = {};
exports.extend = kity.Utils.extend.bind(kity.Utils);
......
.km-view {
font-family: "Microsoft Yahei", "Heiti SC", Arial, sans-serif;
-webkit-user-select: none;
user-select: none;
position: relative;
}
.km-view .km-receiver {
position: absolute;
left: -99999px;
top: -99999px;
width: 20px;
height: 20px;
outline: none;
margin: 0;
}
\ No newline at end of file
......@@ -14,26 +14,28 @@ define('kityminder', function(require, exports, module) {
};
// 核心导出,大写的部分导出类,小写的部分简单 require 一下
// 这里顺序是有讲究的,调整前先弄清楚依赖关系。
require('core/utils');
kityminder.Minder = require('core/minder');
kityminder.Command = require('core/command');
kityminder.Node = require('core/node');
require('core/option');
kityminder.Event = require('core/event');
kityminder.data = require('core/data');
require('core/compatibility');
kityminder.KeyMap = require('core/keymap');
require('core/key');
require('core/status');
require('core/paper');
require('core/select');
kityminder.Module = require('core/module');
kityminder.Data = require('core/data');
require('core/compatibility');
require('core/readonly');
kityminder.Render = require('core/render');
kityminder.Connect = require('core/connect');
kityminder.Layout = require('core/layout');
kityminder.Theme = require('core/theme');
kityminder.Template = require('core/template');
kityminder.Promise = require('core/promise');
// 模块依赖
require('module/arrange');
......@@ -59,6 +61,12 @@ define('kityminder', function(require, exports, module) {
require('module/view');
require('module/zoom');
require('protocol/json');
require('protocol/text');
require('protocol/markdown');
require('protocol/svg');
require('protocol/png');
require('layout/mind');
require('layout/btree');
require('layout/filetree');
......
......@@ -27,48 +27,48 @@ define(function(require, exports, module) {
hint.push({
type: 'up',
node: node,
area: {
area: new kity.Box({
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: {
area: new kity.Box({
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: {
area: new kity.Box({
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: {
area: new kity.Box({
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]
});
}
......
......@@ -60,24 +60,24 @@ define(function(require, exports, module) {
hint.push({
type: 'up',
node: node,
area: {
area: new kity.Box({
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: {
area: new kity.Box({
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;
......
......@@ -36,24 +36,24 @@ define(function(require, exports, module) {
hint.push({
type: 'up',
node: node,
area: {
area: new kity.Box({
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: {
area: new kity.Box({
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;
......
......@@ -6,7 +6,6 @@ define(function(require, exports, module) {
var Module = require('core/module');
// 矩形的变形动画定义
var MoveToParentCommand = kity.createClass('MoveToParentCommand', {
base: Command,
execute: function(minder, nodes, parent) {
......@@ -161,7 +160,7 @@ define(function(require, exports, module) {
hint.node.setLayoutOffset(null);
this._minder.execCommand('arrange', this._dragSources, index);
this._minder.execCommand('arrange', index);
this._renderOrderHint(null);
} else {
this._minder.fire('savescene');
......@@ -290,7 +289,7 @@ define(function(require, exports, module) {
var i, j, target, sourceBox, targetBox;
judge = judge || function(intersectBox, sourceBox, targetBox) {
return intersectBox;
return intersectBox && !intersectBox.isEmpty();
};
for (i = 0; i < targets.length; i++) {
......
......@@ -21,14 +21,14 @@ define(function(require, exports, module) {
if (target[p] === undefined) {
return false;
}
if (this.isObject(tmp) || this.isArray(tmp)) {
if (this.isObject(target[p]) !== this.isObject(tmp)) {
if (utils.isObject(tmp) || utils.isArray(tmp)) {
if (utils.isObject(target[p]) !== utils.isObject(tmp)) {
return false;
}
if (this.isArray(tmp) !== this.isArray(target[p])) {
if (utils.isArray(tmp) !== utils.isArray(target[p])) {
return false;
}
if (this.compareObject(tmp, target[p]) === false) {
if (compareObject(tmp, target[p]) === false) {
return false;
}
} else {
......
......@@ -35,8 +35,7 @@ define(function(require, exports, module) {
height: box.height + paddingTop + paddingBottom
};
var prefix = node.isSelected() ? 'selected-' : '';
var prefix = node.isSelected() ? (node.getMinder().isFocused() ? 'selected-' : 'blur-selected-') : '';
outline
.setPosition(outlineBox.x, outlineBox.y)
.setSize(outlineBox.width, outlineBox.height)
......
......@@ -53,11 +53,11 @@ define(function(require, exports, module) {
mask = new kity.Path().setPathData(MASK_PATH).setOpacity(0.8).setTranslate(0.5, 0.5);
number = new kity.Text()
.setX(this.width / 2 - 0.5).setY(this.height / 2 - 1.5)
.setX(this.width / 2 - 0.5).setY(this.height / 2)
.setTextAnchor('middle')
.setVerticalAlign('middle')
.setFontItalic(true)
.setFontSize(14)
.setFontSize(12)
.fill('white');
this.addShapes([back, mask, number]);
......
......@@ -37,9 +37,10 @@ define(function(require, exports, module) {
var height = (lineHeight * fontSize) * textArr.length - (lineHeight - 1) * fontSize;
var yStart = -height / 2;
var adjust = FONT_ADJUST[fontFamily] || 0;
textGroup.setTranslate(0, adjust * fontSize);
if (kity.Browser.ie) {
var adjust = FONT_ADJUST[fontFamily] || 0;
textGroup.setTranslate(0, adjust * fontSize);
}
var rBox = new kity.Box(),
r = Math.round;
......
......@@ -17,6 +17,7 @@ define(function(require, exports, module) {
this._minder.getViewDragger = function() {
return me;
};
this.setEnabled(false);
},
isEnabled: function() {
......@@ -300,7 +301,7 @@ define(function(require, exports, module) {
this.execCommand('camera', this.getRoot(), 800);
}
},
ready: function() {
'paperrender': function() {
this.execCommand('camera', null, 0);
this._lastClientSize = {
width: this.getRenderTarget().clientWidth,
......
define(function(require, exports, module) {
var data = require('../core/data');
data.registerProtocol('json', module.exports = {
fileDescription: 'KityMinder 格式',
fileExtension: '.km',
dataType: 'json',
mineType: 'application/json',
encode: function(json) {
return JSON.stringify(json);
},
decode: function(local) {
return JSON.parse(local);
}
});
});
\ No newline at end of file
define(function(require, exports, module) {
var data = require('../core/data');
var LINE_ENDING_SPLITER = /\r\n|\r|\n/;
var EMPTY_LINE = '';
var NOTE_MARK_START = '<!--Note-->';
var NOTE_MARK_CLOSE = '<!--/Note-->';
function encode(json) {
return _build(json, 1).join('\n');
}
function _build(node, level) {
var lines = [];
level = level || 1;
var sharps = _generateHeaderSharp(level);
lines.push(sharps + ' ' + node.data.text);
lines.push(EMPTY_LINE);
var note = node.data.note;
if (note) {
var hasSharp = /^#/.test(note);
if (hasSharp) {
lines.push(NOTE_MARK_START);
note = note.replace(/^#+/gm, function($0) {
return sharps + $0;
});
}
lines.push(note);
if (hasSharp) {
lines.push(NOTE_MARK_CLOSE);
}
lines.push(EMPTY_LINE);
}
if (node.children) node.children.forEach(function(child) {
lines = lines.concat(_build(child, level + 1));
});
return lines;
}
function _generateHeaderSharp(level) {
var sharps = '';
while (level--) sharps += '#';
return sharps;
}
function decode(markdown) {
var json,
parentMap = {},
lines, line, lineInfo, level, node, parent, noteProgress, codeBlock;
// 一级标题转换 `{title}\n===` => `# {title}`
markdown = markdown.replace(/^(.+)\n={3,}/, function($0, $1) {
return '# ' + $1;
});
lines = markdown.split(LINE_ENDING_SPLITER);
// 按行分析
for (var i = 0; i < lines.length; i++) {
line = lines[i];
lineInfo = _resolveLine(line);
// 备注标记处理
if (lineInfo.noteClose) {
noteProgress = false;
continue;
} else if (lineInfo.noteStart) {
noteProgress = true;
continue;
}
// 代码块处理
codeBlock = lineInfo.codeBlock ? !codeBlock : codeBlock;
// 备注条件:备注标签中,非标题定义,或标题越位
if (noteProgress || codeBlock || !lineInfo.level || lineInfo.level > level + 1) {
if (node) _pushNote(node, line);
continue;
}
// 标题处理
level = lineInfo.level;
node = _initNode(lineInfo.content, parentMap[level - 1]);
parentMap[level] = node;
}
_cleanUp(parentMap[1]);
return parentMap[1];
}
function _initNode(text, parent) {
var node = {
data: {
text: text,
note: ''
}
};
if (parent) {
if (parent.children) parent.children.push(node);
else parent.children = [node];
}
return node;
}
function _pushNote(node, line) {
node.data.note += line + '\n';
}
function _isEmpty(line) {
return !/\S/.test(line);
}
function _resolveLine(line) {
var match = /^(#+)?\s*(.*)$/.exec(line);
return {
level: match[1] && match[1].length || null,
content: match[2],
noteStart: line == NOTE_MARK_START,
noteClose: line == NOTE_MARK_CLOSE,
codeBlock: /^\s*```/.test(line)
};
}
function _cleanUp(node) {
if (!/\S/.test(node.data.note)) {
node.data.note = null;
delete node.data.note;
} else {
var notes = node.data.note.split('\n');
while (notes.length && !/\S/.test(notes[0])) notes.shift();
while (notes.length && !/\S/.test(notes[notes.length - 1])) notes.pop();
node.data.note = notes.join('\n');
}
if (node.children) node.children.forEach(_cleanUp);
}
data.registerProtocol('markdown', module.exports = {
fileDescription: 'Markdown/GFM 格式',
fileExtension: '.md',
mineType: 'text/markdown',
dataType: 'markdown',
encode: function(json) {
return encode(json);
},
decode: function(markdown) {
return decode(markdown);
}
});
});
\ No newline at end of file
define(function(require, exports, module) {
var kity = require('../core/kity');
var data = require('../core/data');
var Promise = require('../core/promise');
var DomURL = window.URL || window.webkitURL || window;
function loadImage(url, callback) {
return new Promise(function(resolve, reject) {
var image = document.createElement('img');
image.onload = function() {
resolve(this);
};
image.onerror = function(err) {
reject(err);
};
image.crossOrigin = '';
image.src = url;
});
}
function getSVGInfo(minder) {
var paper = minder.getPaper(),
paperTransform,
domContainer = paper.container,
svgXml,
svgContainer,
svgDom,
renderContainer = minder.getRenderContainer(),
renderBox = renderContainer.getRenderBox(),
width = renderBox.width + 1,
height = renderBox.height + 1,
blob, svgUrl, img;
// 保存原始变换,并且移动到合适的位置
paperTransform = paper.shapeNode.getAttribute('transform');
paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
renderContainer.translate(-renderBox.x, -renderBox.y);
// 获取当前的 XML 代码
svgXml = paper.container.innerHTML;
// 回复原始变换及位置
renderContainer.translate(renderBox.x, renderBox.y);
paper.shapeNode.setAttribute('transform', paperTransform);
// 过滤内容
svgContainer = document.createElement('div');
svgContainer.innerHTML = svgXml;
svgDom = svgContainer.querySelector('svg');
svgDom.setAttribute('width', renderBox.width + 1);
svgDom.setAttribute('height', renderBox.height + 1);
svgDom.setAttribute('style', 'font-family: Arial, "Microsoft Yahei","Heiti SC";');
svgContainer = document.createElement('div');
svgContainer.appendChild(svgDom);
svgXml = svgContainer.innerHTML;
// Dummy IE
svgXml = svgXml.replace(' xmlns="http://www.w3.org/2000/svg" ' +
'xmlns:NS1="" NS1:ns1:xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:NS2="" NS2:xmlns:ns1=""', '');
// svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
svgXml = svgXml.replace(/&nbsp;/g, '&#xa0;');
blob = new Blob([svgXml], {
type: 'image/svg+xml'
});
svgUrl = DomURL.createObjectURL(blob);
//svgUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgXml);
return {
width: width,
height: height,
dataUrl: svgUrl,
xml: svgXml
};
}
function encode(json, minder) {
var resultCallback;
/* 绘制 PNG 的画布及上下文 */
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
/* 尝试获取背景图片 URL 或背景颜色 */
var bgDeclare = minder.getStyle('background').toString();
var bgUrl = /url\((.+)\)/.exec(bgDeclare);
var bgColor = kity.Color.parse(bgDeclare);
/* 获取 SVG 文件内容 */
var svgInfo = getSVGInfo(minder);
var width = svgInfo.width;
var height = svgInfo.height;
var svgDataUrl = svgInfo.dataUrl;
/* 画布的填充大小 */
var padding = 20;
canvas.width = width + padding * 2;
canvas.height = height + padding * 2;
function fillBackground(ctx, style) {
ctx.save();
ctx.fillStyle = style;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
}
function drawImage(ctx, image, x, y) {
ctx.drawImage(image, x, y);
}
function generateDataUrl(canvas) {
return canvas.toDataURL('png');
}
function drawSVG() {
return loadImage(svgDataUrl).then(function(svgImage) {
drawImage(ctx, svgImage, padding, padding);
DomURL.revokeObjectURL(svgDataUrl);
return generateDataUrl(canvas);
});
}
if (bgUrl) {
return loadImage(bgUrl[1]).then(function(image) {
fillBackground(ctx, ctx.createPattern(image, 'repeat'));
return drawSVG();
});
} else {
fillBackground(ctx, bgColor.toString());
return drawSVG();
}
}
data.registerProtocol('png', module.exports = {
fileDescription: 'PNG 图片',
fileExtension: '.png',
mineType: 'image/png',
dataType: 'png',
encode: encode
});
});
\ No newline at end of file
define(function(require, exports, module) {
var data = require('../core/data');
data.registerProtocol('svg', module.exports = {
fileDescription: 'SVG 矢量图',
fileExtension: '.svg',
mineType: 'image/svg+xml',
dataType: 'svg',
encode: function(json, minder) {
var paper = minder.getPaper(),
paperTransform = paper.shapeNode.getAttribute('transform'),
svgXml,
svgContainer,
svgDom,
renderContainer = minder.getRenderContainer(),
renderBox = renderContainer.getRenderBox(),
transform = renderContainer.getTransform(),
width = renderBox.width,
height = renderBox.height,
padding = 20;
paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
svgXml = paper.container.innerHTML;
paper.shapeNode.setAttribute('transform', paperTransform);
svgContainer = document.createElement('div');
svgContainer.innerHTML = svgXml;
svgDom = svgContainer.querySelector('svg');
svgDom.setAttribute('width', width + padding * 2 | 0);
svgDom.setAttribute('height', height + padding * 2 | 0);
svgDom.setAttribute('style',
'font-family: Arial, "Microsoft Yahei", "Heiti SC"; ' +
'background: ' + minder.getStyle('background'));
svgDom.setAttribute('viewBox', [
renderBox.x - padding | 0,
renderBox.y - padding | 0,
width + padding * 2 | 0,
height + padding * 2 | 0
].join(' '));
svgContainer = document.createElement('div');
svgContainer.appendChild(svgDom);
// need a xml with width and height
svgXml = svgContainer.innerHTML;
// svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
svgXml = svgXml.replace(/&nbsp;/g, '&#xa0;');
// svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
return svgXml;
}
});
});
\ No newline at end of file
define(function(require, exports, module) {
var data = require('../core/data');
var LINE_ENDING = '\r',
LINE_ENDING_SPLITER = /\r\n|\r|\n/,
TAB_CHAR = '\t';
function repeat(s, n) {
var result = '';
while (n--) result += s;
return result;
}
function encode(json, level) {
var local = '';
level = level || 0;
local += repeat(TAB_CHAR, level);
local += json.data.text + LINE_ENDING;
if (json.children) {
json.children.forEach(function(child) {
local += encode(child, level + 1);
});
}
return local;
}
function isEmpty(line) {
return !/\S/.test(line);
}
function getLevel(line) {
var level = 0;
while (line.charAt(level) === TAB_CHAR) level++;
return level;
}
function getNode(line) {
return {
data: {
text: line.replace(new RegExp('^' + TAB_CHAR + '*'), '')
}
};
}
function decode(local) {
var json,
parentMap = {},
lines = local.split(LINE_ENDING_SPLITER),
line, level, node;
function addChild(parent, child) {
var children = parent.children || (parent.children = []);
children.push(child);
}
for (var i = 0; i < lines.length; i++) {
line = lines[i];
if (isEmpty(line)) continue;
level = getLevel(line);
node = getNode(line);
if (level === 0) {
if (json) {
throw new Error('Invalid local format');
}
json = node;
} else {
if (!parentMap[level - 1]) {
throw new Error('Invalid local format');
}
addChild(parentMap[level - 1], node);
}
parentMap[level] = node;
}
return json;
}
data.registerProtocol('text', module.exports = {
fileDescription: '大纲文本',
fileExtension: '.txt',
dataType: 'text',
mineType: 'text/plain',
encode: function(json) {
return encode(json, 0);
},
decode: function(local) {
return decode(local);
}
});
});
\ No newline at end of file
......@@ -44,6 +44,7 @@ define(function(require, exports, module) {
'selected-stroke': hsl(h, 26, 30),
'selected-stroke-width': '3',
'blur-selected-stroke': hsl(h, 10, 60),
'marquee-background': hsl(h, 100, 80).set('a', 0.1),
'marquee-stroke': hsl(h, 37, 60),
......
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