Commit 651acd74 authored by techird's avatar techird

使用 Module 规范组织代码

parent b27e5394
{
"directory": "lib"
}
\ No newline at end of file
...@@ -4,8 +4,4 @@ ...@@ -4,8 +4,4 @@
*.sublime-workspace *.sublime-workspace
dist/ dist/
node_modules/ node_modules/
_drafts/ _drafts/
native-support/archive/src/tmp/ \ No newline at end of file
native-support/archive/upload/
ui/theme/default/css/*.css
ui/theme/default/css/*.css.map
\ No newline at end of file
[submodule "lib/kity"] [submodule "lib/kity"]
path = lib/kity path = lib/kity
url = https://github.com/fex-team/kity url = https://github.com/fex-team/kity
\ No newline at end of file [submodule "lib/promise"]
path = lib/promise
url = https://github.com/jakearchibald/es6-promise
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
"disallowSpacesInsideParentheses": true, "disallowSpacesInsideParentheses": true,
// 行尾「MUST NOT」使用空格 // 行尾「MUST NOT」使用空格
"disallowTrailingWhitespace": false, "disallowTrailingWhitespace": true,
// 每行「MUST NOT」超过 120 个字符 // 每行「MUST NOT」超过 120 个字符
"maximumLineLength": 120, "maximumLineLength": 120,
......
...@@ -10,23 +10,7 @@ ...@@ -10,23 +10,7 @@
"browser": true, "browser": true,
"boss": true, "boss": true,
"predef" : [ "predef" : [
"module", "define",
"require", "Promise"
"console",
"kity",
"KityMinder",
"KM",
"Minder",
"MinderNode",
"MinderEvent",
"Command",
"KITYMINDER_CONFIG",
"keymap",
"Utils",
"utils",
"$",
"KM",
"keymap",
"browser"
] ]
} }
\ No newline at end of file
/*----------------------------------------------------- /* global require, module */
* livereload Default Setting
*-----------------------------------------------------*/
'use strict';
var path = require('path'); var path = require('path');
/*-----------------------------------------------------
* Module Setting
*-----------------------------------------------------*/
module.exports = function(grunt) { module.exports = function(grunt) {
'use strict';
// These plugins provide necessary tasks. // These plugins provide necessary tasks.
/* [Build plugin & task ] ------------------------------------*/ /* [Build plugin & task ] ------------------------------------*/
grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-module-dependence');
grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-autoprefixer');
var banner = '/*!\n' + var banner = '/*!\n' +
' * ====================================================\n' + ' * ====================================================\n' +
...@@ -32,161 +22,29 @@ module.exports = function(grunt) { ...@@ -32,161 +22,29 @@ module.exports = function(grunt) {
' * ====================================================\n' + ' * ====================================================\n' +
' */\n\n'; ' */\n\n';
var packs = ['index', 'edit', 'share', 'm-share'];
var sources = require('./import.js');
var srcPath = 'src/';
var distPath = 'dist/';
var distPages = ['index', 'edit', 'viewshare', 'm-share'].map(function(name) {
return distPath + name + '.html';
});
var concatConfigs = {};
packs.forEach(function(pack) {
concatConfigs[pack] = {
options: {
banner: banner + '(function(window) {\n\n',
footer: '\n\n})(window)',
sourceMap: true,
sourceMapStyle: 'link'
},
src: sources.filter(function(source) {
return source.pack == '*' || source.pack.split('|').indexOf(pack) !== -1;
}).map(function(source) {
return source.path;
}),
dest: distPath + 'kityminder.' + pack + '.js'
};
});
// Project configuration. // Project configuration.
grunt.initConfig({ grunt.initConfig({
// Metadata. // Metadata.
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
clean: ['dist', 'native-support/upload/', 'native-support/src/tmp/'], dependence: {
options: {
concat: concatConfigs, base: 'src',
entrance: 'kityminder'
uglify: {
minimize: {
options: {
banner: banner,
sourceMap: true
},
files: (function() {
var files = {};
packs.forEach(function(pack) {
files[distPath + 'kityminder.' + pack + '.min.js'] = distPath + 'kityminder.' + pack + '.js';
});
return files;
})()
}
},
copy: {
dir: {
files: [{
src: [
'ui/theme/**/css/*.css',
'ui/theme/**/css/*.css.map',
'ui/theme/**/images/*',
'lang/**/*',
'static/**/*',
'native-support/**/*',
'lib/ZeroClipboard.swf',
'lib/inflate.js',
'lib/source-map.min.js',
'index.html',
'edit.html',
'viewshare.html',
'm-share.html',
'download.php'
],
dest: distPath
}]
},
km_config: {
expand: true,
src: 'kityminder.config.js',
dest: distPath
}, },
mise: { merge: {
files: [{ files: [{
src: ['LICENSE', 'favicon.ico', 'README.md', 'CHANGELOG.md'], src: 'src/**/*.js',
dest: distPath dest: 'release/kityminder.all.js'
}]
}
},
replace: {
online: {
src: distPages,
overwrite: true,
replacements: [{
from: /import\.js\?pack=([\w-]+)\"/,
to: 'kityminder.$1.min.js"'
}]
},
pageNoCache: {
src: distPages,
overwrite: true,
replacements: [{
from: /(src|href)=\"(.+?)\.(js|css)\"/ig,
to: '$1="$2.$3?_=' + (+new Date()) + '"'
}]
},
imageNoCache: {
src: 'dist/ui/theme/default/css/default.all.css',
overwrite: true,
replacements: [{
from: /\.png/ig,
to: '.png?_=' + (+new Date())
}] }]
} }
},
watch: {
less: {
files: ['ui/theme/**/*.less'],
tasks: ['less:compile', 'autoprefixer']
}
},
less: {
compile: {
files: {
'ui/theme/default/css/default.all.temp.css': [
'ui/theme/default/css/import.less'
]
},
options: {
sourceMap: true,
sourceMapFilename: 'ui/theme/default/css/default.all.temp.css.map',
sourceMapBasepath: 'ui/theme/default/css/'
}
}
},
autoprefixer: {
all: {
options: {
map: true
},
src: 'ui/theme/default/css/default.all.temp.css',
dest: 'ui/theme/default/css/default.all.css'
}
} }
}); });
// Build task(s). // Build task(s).
grunt.registerTask('default', ['clean', 'concat', 'uglify', 'less', 'autoprefixer', 'copy', 'replace']); grunt.registerTask('default', ['dependence']);
grunt.registerTask('dev', ['less', 'autoprefixer', 'watch']);
}; };
\ No newline at end of file
{
"name": "kityminder-core",
"title": "Kity Minder Core",
"description": "Powerful online mind graphic visualization and editor (command based)",
"version": "1.3.6",
"main": "src/kityminder.js",
"keywords": ["kityminder", "kity", "svg"],
"homepage": "https://github.com/fex-team/kityminder-core",
"devDependencies": {
"seajs": "~2.3.0"
},
"licenses": [{
"type": "BSD",
"url": "https://github.com/fex-team/kityminder-core/blob/dev/LICENSE"
}],
"bugs": {
"url": "https://github.com/fex-team/kityminder-core/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/fex-team/kityminder-core.git"
},
"author": {
"name": "Baidu FEX",
"url": "http://fex.baidu.com"
}
}
\ No newline at end of file
...@@ -4,13 +4,6 @@ ...@@ -4,13 +4,6 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>KityMinder Example</title> <title>KityMinder Example</title>
<script type="text/javascript" src="lib/kity/dist/kity.js"></script>
<!--dev mode 引入-->
<script type="text/javascript" src="import.js"></script>
<!--dist mode 引入 -->
<!--<script type="text/javascript" src="../dist/kityminder.min.js">-->
<link href="favicon.ico" type="image/x-icon" rel="shortcut icon"> <link href="favicon.ico" type="image/x-icon" rel="shortcut icon">
<style type="text/css"> <style type="text/css">
body { body {
...@@ -37,9 +30,33 @@ ...@@ -37,9 +30,33 @@
<body> <body>
<div id="minder-view"></div> <div id="minder-view"></div>
</body> </body>
<!-- *************************** Module 形式加载引入 **************************** -->
<script type="text/javascript" src="lib/seajs/dist/sea-debug.js"></script>
<script type="text/javascript"> <script type="text/javascript">
window.km = new KityMinder({ /* global seajs */
seajs.config({
base: './src'
});
define('start', function(require) {
var Minder = require('kityminder').Minder;
// 创建 km 实例
var km = window.km = new Minder({
renderTo: 'minder-view' renderTo: 'minder-view'
}); });
});
seajs.use('start');
</script> </script>
<!-- *********************** 打包文件引入(需要先 grunt 发布) ************************* -->
<!--
<script type="text/javascript" src="../release/kityminder.all.min.js">
<script type="text/javascript">
// 创建 km 实例
window.km = new kityminder.Minder('minder-view');
</script>
-->
</html> </html>
\ No newline at end of file
(function() {
var define, requireModule, require, requirejs;
(function() {
var registry = {}, seen = {};
define = function(name, deps, callback) {
registry[name] = { deps: deps, callback: callback };
};
requirejs = require = requireModule = function(name) {
requirejs._eak_seen = registry;
if (seen[name]) { return seen[name]; }
seen[name] = {};
if (!registry[name]) {
throw new Error("Could not find module " + name);
}
var mod = registry[name],
deps = mod.deps,
callback = mod.callback,
reified = [],
exports;
for (var i=0, l=deps.length; i<l; i++) {
if (deps[i] === 'exports') {
reified.push(exports = {});
} else {
reified.push(requireModule(resolve(deps[i])));
}
}
var value = callback.apply(this, reified);
return seen[name] = exports || value;
function resolve(child) {
if (child.charAt(0) !== '.') { return child; }
var parts = child.split("/");
var parentBase = name.split("/").slice(0, -1);
for (var i=0, l=parts.length; i<l; i++) {
var part = parts[i];
if (part === '..') { parentBase.pop(); }
else if (part === '.') { continue; }
else { parentBase.push(part); }
}
return parentBase.join("/");
}
};
})();
define("promise/all",
["./utils","exports"],
function(__dependency1__, __exports__) {
"use strict";
/* global toString */
var isArray = __dependency1__.isArray;
var isFunction = __dependency1__.isFunction;
/**
Returns a promise that is fulfilled when all the given promises have been
fulfilled, or rejected if any of them become rejected. The return promise
is fulfilled with an array that gives all the values in the order they were
passed in the `promises` array argument.
Example:
```javascript
var promise1 = RSVP.resolve(1);
var promise2 = RSVP.resolve(2);
var promise3 = RSVP.resolve(3);
var promises = [ promise1, promise2, promise3 ];
RSVP.all(promises).then(function(array){
// The array here would be [ 1, 2, 3 ];
});
```
If any of the `promises` given to `RSVP.all` are rejected, the first promise
that is rejected will be given as an argument to the returned promises's
rejection handler. For example:
Example:
```javascript
var promise1 = RSVP.resolve(1);
var promise2 = RSVP.reject(new Error("2"));
var promise3 = RSVP.reject(new Error("3"));
var promises = [ promise1, promise2, promise3 ];
RSVP.all(promises).then(function(array){
// Code here never runs because there are rejected promises!
}, function(error) {
// error.message === "2"
});
```
@method all
@for RSVP
@param {Array} promises
@param {String} label
@return {Promise} promise that is fulfilled when all `promises` have been
fulfilled, or rejected if any of them become rejected.
*/
function all(promises) {
/*jshint validthis:true */
var Promise = this;
if (!isArray(promises)) {
throw new TypeError('You must pass an array to all.');
}
return new Promise(function(resolve, reject) {
var results = [], remaining = promises.length,
promise;
if (remaining === 0) {
resolve([]);
}
function resolver(index) {
return function(value) {
resolveAll(index, value);
};
}
function resolveAll(index, value) {
results[index] = value;
if (--remaining === 0) {
resolve(results);
}
}
for (var i = 0; i < promises.length; i++) {
promise = promises[i];
if (promise && isFunction(promise.then)) {
promise.then(resolver(i), reject);
} else {
resolveAll(i, promise);
}
}
});
}
__exports__.all = all;
});
define("promise/asap",
["exports"],
function(__exports__) {
"use strict";
var browserGlobal = (typeof window !== 'undefined') ? window : {};
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);
// node
function useNextTick() {
return function() {
process.nextTick(flush);
};
}
function useMutationObserver() {
var iterations = 0;
var observer = new BrowserMutationObserver(flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
function useSetTimeout() {
return function() {
local.setTimeout(flush, 1);
};
}
var queue = [];
function flush() {
for (var i = 0; i < queue.length; i++) {
var tuple = queue[i];
var callback = tuple[0], arg = tuple[1];
callback(arg);
}
queue = [];
}
var scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
scheduleFlush = useMutationObserver();
} else {
scheduleFlush = useSetTimeout();
}
function asap(callback, arg) {
var length = queue.push([callback, arg]);
if (length === 1) {
// If length is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
scheduleFlush();
}
}
__exports__.asap = asap;
});
define("promise/config",
["exports"],
function(__exports__) {
"use strict";
var config = {
instrument: false
};
function configure(name, value) {
if (arguments.length === 2) {
config[name] = value;
} else {
return config[name];
}
}
__exports__.config = config;
__exports__.configure = configure;
});
define("promise/polyfill",
["./promise","./utils","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/*global self*/
var RSVPPromise = __dependency1__.Promise;
var isFunction = __dependency2__.isFunction;
function polyfill() {
var local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof window !== 'undefined' && window.document) {
local = window;
} else {
local = self;
}
var es6PromiseSupport =
"Promise" in local &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in local.Promise &&
"reject" in local.Promise &&
"all" in local.Promise &&
"race" in local.Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function() {
var resolve;
new local.Promise(function(r) { resolve = r; });
return isFunction(resolve);
}());
// !es6PromiseSupport || ~window.location.href.indexOf('rsvpromise')
if (true) {
local.Promise = RSVPPromise;
}
}
__exports__.polyfill = polyfill;
});
define("promise/promise",
["./config","./utils","./all","./race","./resolve","./reject","./asap","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {
"use strict";
var config = __dependency1__.config;
var configure = __dependency1__.configure;
var objectOrFunction = __dependency2__.objectOrFunction;
var isFunction = __dependency2__.isFunction;
var now = __dependency2__.now;
var all = __dependency3__.all;
var race = __dependency4__.race;
var staticResolve = __dependency5__.resolve;
var staticReject = __dependency6__.reject;
var asap = __dependency7__.asap;
var counter = 0;
config.async = asap; // default async is asap;
function Promise(resolver) {
if (!isFunction(resolver)) {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
if (!(this instanceof Promise)) {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
this._subscribers = [];
invokeResolver(resolver, this);
}
function invokeResolver(resolver, promise) {
function resolvePromise(value) {
resolve(promise, value);
}
function rejectPromise(reason) {
reject(promise, reason);
}
try {
resolver(resolvePromise, rejectPromise);
} catch(e) {
rejectPromise(e);
}
}
function invokeCallback(settled, promise, callback, detail) {
var hasCallback = isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
try {
value = callback(detail);
succeeded = true;
} catch(e) {
failed = true;
error = e;
}
} else {
value = detail;
succeeded = true;
}
if (handleThenable(promise, value)) {
return;
} else if (hasCallback && succeeded) {
resolve(promise, value);
} else if (failed) {
reject(promise, error);
} else if (settled === FULFILLED) {
resolve(promise, value);
} else if (settled === REJECTED) {
reject(promise, value);
}
}
var PENDING = void 0;
var SEALED = 0;
var FULFILLED = 1;
var REJECTED = 2;
function subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
subscribers[length] = child;
subscribers[length + FULFILLED] = onFulfillment;
subscribers[length + REJECTED] = onRejection;
}
function publish(promise, settled) {
var child, callback, subscribers = promise._subscribers, detail = promise._detail;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
invokeCallback(settled, child, callback, detail);
}
promise._subscribers = null;
}
Promise.prototype = {
constructor: Promise,
_state: undefined,
_detail: undefined,
_subscribers: undefined,
then: function(onFulfillment, onRejection) {
var promise = this;
var thenPromise = new this.constructor(function() {});
if (this._state) {
var callbacks = arguments;
config.async(function invokePromiseCallback() {
invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
});
} else {
subscribe(this, thenPromise, onFulfillment, onRejection);
}
return thenPromise;
},
'catch': function(onRejection) {
return this.then(null, onRejection);
}
};
Promise.all = all;
Promise.race = race;
Promise.resolve = staticResolve;
Promise.reject = staticReject;
function handleThenable(promise, value) {
var then = null,
resolved;
try {
if (promise === value) {
throw new TypeError("A promises callback cannot return that same promise.");
}
if (objectOrFunction(value)) {
then = value.then;
if (isFunction(then)) {
then.call(value, function(val) {
if (resolved) { return true; }
resolved = true;
if (value !== val) {
resolve(promise, val);
} else {
fulfill(promise, val);
}
}, function(val) {
if (resolved) { return true; }
resolved = true;
reject(promise, val);
});
return true;
}
}
} catch (error) {
if (resolved) { return true; }
reject(promise, error);
return true;
}
return false;
}
function resolve(promise, value) {
if (promise === value) {
fulfill(promise, value);
} else if (!handleThenable(promise, value)) {
fulfill(promise, value);
}
}
function fulfill(promise, value) {
if (promise._state !== PENDING) { return; }
promise._state = SEALED;
promise._detail = value;
config.async(publishFulfillment, promise);
}
function reject(promise, reason) {
if (promise._state !== PENDING) { return; }
promise._state = SEALED;
promise._detail = reason;
config.async(publishRejection, promise);
}
function publishFulfillment(promise) {
publish(promise, promise._state = FULFILLED);
}
function publishRejection(promise) {
publish(promise, promise._state = REJECTED);
}
__exports__.Promise = Promise;
});
define("promise/race",
["./utils","exports"],
function(__dependency1__, __exports__) {
"use strict";
/* global toString */
var isArray = __dependency1__.isArray;
/**
`RSVP.race` allows you to watch a series of promises and act as soon as the
first promise given to the `promises` argument fulfills or rejects.
Example:
```javascript
var promise1 = new RSVP.Promise(function(resolve, reject){
setTimeout(function(){
resolve("promise 1");
}, 200);
});
var promise2 = new RSVP.Promise(function(resolve, reject){
setTimeout(function(){
resolve("promise 2");
}, 100);
});
RSVP.race([promise1, promise2]).then(function(result){
// result === "promise 2" because it was resolved before promise1
// was resolved.
});
```
`RSVP.race` is deterministic in that only the state of the first completed
promise matters. For example, even if other promises given to the `promises`
array argument are resolved, but the first completed promise has become
rejected before the other promises became fulfilled, the returned promise
will become rejected:
```javascript
var promise1 = new RSVP.Promise(function(resolve, reject){
setTimeout(function(){
resolve("promise 1");
}, 200);
});
var promise2 = new RSVP.Promise(function(resolve, reject){
setTimeout(function(){
reject(new Error("promise 2"));
}, 100);
});
RSVP.race([promise1, promise2]).then(function(result){
// Code here never runs because there are rejected promises!
}, function(reason){
// reason.message === "promise2" because promise 2 became rejected before
// promise 1 became fulfilled
});
```
@method race
@for RSVP
@param {Array} promises array of promises to observe
@param {String} label optional string for describing the promise returned.
Useful for tooling.
@return {Promise} a promise that becomes fulfilled with the value the first
completed promises is resolved with if the first completed promise was
fulfilled, or rejected with the reason that the first completed promise
was rejected with.
*/
function race(promises) {
/*jshint validthis:true */
var Promise = this;
if (!isArray(promises)) {
throw new TypeError('You must pass an array to race.');
}
return new Promise(function(resolve, reject) {
var results = [], promise;
for (var i = 0; i < promises.length; i++) {
promise = promises[i];
if (promise && typeof promise.then === 'function') {
promise.then(resolve, reject);
} else {
resolve(promise);
}
}
});
}
__exports__.race = race;
});
define("promise/reject",
["exports"],
function(__exports__) {
"use strict";
/**
`RSVP.reject` returns a promise that will become rejected with the passed
`reason`. `RSVP.reject` is essentially shorthand for the following:
```javascript
var promise = new RSVP.Promise(function(resolve, reject){
reject(new Error('WHOOPS'));
});
promise.then(function(value){
// Code here doesn't run because the promise is rejected!
}, function(reason){
// reason.message === 'WHOOPS'
});
```
Instead of writing the above, your code now simply becomes the following:
```javascript
var promise = RSVP.reject(new Error('WHOOPS'));
promise.then(function(value){
// Code here doesn't run because the promise is rejected!
}, function(reason){
// reason.message === 'WHOOPS'
});
```
@method reject
@for RSVP
@param {Any} reason value that the returned promise will be rejected with.
@param {String} label optional string for identifying the returned promise.
Useful for tooling.
@return {Promise} a promise that will become rejected with the given
`reason`.
*/
function reject(reason) {
/*jshint validthis:true */
var Promise = this;
return new Promise(function (resolve, reject) {
reject(reason);
});
}
__exports__.reject = reject;
});
define("promise/resolve",
["exports"],
function(__exports__) {
"use strict";
function resolve(value) {
/*jshint validthis:true */
if (value && typeof value === 'object' && value.constructor === this) {
return value;
}
var Promise = this;
return new Promise(function(resolve) {
resolve(value);
});
}
__exports__.resolve = resolve;
});
define("promise/utils",
["exports"],
function(__exports__) {
"use strict";
function objectOrFunction(x) {
return isFunction(x) || (typeof x === "object" && x !== null);
}
function isFunction(x) {
return typeof x === "function";
}
function isArray(x) {
return Object.prototype.toString.call(x) === "[object Array]";
}
// Date.now is not available in browsers < IE9
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
var now = Date.now || function() { return new Date().getTime(); };
__exports__.objectOrFunction = objectOrFunction;
__exports__.isFunction = isFunction;
__exports__.isArray = isArray;
__exports__.now = now;
});
requireModule('promise/polyfill').polyfill();
}());
\ No newline at end of file
{
"name": "seajs",
"version": "2.3.0",
"main": "./dist/sea.js",
"ignore": [
"**/.*",
"docs",
"lib",
"src",
"tests",
"CNAME",
"component.json",
"CONTRIBUTING.md",
"index.html",
"Makefile",
"package.json",
"README.md"
],
"homepage": "https://github.com/seajs/seajs",
"_release": "2.3.0",
"_resolution": {
"type": "version",
"tag": "2.3.0",
"commit": "9c6299636991fbca73a9aa7b2eb152c6e8614854"
},
"_source": "git://github.com/seajs/seajs.git",
"_target": "~2.3.0",
"_originalSource": "seajs"
}
\ No newline at end of file
MIT LICENSE
Copyright (c) 2009 - 2099 Frank Wang, http://seajs.org/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"name": "seajs",
"version": "2.3.0",
"main": "./dist/sea.js",
"ignore": [
"**/.*",
"docs",
"lib",
"src",
"tests",
"CNAME",
"component.json",
"CONTRIBUTING.md",
"index.html",
"Makefile",
"package.json",
"README.md"
]
}
...@@ -3,14 +3,14 @@ ...@@ -3,14 +3,14 @@
"title": "kityminder", "title": "kityminder",
"description": "Kity Minder", "description": "Kity Minder",
"version": "1.3.5", "version": "1.3.5",
"homepage": "https://github.com/fex-team/kityminder", "homepage": "https://github.com/fex-team/kityminder-core",
"author": { "author": {
"name": "f-cube @ FEX", "name": "f-cube @ FEX",
"url": "http://fex.baidu.com" "url": "http://fex.baidu.com"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/fex-team/kityminder.git" "url": "https://github.com/fex-team/kityminder-core.git"
}, },
"keywords": [ "keywords": [
"kityminder", "kityminder",
...@@ -21,23 +21,20 @@ ...@@ -21,23 +21,20 @@
"javascript" "javascript"
], ],
"bugs": { "bugs": {
"url": "https://github.com/fex-team/kityminder/issues" "url": "https://github.com/fex-team/kityminder-core/issues"
}, },
"licenses": [ { "licenses": [ {
"type": "MIT", "type": "MIT",
"url": "https://github.com/fex-team/kityminder/blob/dev/LICENSE" "url": "https://github.com/fex-team/kityminder-core/blob/dev/LICENSE"
} ], } ],
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"grunt": "~0.4.1", "grunt": "~0.4.1",
"grunt-module-dependence": "~0.1.4",
"grunt-contrib-concat": "~0.5.0", "grunt-contrib-concat": "~0.5.0",
"grunt-contrib-uglify": "~0.4.0", "grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-copy": "~0.5.0", "grunt-contrib-copy": "~0.5.0",
"grunt-text-replace": "~0.3.9", "grunt-contrib-clean": "~0.5.0"
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-less": "~0.11.3",
"grunt-contrib-clean": "~0.6.0",
"grunt-autoprefixer": "~1.0.1"
} }
} }
\ No newline at end of file
...@@ -7,38 +7,43 @@ ...@@ -7,38 +7,43 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
var connectMarker = new kity.Marker().pipe(function() { define(function(require, exports, module) {
var r = 7; var kity = require('core/kity');
var dot = new kity.Circle(r - 1); var connect = require('core/connect');
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('arc', function(node, parent, connection, width, color) { 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');
});
var box = node.getLayoutBox(), connect.register('arc', function(node, parent, connection, width, color) {
pBox = parent.getLayoutBox();
var start, end, vector; var box = node.getLayoutBox(),
var abs = Math.abs; pBox = parent.getLayoutBox();
var pathData = [];
var side = box.x > pBox.x ? 'right' : 'left';
node.getMinder().getPaper().addResource(connectMarker); var start, end, vector;
var abs = Math.abs;
var pathData = [];
var side = box.x > pBox.x ? 'right' : 'left';
start = new kity.Point(pBox.cx, pBox.cy); node.getMinder().getPaper().addResource(connectMarker);
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); start = new kity.Point(pBox.cx, pBox.cy);
pathData.push('M', start); end = side == 'left' ?
pathData.push('A', abs(vector.x), abs(vector.y), 0, 0, (vector.x * vector.y > 0 ? 0 : 1), end); new kity.Point(box.right + 2, box.cy) :
new kity.Point(box.left - 2, box.cy);
connection.setMarker(connectMarker); vector = kity.Vector.fromPoints(start, end);
connectMarker.dot.fill(color); pathData.push('M', start);
pathData.push('A', abs(vector.x), abs(vector.y), 0, 0, (vector.x * vector.y > 0 ? 0 : 1), end);
connection.setPathData(pathData); connection.setMarker(connectMarker);
connectMarker.dot.fill(color);
connection.setPathData(pathData);
});
}); });
\ No newline at end of file
...@@ -7,31 +7,36 @@ ...@@ -7,31 +7,36 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerConnectProvider('bezier', function(node, parent, connection) { define(function(require, exports, module) {
var kity = require('core/kity');
var connect = require('core/connect');
// 连线起点和终点 connect.register('bezier', function(node, parent, connection) {
var po = parent.getLayoutVertexOut(),
pi = node.getLayoutVertexIn();
// 连线矢量和方向 // 连线起点和终点
var v = parent.getLayoutVectorOut().normalize(); var po = parent.getLayoutVertexOut(),
pi = node.getLayoutVertexIn();
var r = Math.round; // 连线矢量和方向
var abs = Math.abs; var v = parent.getLayoutVectorOut().normalize();
var pathData = []; var r = Math.round;
pathData.push('M', r(po.x), r(po.y)); var abs = Math.abs;
if (abs(v.x) > abs(v.y)) { var pathData = [];
// x - direction pathData.push('M', r(po.x), r(po.y));
var hx = (pi.x + po.x) / 2;
pathData.push('C', hx, po.y, hx, pi.y, pi.x, pi.y);
} else {
// y - direction
var hy = (pi.y + po.y) / 2;
pathData.push('C', po.x, hy, pi.x, hy, pi.x, pi.y);
}
connection.setMarker(null); if (abs(v.x) > abs(v.y)) {
connection.setPathData(pathData); // x - direction
var hx = (pi.x + po.x) / 2;
pathData.push('C', hx, po.y, hx, pi.y, pi.x, pi.y);
} else {
// y - direction
var hy = (pi.y + po.y) / 2;
pathData.push('C', po.x, hy, pi.x, hy, pi.x, pi.y);
}
connection.setMarker(null);
connection.setPathData(pathData);
});
}); });
\ No newline at end of file
...@@ -7,22 +7,27 @@ ...@@ -7,22 +7,27 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerConnectProvider('fish-bone-master', function(node, parent, connection) { define(function(require, exports, module) {
var kity = require('core/kity');
var connect = require('core/connect');
var pout = parent.getLayoutVertexOut(), connect.register('fish-bone-master', function(node, parent, connection) {
pin = node.getLayoutVertexIn();
var abs = Math.abs; var pout = parent.getLayoutVertexOut(),
pin = node.getLayoutVertexIn();
var dy = abs(pout.y - pin.y), var abs = Math.abs;
dx = abs(pout.x - pin.x);
var pathData = []; var dy = abs(pout.y - pin.y),
dx = abs(pout.x - pin.x);
pathData.push('M', pout.x, pout.y); var pathData = [];
pathData.push('h', dx - dy);
pathData.push('L', pin.x, pin.y);
connection.setMarker(null); pathData.push('M', pout.x, pout.y);
connection.setPathData(pathData); pathData.push('h', dx - dy);
pathData.push('L', pin.x, pin.y);
connection.setMarker(null);
connection.setPathData(pathData);
});
}); });
\ No newline at end of file
...@@ -7,23 +7,28 @@ ...@@ -7,23 +7,28 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerConnectProvider('l', function(node, parent, connection) { define(function(require, exports, module) {
var kity = require('core/kity');
var connect = require('core/connect');
var po = parent.getLayoutVertexOut(); connect.register('l', function(node, parent, connection) {
var pi = node.getLayoutVertexIn();
var vo = parent.getLayoutVectorOut();
var pathData = []; var po = parent.getLayoutVertexOut();
var r = Math.round, var pi = node.getLayoutVertexIn();
abs = Math.abs; var vo = parent.getLayoutVectorOut();
pathData.push('M', po.round()); var pathData = [];
if (abs(vo.x) > abs(vo.y)) { var r = Math.round,
pathData.push('H', r(pi.x)); abs = Math.abs;
} else {
pathData.push('V', pi.y);
}
pathData.push('L', pi);
connection.setPathData(pathData); 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,52 +7,57 @@ ...@@ -7,52 +7,57 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerConnectProvider('poly', function(node, parent, connection, width) { define(function(require, exports, module) {
var kity = require('core/kity');
// 连线起点和终点 var connect = require('core/connect');
var po = parent.getLayoutVertexOut(),
pi = node.getLayoutVertexIn(); connect.register('poly', function(node, parent, connection, width) {
// 连线矢量和方向 // 连线起点和终点
var v = parent.getLayoutVectorOut().normalize(); var po = parent.getLayoutVertexOut(),
pi = node.getLayoutVertexIn();
var r = Math.round;
var abs = Math.abs; // 连线矢量和方向
var v = parent.getLayoutVectorOut().normalize();
var pathData = [];
pathData.push('M', r(po.x), r(po.y)); var r = Math.round;
var abs = Math.abs;
switch (true) {
case abs(v.x) > abs(v.y) && v.x < 0: var pathData = [];
// left pathData.push('M', r(po.x), r(po.y));
pathData.push('h', -parent.getStyle('margin-left'));
pathData.push('v', pi.y - po.y); switch (true) {
pathData.push('H', pi.x); case abs(v.x) > abs(v.y) && v.x < 0:
break; // left
pathData.push('h', -parent.getStyle('margin-left'));
case abs(v.x) > abs(v.y) && v.x >= 0: pathData.push('v', pi.y - po.y);
// right pathData.push('H', pi.x);
pathData.push('h', parent.getStyle('margin-right')); break;
pathData.push('v', pi.y - po.y);
pathData.push('H', pi.x); case abs(v.x) > abs(v.y) && v.x >= 0:
break; // right
pathData.push('h', parent.getStyle('margin-right'));
case abs(v.x) <= abs(v.y) && v.y < 0: pathData.push('v', pi.y - po.y);
// top pathData.push('H', pi.x);
pathData.push('v', -parent.getStyle('margin-top')); break;
pathData.push('h', pi.x - po.x);
pathData.push('V', pi.y); case abs(v.x) <= abs(v.y) && v.y < 0:
break; // top
pathData.push('v', -parent.getStyle('margin-top'));
case abs(v.x) <= abs(v.y) && v.y >= 0: pathData.push('h', pi.x - po.x);
// bottom pathData.push('V', pi.y);
pathData.push('v', parent.getStyle('margin-bottom')); break;
pathData.push('h', pi.x - po.x);
pathData.push('V', pi.y); case abs(v.x) <= abs(v.y) && v.y >= 0:
break; // bottom
pathData.push('v', parent.getStyle('margin-bottom'));
} pathData.push('h', pi.x - po.x);
pathData.push('V', pi.y);
connection.setMarker(null); break;
connection.setPathData(pathData);
}
connection.setMarker(null);
connection.setPathData(pathData);
});
}); });
\ No newline at end of file
...@@ -7,39 +7,44 @@ ...@@ -7,39 +7,44 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerConnectProvider('under', function(node, parent, connection, width, color) { define(function(require, exports, module) {
var kity = require('core/kity');
var connect = require('core/connect');
var box = node.getLayoutBox(), connect.register('under', function(node, parent, connection, width, color) {
pBox = parent.getLayoutBox();
var start, end, vector; var box = node.getLayoutBox(),
var abs = Math.abs; pBox = parent.getLayoutBox();
var pathData = [];
var side = box.x > pBox.x ? 'right' : 'left';
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') { var radius = node.getStyle('connect-radius');
p1 = new kity.Point(pBox.right, startY); var underY = box.bottom + 3;
p2 = new kity.Point(box.left - 10, underY); var startY = parent.getType() == 'sub' ? pBox.bottom + 3 : pBox.cy;
p3 = new kity.Point(box.right, underY); var p1, p2, p3, mx;
} else {
p1 = new kity.Point(pBox.left, startY);
p2 = new kity.Point(box.right + 10, underY);
p3 = new kity.Point(box.left, underY);
}
mx = (p1.x + p2.x) / 2; if (side == 'right') {
p1 = new kity.Point(pBox.right, startY);
p2 = new kity.Point(box.left - 10, underY);
p3 = new kity.Point(box.right, underY);
} else {
p1 = new kity.Point(pBox.left, startY);
p2 = new kity.Point(box.right + 10, underY);
p3 = new kity.Point(box.left, underY);
}
pathData.push('M', p1); mx = (p1.x + p2.x) / 2;
pathData.push('C', mx, p1.y, mx, p2.y, p2);
pathData.push('L', p3);
connection.setMarker(null); pathData.push('M', p1);
pathData.push('C', mx, p1.y, mx, p2.y, p2);
pathData.push('L', p3);
connection.setPathData(pathData); connection.setMarker(null);
connection.setPathData(pathData);
});
}); });
\ No newline at end of file
KityMinder.COMMAND_STATE_NORMAL = 0; define(function(require, exports, module) {
KityMinder.COMMAND_STATE_DISABLED = -1; var kity = require('./kity');
KityMinder.COMMAND_STATE_ACTIVED = 1; var utils = require('./utils');
var Minder = require('./minder');
var Command = kity.createClass( "Command", { var MinderNode = require('./node');
constructor: function () { var MinderEvent = require('./event');
this._isContentChange = true;
this._isSelectionChange = false; var COMMAND_STATE_NORMAL = 0;
}, var COMMAND_STATE_DISABLED = -1;
var COMMAND_STATE_ACTIVED = 1;
execute: function ( minder, args ) {
/**
}, * @class Command
*
setContentChanged: function ( val ) { * 表示一个命令,包含命令的查询及执行
this._isContentChange = !! val; */
}, var Command = kity.createClass('Command', {
constructor: function() {
isContentChanged: function () { this._isContentChange = true;
return this._isContentChange; this._isSelectionChange = false;
}, },
setSelectionChanged: function ( val ) { execute: function(minder, args) {
this._isSelectionChange = !! val; throw new Error('Not Implement: Command.execute()');
}, },
isSelectionChanged: function () { setContentChanged: function(val) {
return this._isContentChange; this._isContentChange = !!val;
}, },
queryState: function ( km ) { isContentChanged: function() {
return KityMinder.COMMAND_STATE_NORMAL; return this._isContentChange;
}, },
queryValue: function ( km ) { setSelectionChanged: function(val) {
return 0; this._isSelectionChange = !!val;
}, },
isNeedUndo: function () {
return true; isSelectionChanged: function() {
} return this._isContentChange;
} ); },
kity.extendClass(KityMinder, { queryState: function(km) {
_getCommand: function (name) { return COMMAND_STATE_NORMAL;
return this._commands[name.toLowerCase()]; },
},
queryValue: function(km) {
_queryCommand: function (name, type, args) { return 0;
var cmd = this._getCommand(name); },
if (cmd) {
var queryCmd = cmd['query' + type]; isNeedUndo: function() {
if (queryCmd) return true;
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;
} }
});
Command.STATE_NORMAL = COMMAND_STATE_NORMAL;
Command.STATE_ACTIVE = COMMAND_STATE_ACTIVED;
Command.STATE_DISABLED = COMMAND_STATE_DISABLED;
kity.extendClass(Minder, {
_getCommand: function(name) {
return this._commands[name.toLowerCase()];
},
_queryCommand: function(name, type, args) {
var cmd = this._getCommand(name);
if (cmd) {
var queryCmd = cmd['query' + type];
if (queryCmd)
return queryCmd.apply(cmd, [this].concat(args));
}
return 0;
},
queryCommandState: function(name) {
return this._queryCommand(name, 'State', [].slice.call(arguments, 1));
},
queryCommandValue: function(name) {
return this._queryCommand(name, 'Value', [].slice.call(arguments, 1));
},
execCommand: function(name) {
name = name.toLowerCase();
var cmdArgs = [].slice.call(arguments, 1),
cmd, stoped, result, eventParams;
var me = this;
cmd = this._getCommand(name);
eventParams = {
command: cmd,
commandName: name.toLowerCase(),
commandArgs: cmdArgs
};
if (!cmd || !~this.queryCommandState(name)) {
return false;
}
if (!this._hasEnterExecCommand && cmd.isNeedUndo()) { if (!this._hasEnterExecCommand && cmd.isNeedUndo()) {
this._hasEnterExecCommand = true; this._hasEnterExecCommand = true;
stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true)); stoped = this._fire(new MinderEvent('beforeExecCommand', eventParams, true));
if (!stoped) { if (!stoped) {
//保存场景 //保存场景
this._fire(new MinderEvent('saveScene')); this._fire(new MinderEvent('saveScene'));
this._fire(new MinderEvent("preExecCommand", eventParams, false)); this._fire(new MinderEvent('preExecCommand', eventParams, false));
result = cmd.execute.apply(cmd, [me].concat(cmdArgs)); result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
this._fire(new MinderEvent('execCommand', eventParams, false)); this._fire(new MinderEvent('execCommand', eventParams, false));
//保存场景 //保存场景
this._fire(new MinderEvent('saveScene')); this._fire(new MinderEvent('saveScene'));
if (cmd.isContentChanged()) { if (cmd.isContentChanged()) {
this._firePharse(new MinderEvent('contentchange')); this._firePharse(new MinderEvent('contentchange'));
}
this._interactChange();
} }
this._hasEnterExecCommand = false;
} else {
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
this._interactChange(); if (!this._hasEnterExecCommand) {
this._interactChange();
}
} }
this._hasEnterExecCommand = false;
} else {
result = cmd.execute.apply(cmd, [me].concat(cmdArgs));
if (!this._hasEnterExecCommand) { return result === undefined ? null : result;
this._interactChange();
}
} }
});
return result === undefined ? null : result; module.exports = Command;
}
}); });
\ No newline at end of file
Utils.extend(KityMinder, { define(function(require, exports, module) {
var utils = require('./utils');
compatibility: function(json) {
var version = json.version || '1.1.3'; function compatibility(json) {
function traverse(node, fn) {
fn(node);
if (node.children) node.children.forEach(function(child) {
traverse(child, fn);
});
}
/* 脑图数据升级 */
function c_120_130(json) {
traverse(json, function(node) {
var data = node.data;
delete data.layout_bottom_offset;
delete data.layout_default_offset;
delete data.layout_filetree_offset;
});
}
/**
* 脑图数据升级
* v1.1.3 => v1.2.0
* */
function c_113_120(json) {
// 原本的布局风格
var ocs = json.data.currentstyle;
delete json.data.currentstyle;
// 为 1.2 选择模板,同时保留老版本文件的皮肤
if (ocs == 'bottom') {
json.template = 'structure';
json.theme = 'snow';
} else if (ocs == 'default') {
json.template = 'default';
json.theme = 'classic';
}
traverse(json, function(node) {
var data = node.data;
// 升级优先级、进度图标 var version = json.version || '1.1.3';
if ('PriorityIcon' in data) {
data.priority = data.PriorityIcon;
delete data.PriorityIcon;
}
if ('ProgressIcon' in data) {
data.progress = 1 + ((data.ProgressIcon - 1) << 1);
delete data.ProgressIcon;
}
// 删除过时属性
delete data.point;
delete data.layout;
});
}
switch (version) { switch (version) {
case '1.1.3': case '1.1.3':
c_113_120(json); c_113_120(json);
/* falls through */
case '1.2.0': case '1.2.0':
case '1.2.1': case '1.2.1':
c_120_130(json); c_120_130(json);
/* falls through */
} }
return json; return json;
} }
function traverse(node, fn) {
fn(node);
if (node.children) node.children.forEach(function(child) {
traverse(child, fn);
});
}
/* 脑图数据升级 */
function c_120_130(json) {
traverse(json, function(node) {
var data = node.data;
delete data.layout_bottom_offset;
delete data.layout_default_offset;
delete data.layout_filetree_offset;
});
}
/**
* 脑图数据升级
* v1.1.3 => v1.2.0
* */
function c_113_120(json) {
// 原本的布局风格
var ocs = json.data.currentstyle;
delete json.data.currentstyle;
// 为 1.2 选择模板,同时保留老版本文件的皮肤
if (ocs == 'bottom') {
json.template = 'structure';
json.theme = 'snow';
} else if (ocs == 'default') {
json.template = 'default';
json.theme = 'classic';
}
traverse(json, function(node) {
var data = node.data;
// 升级优先级、进度图标
if ('PriorityIcon' in data) {
data.priority = data.PriorityIcon;
delete data.PriorityIcon;
}
if ('ProgressIcon' in data) {
data.progress = 1 + ((data.ProgressIcon - 1) << 1);
delete data.ProgressIcon;
}
// 删除过时属性
delete data.point;
delete data.layout;
});
}
module.exports = compatibility;
}); });
\ No newline at end of file
/* global Renderer: true */ define(function(require, exports, module) {
var kity = require('./kity');
utils.extend(KityMinder, { var utils = require('./utils');
_connectProviders: {}, var Module = require('./module');
var Minder = require('./minder');
var MinderNode = require('./node');
// 连线提供方
var _connectProviders = {};
function register(name, provider) {
_connectProviders[name] = provider;
}
_defaultConnectProvider: function(node, parent, connection) { register('default', function(node, parent, connection) {
connection.setPathData([ connection.setPathData([
'M', parent.getLayoutVertexOut(), 'M', parent.getLayoutVertexOut(),
'L', node.getLayoutVertexIn() 'L', node.getLayoutVertexIn()
]); ]);
}, });
registerConnectProvider: function(name, provider) {
KityMinder._connectProviders[name] = provider;
},
getConnectProvider: function(name) {
return KityMinder._connectProviders[name] || KityMinder._defaultConnectProvider;
}
});
kity.extendClass(MinderNode, { kity.extendClass(MinderNode, {
getConnectProvider: function() { getConnect: function() {
return KityMinder.getConnectProvider(this.getConnect()); return this.data.connect || 'default';
}, },
getConnect: function() { getConnectProvider: function() {
return null; return _connectProviders[this.getConnect()] || _connectProviders['default'];
}, },
getConnection: function() { getConnection: function() {
return this._connection || null; return this._connection || null;
} }
}); });
kity.extendClass(KityMinder, { kity.extendClass(Minder, {
getConnectContainer: function() { getConnectContainer: function() {
return this._connectContainer; return this._connectContainer;
}, },
createConnect: function(node) { createConnect: function(node) {
if (node.isRoot()) return; if (node.isRoot()) return;
var connection = new kity.Path(); var connection = new kity.Path();
node._connection = connection; node._connection = connection;
this._connectContainer.addShape(connection); this._connectContainer.addShape(connection);
this.updateConnect(node); this.updateConnect(node);
}, },
removeConnect: function(node) { removeConnect: function(node) {
var me = this; var me = this;
node.traverse(function(node) { node.traverse(function(node) {
me._connectContainer.removeShape(node._connection); me._connectContainer.removeShape(node._connection);
node._connection = null; node._connection = null;
}); });
}, },
updateConnect: function(node) { updateConnect: function(node) {
var connection = node._connection; var connection = node._connection;
var parent = node.parent; var parent = node.parent;
if (!parent || !connection) return; if (!parent || !connection) return;
if (parent.isCollapsed()) { if (parent.isCollapsed()) {
connection.setVisible(false); connection.setVisible(false);
return; return;
} }
connection.setVisible(true); connection.setVisible(true);
var provider = node.getConnectProvider(); var provider = node.getConnectProvider();
var strokeColor = node.getStyle('connect-color') || 'white', var strokeColor = node.getStyle('connect-color') || 'white',
strokeWidth = node.getStyle('connect-width') || 2; strokeWidth = node.getStyle('connect-width') || 2;
connection.stroke(strokeColor, strokeWidth); connection.stroke(strokeColor, strokeWidth);
provider(node, parent, connection, strokeWidth, strokeColor); provider(node, parent, connection, strokeWidth, strokeColor);
if (strokeWidth % 2 === 0) { if (strokeWidth % 2 === 0) {
connection.setTranslate(0.5, 0.5); connection.setTranslate(0.5, 0.5);
} else { } else {
connection.setTranslate(0, 0); connection.setTranslate(0, 0);
}
} }
} });
});
Module.register('Connect', {
KityMinder.registerModule('Connect', { init: function() {
init: function() { this._connectContainer = new kity.Group().setId(utils.uuid('minder_connect_group'));
this._connectContainer = new kity.Group().setId(KityMinder.uuid('minder_connect_group')); this.getRenderContainer().prependShape(this._connectContainer);
this.getRenderContainer().prependShape(this._connectContainer);
},
events: {
'nodeattach': function(e) {
this.createConnect(e.node);
},
'nodedetach': function(e) {
this.removeConnect(e.node);
}, },
'layoutapply layoutfinish noderender': function(e) { events: {
this.updateConnect(e.node); 'nodeattach': function(e) {
this.createConnect(e.node);
},
'nodedetach': function(e) {
this.removeConnect(e.node);
},
'layoutapply layoutfinish noderender': function(e) {
this.updateConnect(e.node);
}
} }
} });
exports.register = register;
}); });
\ No newline at end of file
Utils.extend(KityMinder, { define(function(require, exports, module) {
_protocols: {}, var kity = require('./kity');
registerProtocol: function(name, protocolDeal) { var utils = require('./utils');
KityMinder._protocols[name] = protocolDeal; var Minder = require('./minder');
} var MinderNode = require('./node');
}); var MinderEvent = require('./event');
var compatibility = require('./compatibility');
var DEFAULT_TEXT = {
'root': 'maintopic', // 导入导出
'main': 'topic', kity.extendClass(Minder, {
'sub': 'topic'
}; exportJson: function() {
/* 导出 node 上整棵树的数据为 JSON */
KityMinder.registerInit(function() { function exportNode(node) {
this._initProtocols(); var exported = {};
}); exported.data = node.getData();
var childNodes = node.getChildren();
// 导入导出 if (childNodes.length) {
kity.extendClass(KityMinder, { exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
_initProtocols: function(options) { exported.children.push(exportNode(childNodes[i]));
var protocols = this._protocols = {}; }
var pool = KityMinder._protocols;
for (var name in pool) {
if (pool.hasOwnProperty(name))
protocols[name] = pool[name](this);
protocols[name].name = name;
}
},
getProtocol: function(name) {
return this._protocols[name] || null;
},
getSupportedProtocols: function() {
var protocols = this._protocols;
return Utils.keys(protocols).map(function(name) {
return protocols[name];
});
},
exportJson: function() {
/* 导出 node 上整棵树的数据为 JSON */
function exportNode(node) {
var exported = {};
exported.data = node.getData();
var childNodes = node.getChildren();
if (childNodes.length) {
exported.children = [];
for (var i = 0; i < childNodes.length; i++) {
exported.children.push(exportNode(childNodes[i]));
} }
return exported;
} }
return exported;
}
var json = exportNode(this.getRoot()); var json = exportNode(this.getRoot());
json.template = this.getTemplate(); json.template = this.getTemplate();
json.theme = this.getTheme(); json.theme = this.getTheme();
json.version = KityMinder.version; json.version = Minder.version;
return json; return json;
}, },
importJson: function(json, params) { importJson: function(json, params) {
function importNode(node, json, km) { function importNode(node, json, km) {
var data = json.data; var data = json.data;
node.data = {}; node.data = {};
for (var field in data) { for (var field in data) {
node.setData(field, data[field]); node.setData(field, data[field]);
} }
node.setData('text', data.text || km.getLang(DEFAULT_TEXT[node.getType()])); node.setData('text', data.text);
var childrenTreeData = json.children || []; var childrenTreeData = json.children || [];
for (var i = 0; i < childrenTreeData.length; i++) { for (var i = 0; i < childrenTreeData.length; i++) {
var childNode = km.createNode(null, node); var childNode = km.createNode(null, node);
importNode(childNode, childrenTreeData[i], km); importNode(childNode, childrenTreeData[i], km);
}
return node;
} }
return node;
}
if (!json) return;
this._fire(new MinderEvent('preimport', params, false));
// 删除当前所有节点
while (this._root.getChildren().length) {
this.removeNode(this._root.getChildren()[0]);
}
json = KityMinder.compatibility(json);
importNode(this._root, json, this);
this.setTemplate(json.template || 'default');
this.setTheme(json.theme || null);
this.refresh();
this.fire('import', params);
this._firePharse({
type: 'contentchange'
});
this._interactChange();
},
exportData: function(protocolName, options) {
var json, protocol; if (!json) return;
json = this.exportJson(); this._fire(new MinderEvent('preimport', params, false));
// 指定了协议进行导出,需要检测协议是否支持 // 删除当前所有节点
if (protocolName) { while (this._root.getChildren().length) {
protocol = this.getProtocol(protocolName); this.removeNode(this._root.getChildren()[0]);
if (!protocol || !protocol.encode) {
return Promise.reject(new Error('Not supported protocol:' + protocolName));
} }
}
// 导出前抛个事件
this._fire(new MinderEvent('beforeexport', {
json: json,
protocolName: protocolName,
protocol: protocol
}));
if (protocol) { json = Minder.compatibility(json);
return Promise.resolve(protocol.encode(json, this, options));
} else {
return Promise.resolve(json);
}
},
importData: function(local, protocolName) { importNode(this._root, json, this);
var json, protocol; this.setTemplate(json.template || 'default');
var minder = this; this.setTheme(json.theme || null);
this.refresh();
// 指定了协议进行导入,需要检测协议是否支持 this.fire('import', params);
if (protocolName) {
protocol = this.getProtocol(protocolName);
if (!protocol || !protocol.decode) { this._firePharse({
return Promise.reject(new Error('Not supported protocol:' + protocolName)); type: 'contentchange'
} });
this._interactChange();
} }
});
var params = {
local: local,
protocolName: protocolName,
protocol: protocol
};
// 导入前抛事件
this._fire(new MinderEvent('beforeimport', params));
return new Promise(function(resolve, reject) {
resolve(protocol ? protocol.decode(local) : local);
}).then(function(json) {
minder.importJson(json, params);
return json;
});
}
}); });
\ No newline at end of file
var MinderEvent = kity.createClass('MindEvent', { define(function(require, exports, module) {
constructor: function(type, params, canstop) { var kity = require('./kity');
params = params || {}; var utils = require('./utils');
if (params.getType && params.getType() == 'ShapeEvent') { var Minder = require('./minder');
this.kityEvent = params;
this.originEvent = params.originEvent; function listen(element, type, handler) {
this.getPosition = params.getPosition.bind(params); var types = utils.isArray(type) ? type : utils.trim(type).split(' '),
} else if (params.target && params.preventDefault) { k = types.length;
this.originEvent = params; types.forEach(function(name) {
} else { element.addEventListener(name, handler, false);
kity.Utils.extend(this, params); });
}
this.type = type;
this._canstop = canstop || false;
},
getTargetNode: function() {
var findShape = this.kityEvent && this.kityEvent.targetShape;
if (!findShape) return null;
while (!findShape.minderNode && findShape.container) {
findShape = findShape.container;
}
var node = findShape.minderNode;
if (node && findShape.getOpacity() < 1) return null;
return node || null;
},
stopPropagation: function() {
this._stoped = true;
},
stopPropagationImmediately: function() {
this._immediatelyStoped = true;
this._stoped = true;
},
shouldStopPropagation: function() {
return this._canstop && this._stoped;
},
shouldStopPropagationImmediately: function() {
return this._canstop && this._immediatelyStoped;
},
preventDefault: function() {
this.originEvent.preventDefault();
},
isRightMB: function() {
var isRightMB = false;
if (!this.originEvent) {
return false;
}
if ("which" in this.originEvent)
isRightMB = this.originEvent.which == 3;
else if ("button" in this.originEvent)
isRightMB = this.originEvent.button == 2;
return isRightMB;
},
getKeyCode: function(){
var evt = this.originEvent;
return evt.keyCode || evt.which;
} }
});
KityMinder.registerInit(function() { var MinderEvent = kity.createClass('MindEvent', {
this._initEvents(); constructor: function(type, params, canstop) {
}); params = params || {};
if (params.getType && params.getType() == 'ShapeEvent') {
// 事件机制 this.kityEvent = params;
kity.extendClass(KityMinder, { this.originEvent = params.originEvent;
_initEvents: function() { this.getPosition = params.getPosition.bind(params);
this._eventCallbacks = {}; } else if (params.target && params.preventDefault) {
}, this.originEvent = params;
_bindEvents: function() { } else {
this._bindPaperEvents(); kity.Utils.extend(this, params);
this._bindKeyboardEvents(); }
}, this.type = type;
_resetEvents: function() { this._canstop = canstop || false;
this._initEvents(); },
this._bindEvents();
}, getTargetNode: function() {
// TODO: mousemove lazy bind var findShape = this.kityEvent && this.kityEvent.targetShape;
_bindPaperEvents: function() { if (!findShape) return null;
this._paper.on('click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this)); while (!findShape.minderNode && findShape.container) {
if (window) { findShape = findShape.container;
window.addEventListener('resize', this._firePharse.bind(this)); }
window.addEventListener('blur', this._firePharse.bind(this)); var node = findShape.minderNode;
} if (node && findShape.getOpacity() < 1) return null;
}, return node || null;
_bindKeyboardEvents: function() { },
if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
//只能在这里做,要不无法触发 stopPropagation: function() {
Utils.listen(document.body, 'keydown keyup keypress paste', this._firePharse.bind(this)); this._stoped = true;
} },
},
_firePharse: function(e) { stopPropagationImmediately: function() {
// //只读模式下强了所有的事件操作 this._immediatelyStoped = true;
// if(this.readOnly === true){ this._stoped = true;
// return false; },
// }
var beforeEvent, preEvent, executeEvent; shouldStopPropagation: function() {
return this._canstop && this._stoped;
if (e.type == 'DOMMouseScroll') { },
e.type = 'mousewheel';
e.wheelDelta = e.originEvent.wheelDelta = e.originEvent.detail * -10; shouldStopPropagationImmediately: function() {
e.wheelDeltaX = e.originEvent.mozMovementX; return this._canstop && this._immediatelyStoped;
e.wheelDeltaY = e.originEvent.mozMovementY; },
} preventDefault: function() {
this.originEvent.preventDefault();
beforeEvent = new MinderEvent('before' + e.type, e, true); },
if (this._fire(beforeEvent)) { isRightMB: function() {
return; var isRightMB = false;
} if (!this.originEvent) {
preEvent = new MinderEvent('pre' + e.type, e, true); return false;
executeEvent = new MinderEvent(e.type, e, true); }
if ('which' in this.originEvent)
if (this._fire(preEvent) || isRightMB = this.originEvent.which == 3;
this._fire(executeEvent)) else if ('button' in this.originEvent)
this._fire(new MinderEvent('after' + e.type, e, false)); isRightMB = this.originEvent.button == 2;
}, return isRightMB;
_interactChange: function(e) { },
var me = this; getKeyCode: function(){
if (me._interactScheduled) return; var evt = this.originEvent;
setTimeout(function() { return evt.keyCode || evt.which;
me._fire(new MinderEvent('interactchange'));
me._interactScheduled = false;
}, 100);
me._interactScheduled = true;
},
_listen: function(type, callback) {
var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
callbacks.push(callback);
},
_fire: function(e) {
var status = this.getStatus();
var callbacks = this._eventCallbacks[e.type.toLowerCase()] || [];
if (status) {
callbacks = callbacks.concat(this._eventCallbacks[status + '.' + e.type.toLowerCase()] || []);
} }
});
Minder.registerInitHook(function() {
this._initEvents();
});
kity.extendClass(Minder, {
_initEvents: function() {
this._eventCallbacks = {};
},
_bindEvents: function() {
this._bindPaperEvents();
this._bindKeyboardEvents();
},
_resetEvents: function() {
this._initEvents();
this._bindEvents();
},
_bindPaperEvents: function() {
/* jscs:disable maximumLineLength */
this._paper.on('click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
if (window) {
window.addEventListener('resize', this._firePharse.bind(this));
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));
}
},
_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;
}
if (callbacks.length === 0) { beforeEvent = new MinderEvent('before' + e.type, e, true);
return; if (this._fire(beforeEvent)) {
} return;
var lastStatus = this.getStatus(); }
preEvent = new MinderEvent('pre' + e.type, e, true);
executeEvent = new MinderEvent(e.type, e, true);
if (this._fire(preEvent) ||
this._fire(executeEvent))
this._fire(new MinderEvent('after' + e.type, e, false));
},
_interactChange: function(e) {
var me = this;
if (me._interactScheduled) return;
setTimeout(function() {
me._fire(new MinderEvent('interactchange'));
me._interactScheduled = false;
}, 100);
me._interactScheduled = true;
},
_listen: function(type, callback) {
var callbacks = this._eventCallbacks[type] || (this._eventCallbacks[type] = []);
callbacks.push(callback);
},
_fire: function(e) {
var status = this.getStatus();
var callbacks = this._eventCallbacks[e.type.toLowerCase()] || [];
if (status) {
callbacks = callbacks.concat(this._eventCallbacks[status + '.' + e.type.toLowerCase()] || []);
}
for (var i = 0; i < callbacks.length; i++) { if (callbacks.length === 0) {
return;
}
callbacks[i].call(this, e); var lastStatus = this.getStatus();
for (var i = 0; i < callbacks.length; i++) {
callbacks[i].call(this, e);
/* this.getStatus() != lastStatus ||*/ /* this.getStatus() != lastStatus ||*/
if (e.shouldStopPropagationImmediately()) { if (e.shouldStopPropagationImmediately()) {
break; break;
}
} }
}
return e.shouldStopPropagation(); return e.shouldStopPropagation();
}, },
on: function(name, callback) {
var km = this; on: function(name, callback) {
utils.each(name.split(/\s+/), function(i, n) { var km = this;
km._listen(n.toLowerCase(), callback); name.split(/\s+/).forEach(function(n) {
}); km._listen(n.toLowerCase(), callback);
return this; });
}, return this;
off: function(name, callback) { },
var types = name.split(/\s+/); off: function(name, callback) {
var i, j, callbacks, removeIndex;
for (i = 0; i < types.length; i++) { var types = name.split(/\s+/);
var i, j, callbacks, removeIndex;
callbacks = this._eventCallbacks[types[i].toLowerCase()]; for (i = 0; i < types.length; i++) {
if (callbacks) {
removeIndex = null; callbacks = this._eventCallbacks[types[i].toLowerCase()];
for (j = 0; j < callbacks.length; j++) { if (callbacks) {
if (callbacks[j] == callback) { removeIndex = null;
removeIndex = j; for (j = 0; j < callbacks.length; j++) {
if (callbacks[j] == callback) {
removeIndex = j;
}
}
if (removeIndex !== null) {
callbacks.splice(removeIndex, 1);
} }
}
if (removeIndex !== null) {
callbacks.splice(removeIndex, 1);
} }
} }
},
fire: function(type, params) {
var e = new MinderEvent(type, params);
this._fire(e);
return this;
} }
}, });
fire: function(type, params) {
var e = new MinderEvent(type, params); module.exports = MinderEvent;
this._fire(e); });
return this;
}
});
\ No newline at end of file
...@@ -7,126 +7,134 @@ ...@@ -7,126 +7,134 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
/** define(function(require, exports, module) {
* 计算包含 meta 键的 keycode var kity = require('./kity.js');
* var utils = require('./utils');
* @param {String|KeyEvent} unknown var keymap = require('./keymap');
*/ var Minder = require('./minder');
function getMetaKeyCode(unknown) { var MinderEvent = require('./event');
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; /**
} * 计算包含 meta 键的 keycode
kity.extendClass(MinderEvent, { *
isShortcutKey: function(keyCombine) { * @param {String|KeyEvent} unknown
var keyEvent = this.originEvent; */
if (!keyEvent) return false; function getMetaKeyCode(unknown) {
var CTRL_MASK = 0x1000;
var ALT_MASK = 0x2000;
var SHIFT_MASK = 0x4000;
var metaKeyCode = 0;
return getMetaKeyCode(keyCombine) == getMetaKeyCode(keyEvent); if (typeof(unknown) == 'string') {
} // unknown as string
}); unknown.toLowerCase().split(/\+\s*/).forEach(function(name) {
switch(name) {
KityMinder.registerInit(function() { case 'ctrl':
this._initShortcutKey(); case 'cmd':
}); metaKeyCode |= CTRL_MASK;
break;
kity.extendClass(KityMinder, { case 'alt':
metaKeyCode |= ALT_MASK;
_initShortcutKey: function() { break;
this._bindShortcutKeys(); case 'shift':
}, metaKeyCode |= SHIFT_MASK;
break;
_bindShortcutKeys: function() { default:
var map = this._shortcutKeys = {}; metaKeyCode |= keymap[name];
var has = 'hasOwnProperty';
this.on('keydown', function(e) {
for (var keys in map) {
if (!map[has](keys)) continue;
if (e.isShortcutKey(keys)) {
var fn = map[keys];
if (fn.__statusCondition && fn.__statusCondition != this.getStatus()) return;
fn();
e.preventDefault();
} }
});
} else {
// unknown as key event
if (unknown.ctrlKey || unknown.metaKey) {
metaKeyCode |= CTRL_MASK;
} }
}); if (unknown.altKey) {
}, metaKeyCode |= ALT_MASK;
addShortcut: function(keys, fn) {
var binds = this._shortcutKeys;
keys.split(/\|\s*/).forEach(function(combine) {
var parts = combine.split('::');
var status;
if (parts.length > 1) {
combine = parts[1];
status = parts[0];
fn.__statusCondition = status;
} }
binds[combine] = fn; if (unknown.shiftKey) {
}); metaKeyCode |= SHIFT_MASK;
}, }
metaKeyCode |= unknown.keyCode;
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; return metaKeyCode;
}
kity.extendClass(MinderEvent, {
isShortcutKey: function(keyCombine) {
var keyEvent = this.originEvent;
if (!keyEvent) return false;
utils.each(obj, function(command, keys) { return getMetaKeyCode(keyCombine) == getMetaKeyCode(keyEvent);
}
});
binds[command] = keys; Minder.registerInitHook(function() {
this._initShortcutKey();
});
minder.addShortcut(keys, function execCommandByShortcut() { kity.extendClass(Minder, {
if (minder.queryCommandState(command) === 0) {
minder.execCommand(command); _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)) continue;
if (e.isShortcutKey(keys)) {
var fn = map[keys];
if (fn.__statusCondition && fn.__statusCondition != this.getStatus()) return;
fn();
e.preventDefault();
}
} }
}); });
}); },
},
getCommandShortcutKey: function(cmd) { addShortcut: function(keys, fn) {
var binds = this._commandShortcutKeys; var binds = this._shortcutKeys;
return binds && binds[cmd] || null; keys.split(/\|\s*/).forEach(function(combine) {
} var parts = combine.split('::');
var status;
if (parts.length > 1) {
combine = parts[1];
status = parts[0];
fn.__statusCondition = status;
}
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(keys, command) {
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
var keymap = KityMinder.keymap = (function(origin) { define(function(require, exports, module) {
var ret = {}; var keymap = {
for (var key in origin) { 'Backspace': 8,
if (origin.hasOwnProperty(key)) { 'Tab': 9,
ret[key] = origin[key]; 'Enter': 13,
ret[key.toLowerCase()] = origin[key];
'Shift': 16,
'Control': 17,
'Alt': 18,
'CapsLock': 20,
'Esc': 27,
'Spacebar': 32,
'PageUp': 33,
'PageDown': 34,
'End': 35,
'Home': 36,
'Insert': 45,
'Left': 37,
'Up': 38,
'Right': 39,
'Down': 40,
'direction': {
37: 1,
38: 1,
39: 1,
40: 1
},
'Del': 46,
'NumLock': 144,
'Cmd': 91,
'CmdFF': 224,
'F1': 112,
'F2': 113,
'F3': 114,
'F4': 115,
'F5': 116,
'F6': 117,
'F7': 118,
'F8': 119,
'F9': 120,
'F10': 121,
'F11': 122,
'F12': 123,
'`': 192,
'=': 187,
'-': 189,
'/': 191,
'.': 190,
controlKeys: {
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
224: 1
},
'notContentChange': {
13: 1,
9: 1,
33: 1,
34: 1,
35: 1,
36: 1,
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
113: 1,
114: 1,
115: 1,
144: 1,
27: 1
},
'isSelectedNodeKey': {
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
13: 1,
9: 1
}
};
// 小写适配
for (var key in keymap) {
if (keymap.hasOwnProperty(key)) {
keymap[key.toLowerCase()] = keymap[key];
} }
} }
var aKeyCode = 65; var aKeyCode = 65;
...@@ -11,118 +115,14 @@ var keymap = KityMinder.keymap = (function(origin) { ...@@ -11,118 +115,14 @@ var keymap = KityMinder.keymap = (function(origin) {
// letters // letters
'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) { 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
ret[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode); keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
}); });
// numbers // numbers
var n = 9; var n = 9;
do { do {
ret[n.toString()] = n + 48; keymap[n.toString()] = n + 48;
} while(--n); } while(--n);
return ret; module.exports = keymap;
})({
'Backspace': 8,
'Tab': 9,
'Enter': 13,
'Shift': 16,
'Control': 17,
'Alt': 18,
'CapsLock': 20,
'Esc': 27,
'Spacebar': 32,
'PageUp': 33,
'PageDown': 34,
'End': 35,
'Home': 36,
'Insert': 45,
'Left': 37,
'Up': 38,
'Right': 39,
'Down': 40,
'direction': {
37: 1,
38: 1,
39: 1,
40: 1
},
'Del': 46,
'NumLock': 144,
'Cmd': 91,
'CmdFF': 224,
'F1': 112,
'F2': 113,
'F3': 114,
'F4': 115,
'F5': 116,
'F6': 117,
'F7': 118,
'F8': 119,
'F9': 120,
'F10': 121,
'F11': 122,
'F12': 123,
'`': 192,
'=': 187,
'-': 189,
'/': 191,
'.': 190,
controlKeys: {
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
224: 1
},
'notContentChange': {
13: 1,
9: 1,
33: 1,
34: 1,
35: 1,
36: 1,
16: 1,
17: 1,
18: 1,
20: 1,
91: 1,
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
113: 1,
114: 1,
115: 1,
144: 1,
27: 1
},
'isSelectedNodeKey': {
//上下左右
37: 1,
38: 1,
39: 1,
40: 1,
13: 1,
9: 1
}
}); });
\ No newline at end of file
/**
* @fileOverview
*
* Kity 引入
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
module.exports = require('../../lib/kity/src/kity.js');
});
\ No newline at end of file
/**
* @fileOverview
*
* KityMinder 类,暴露在 window 上的唯一变量
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
/* jshint -W079 */
var _initFnQueue = [];
var _uuidMap = {};
var KityMinder = kity.createClass('KityMinder', {
constructor: function(options) {
this._options = Utils.extend({}, options);
var initQueue = _initFnQueue.slice();
// @see option.js
// @see event.js
// @see status.js
// @see paper.js
// @see select.js
// @see key.js
// @see contextmenu.js
// @see module.js
// @see data.js
// @see readonly.js
// @see layout.js
// @see theme.js
while (initQueue.length) initQueue.shift().call(this, options);
this.fire('ready');
}
});
KityMinder.version = '1.0.0';
KityMinder.registerInit = function(fn) {
_initFnQueue.push(fn);
};
KityMinder.uuid = function(name) {
name = name || 'unknown';
_uuidMap[name] = _uuidMap[name] || 0;
++_uuidMap[name];
return name + '_' + _uuidMap[name];
};
// expose
if (typeof(module) != 'undefined') {
module.exports = KityMinder;
} else {
window.KityMinder = KityMinder;
}
/** define(function(require, exports, module) {
* 布局支持池子管理 var kity = require('./kity');
*/ var utils = require('./utils');
Utils.extend(KityMinder, { var Minder = require('./minder');
_layout: {}, var MinderNode = require('./node');
var MinderEvent = require('./event');
registerLayout: function(name, layout) { var Command = require('./command');
KityMinder._layout[name] = layout;
if (!KityMinder._defaultLayout) { var _layouts = {};
KityMinder._defaultLayout = name; var _defaultLayout;
}
}, function register(name, layout) {
_layouts[name] = layout;
getLayoutList: function() { _defaultLayout = _defaultLayout || name;
return this._layout;
},
getLayoutInstance: function(name) {
var LayoutClass = KityMinder._layout[name];
if (!LayoutClass) throw new Error('Missing Layout: ' + name);
var layout = new LayoutClass();
return layout;
} }
});
/**
* MinderNode 上的布局支持
*/
kity.extendClass(MinderNode, {
/** /**
* 获得当前节点的布局名称 * @class Layout 布局基类,具体布局需要从该类派生
*
* @return {String}
*/ */
getLayout: function() { var Layout = kity.createClass('Layout', {
var layout = this.getData('layout');
/**
* @abstract
*
* 子类需要实现的布局算法,该算法输入一个节点,排布该节点的子节点(相对父节点的变换)
*
* @param {MinderNode} node 需要布局的节点
*
* @example
*
* doLayout: function(node) {
* var children = node.getChildren();
* // layout calculation
* children[i].setLayoutTransform(new kity.Matrix().translate(x, y));
* }
*/
doLayout: function(node) {
throw new Error('Not Implement: Layout.doLayout()');
},
/**
* 对齐指定的节点
*
* @param {Array<MinderNode>} nodes 要对齐的节点
* @param {string} border 对齐边界,允许取值 left, right, top, bottom
*
*/
align: function(nodes, border, offset) {
var me = this;
offset = offset || 0;
nodes.forEach(function(node) {
var tbox = me.getTreeBox([node]);
var matrix = node.getLayoutTransform();
switch (border) {
case 'left':
return matrix.translate(offset - tbox.left, 0);
case 'right':
return matrix.translate(offset - tbox.right, 0);
case 'top':
return matrix.translate(0, offset - tbox.top);
case 'bottom':
return matrix.translate(0, offset - tbox.bottom);
}
});
},
stack: function(nodes, axis, distance) {
var me = this;
var position = 0;
distance = distance || function(node, next, axis) {
return node.getStyle({
x: 'margin-right',
y: 'margin-bottom'
}[axis]) + next.getStyle({
x: 'margin-left',
y: 'margin-top'
}[axis]);
};
nodes.forEach(function(node, index, nodes) {
var tbox = me.getTreeBox([node]);
var size = {
x: tbox.width,
y: tbox.height
}[axis];
var offset = {
x: tbox.left,
y: tbox.top
}[axis];
var matrix = node.getLayoutTransform();
if (axis == 'x') {
matrix.translate(position - offset, 0);
} else {
matrix.translate(0, position - offset);
}
position += size;
if (nodes[index + 1])
position += distance(node, nodes[index + 1], axis);
});
return position;
},
layout = layout || (this.isRoot() ? KityMinder._defaultLayout : this.parent.getLayout()); move: function(nodes, dx, dy) {
nodes.forEach(function(node) {
node.getLayoutTransform().translate(dx, dy);
});
},
/**
* 工具方法:获取给点的节点所占的布局区域
*
* @param {MinderNode[]} nodes 需要计算的节点
*
* @return {Box} 计算结果
*/
getBranchBox: function(nodes) {
var box = new kity.Box();
var i, node, matrix, contentBox;
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
matrix = node.getLayoutTransform();
contentBox = node.getContentBox();
box = box.merge(matrix.transformBox(contentBox));
}
return layout; return box;
}, },
setLayout: function(name) { /**
if (name) { * 工具方法:计算给定的节点的子树所占的布局区域
if (name == 'inherit') { *
this.setData('layout'); * @param {MinderNode} nodes 需要计算的节点
} else { *
this.setData('layout', name); * @return {Box} 计算的结果
} */
} getTreeBox: function(nodes) {
return this;
},
layout: function(name, duration) { var i, node, matrix, treeBox;
this.setLayout(name).getMinder().layout(duration); var box = new kity.Box();
return this; if (!(nodes instanceof Array)) nodes = [nodes];
},
getLayoutInstance: function() { for (i = 0; i < nodes.length; i++) {
return KityMinder.getLayoutInstance(this.getLayout()); node = nodes[i];
}, matrix = node.getLayoutTransform();
getOrderHint: function(refer) { treeBox = node.getContentBox();
return this.parent.getLayoutInstance().getOrderHint(this);
},
getExpandPosition: function() { if (node.isExpanded() && node.children.length) {
return this.getLayoutInstance().getExpandPosition(); treeBox = treeBox.merge(this.getTreeBox(node.children));
}, }
/** box = box.merge(matrix.transformBox(treeBox));
* 获取当前节点相对于父节点的布局变换 }
*/
getLayoutTransform: function() {
return this._layoutTransform || new kity.Matrix();
},
/** return box;
* 第一轮布局计算后,获得的全局布局位置 },
*
* @return {[type]} [description] getOrderHint: function(node) {
*/ return [];
getGlobalLayoutTransformPreview: function() {
var pMatrix = this.parent ? this.parent.getLayoutTransform() : new kity.Matrix();
var matrix = this.getLayoutTransform();
var offset = this.getLayoutOffset();
if (offset) {
matrix.translate(offset.x, offset.y);
} }
return pMatrix.merge(matrix); });
},
getLayoutPointPreview: function() { Layout.register = register;
return this.getGlobalLayoutTransformPreview().transformPoint(new kity.Point());
},
/** Minder.registerInitHook(function(options) {
* 获取节点相对于全局的布局变换 this.refresh();
*/ });
getGlobalLayoutTransform: function() {
if (this._globalLayoutTransform) {
return this._globalLayoutTransform;
} else if (this.parent) {
return this.parent.getGlobalLayoutTransform();
} else {
return new kity.Matrix();
}
},
/** /**
* 设置当前节点相对于父节点的布局变换 * 布局支持池子管理
*/ */
setLayoutTransform: function(matrix) { utils.extend(Minder, {
this._layoutTransform = matrix;
return this;
},
/** getLayoutList: function() {
* 设置当前节点相对于全局的布局变换(冗余优化) return _layouts;
*/ },
setGlobalLayoutTransform: function(matrix) {
this.getRenderContainer().setMatrix(this._globalLayoutTransform = matrix);
return this;
},
setVertexIn: function(p) { getLayoutInstance: function(name) {
this._vertexIn = p; var LayoutClass = _layouts[name];
}, if (!LayoutClass) throw new Error('Missing Layout: ' + name);
var layout = new LayoutClass();
return layout;
}
});
setVertexOut: function(p) { /**
this._vertexOut = p; * MinderNode 上的布局支持
}, */
kity.extendClass(MinderNode, {
/**
* 获得当前节点的布局名称
*
* @return {String}
*/
getLayout: function() {
var layout = this.getData('layout');
layout = layout || (this.isRoot() ? _defaultLayout : this.parent.getLayout());
return layout;
},
setLayout: function(name) {
if (name) {
if (name == 'inherit') {
this.setData('layout');
} else {
this.setData('layout', name);
}
}
return this;
},
getVertexIn: function() { layout: function(name, duration) {
return this._vertexIn || new kity.Point();
},
getVertexOut: function() { this.setLayout(name).getMinder().layout(duration);
return this._vertexOut || new kity.Point();
},
getLayoutVertexIn: function() { return this;
return this.getGlobalLayoutTransform().transformPoint(this.getVertexIn()); },
},
getLayoutInstance: function() {
return Minder.getLayoutInstance(this.getLayout());
},
getOrderHint: function(refer) {
return this.parent.getLayoutInstance().getOrderHint(this);
},
getExpandPosition: function() {
return this.getLayoutInstance().getExpandPosition();
},
/**
* 获取当前节点相对于父节点的布局变换
*/
getLayoutTransform: function() {
return this._layoutTransform || new kity.Matrix();
},
/**
* 第一轮布局计算后,获得的全局布局位置
*
* @return {[type]} [description]
*/
getGlobalLayoutTransformPreview: function() {
var pMatrix = this.parent ? this.parent.getLayoutTransform() : new kity.Matrix();
var matrix = this.getLayoutTransform();
var offset = this.getLayoutOffset();
if (offset) {
matrix.translate(offset.x, offset.y);
}
return pMatrix.merge(matrix);
},
getLayoutPointPreview: function() {
return this.getGlobalLayoutTransformPreview().transformPoint(new kity.Point());
},
/**
* 获取节点相对于全局的布局变换
*/
getGlobalLayoutTransform: function() {
if (this._globalLayoutTransform) {
return this._globalLayoutTransform;
} else if (this.parent) {
return this.parent.getGlobalLayoutTransform();
} else {
return new kity.Matrix();
}
},
getLayoutVertexOut: function() { /**
return this.getGlobalLayoutTransform().transformPoint(this.getVertexOut()); * 设置当前节点相对于父节点的布局变换
}, */
setLayoutTransform: function(matrix) {
this._layoutTransform = matrix;
return this;
},
setLayoutVectorIn: function(v) { /**
this._layoutVectorIn = v; * 设置当前节点相对于全局的布局变换(冗余优化)
return this; */
}, setGlobalLayoutTransform: function(matrix) {
this.getRenderContainer().setMatrix(this._globalLayoutTransform = matrix);
return this;
},
setLayoutVectorOut: function(v) { setVertexIn: function(p) {
this._layoutVectorOut = v; this._vertexIn = p;
return this; },
},
getLayoutVectorIn: function() { setVertexOut: function(p) {
return this._layoutVectorIn || new kity.Vector(); this._vertexOut = p;
}, },
getLayoutVectorOut: function() { getVertexIn: function() {
return this._layoutVectorOut || new kity.Vector(); return this._vertexIn || new kity.Point();
}, },
getLayoutBox: function() { getVertexOut: function() {
var matrix = this.getGlobalLayoutTransform(); return this._vertexOut || new kity.Point();
return matrix.transformBox(this.getContentBox()); },
},
getLayoutPoint: function() { getLayoutVertexIn: function() {
var matrix = this.getGlobalLayoutTransform(); return this.getGlobalLayoutTransform().transformPoint(this.getVertexIn());
return matrix.transformPoint(new kity.Point()); },
},
getLayoutOffset: function() { getLayoutVertexOut: function() {
if (!this.parent) return new kity.Point(); return this.getGlobalLayoutTransform().transformPoint(this.getVertexOut());
},
// 影响当前节点位置的是父节点的布局 setLayoutVectorIn: function(v) {
var data = this.getData('layout_' + this.parent.getLayout() + '_offset'); this._layoutVectorIn = v;
return this;
},
if (data) return new kity.Point(data.x, data.y); setLayoutVectorOut: function(v) {
this._layoutVectorOut = v;
return this;
},
return new kity.Point(); getLayoutVectorIn: function() {
}, return this._layoutVectorIn || new kity.Vector();
},
setLayoutOffset: function(p) { getLayoutVectorOut: function() {
if (!this.parent) return this; return this._layoutVectorOut || new kity.Vector();
},
if (p && !this.hasLayoutOffset()) { getLayoutBox: function() {
var m = this.getLayoutTransform().m; var matrix = this.getGlobalLayoutTransform();
p = p.offset(m.e, m.f); return matrix.transformBox(this.getContentBox());
this.setLayoutTransform(null); },
}
this.setData('layout_' + this.parent.getLayout() + '_offset', p ? { getLayoutPoint: function() {
x: p.x, var matrix = this.getGlobalLayoutTransform();
y: p.y return matrix.transformPoint(new kity.Point());
} : null); },
return this; getLayoutOffset: function() {
}, if (!this.parent) return new kity.Point();
hasLayoutOffset: function() { // 影响当前节点位置的是父节点的布局
return !!this.getData('layout_' + this.parent.getLayout() + '_offset'); var data = this.getData('layout_' + this.parent.getLayout() + '_offset');
},
resetLayoutOffset: function() { if (data) return new kity.Point(data.x, data.y);
return this.setLayoutOffset(null);
},
getLayoutRoot: function() { return new kity.Point();
if (this.isLayoutRoot()) { },
return this;
}
return this.parent.getLayoutRoot();
},
isLayoutRoot: function() { setLayoutOffset: function(p) {
return this.getData('layout') || this.isRoot(); if (!this.parent) return this;
}
});
KityMinder.registerInit(function(options) { if (p && !this.hasLayoutOffset()) {
this.refresh(); var m = this.getLayoutTransform().m;
}); p = p.offset(m.e, m.f);
this.setLayoutTransform(null);
}
kity.extendClass(KityMinder, { this.setData('layout_' + this.parent.getLayout() + '_offset', p ? {
x: p.x,
y: p.y
} : null);
layout: function(duration) { return this;
},
this.getRoot().traverse(function(node) { hasLayoutOffset: function() {
// clear last results return !!this.getData('layout_' + this.parent.getLayout() + '_offset');
node.setLayoutTransform(null); },
});
function layoutNode(node, round) { resetLayoutOffset: function() {
return this.setLayoutOffset(null);
},
// layout all children first getLayoutRoot: function() {
// 剪枝:收起的节点无需计算 if (this.isLayoutRoot()) {
if (node.isExpanded() || true) { return this;
node.children.forEach(function(child) {
layoutNode(child, round);
});
} }
return this.parent.getLayoutRoot();
},
var layout = node.getLayoutInstance(); isLayoutRoot: function() {
var childrenInFlow = node.getChildren().filter(function(child) { return this.getData('layout') || this.isRoot();
return !child.hasLayoutOffset();
});
layout.doLayout(node, childrenInFlow, round);
} }
});
// 第一轮布局 /**
layoutNode(this.getRoot(), 1); * Minder 上的布局支持
*/
// 第二轮布局 kity.extendClass(Minder, {
layoutNode(this.getRoot(), 2);
duration = duration ? 300 : 0;
var minder = this;
this.applyLayoutResult(this.getRoot(), duration).then(function() {
minder.fire('layoutallfinish');
});
return this.fire('layout');
},
refresh: function(duration) { layout: function(duration) {
this.getRoot().renderTree();
this.layout(duration).fire('contentchange')._interactChange();
return this;
},
applyLayoutResult: function(root, duration) { this.getRoot().traverse(function(node) {
root = root || this.getRoot(); // clear last results
var me = this; node.setLayoutTransform(null);
var deffered = {}; });
var promise = new Promise(function(resolve, reject) { function layoutNode(node, round) {
deffered.resolve = resolve;
deffered.reject = reject;
});
var complex = root.getComplex(); // layout all children first
// 剪枝:收起的节点无需计算
if (node.isExpanded() || true) {
node.children.forEach(function(child) {
layoutNode(child, round);
});
}
function consume() { var layout = node.getLayoutInstance();
if (!--complex) { var childrenInFlow = node.getChildren().filter(function(child) {
deffered.resolve(); return !child.hasLayoutOffset();
});
layout.doLayout(node, childrenInFlow, round);
} }
}
// 节点复杂度大于 100,关闭动画 // 第一轮布局
if (complex > 200) duration = 0; layoutNode(this.getRoot(), 1);
// 第二轮布局
layoutNode(this.getRoot(), 2);
function applyMatrix(node, matrix) { duration = duration ? 300 : 0;
node.setGlobalLayoutTransform(matrix);
me.fire('layoutapply', { var minder = this;
node: node, this.applyLayoutResult(this.getRoot(), duration, function() {
matrix: matrix minder.fire('layoutallfinish');
}); });
}
function apply(node, pMatrix) { return this.fire('layout');
var matrix = node.getLayoutTransform().merge(pMatrix); },
var lastMatrix = node.getGlobalLayoutTransform() || new kity.Matrix();
var offset = node.getLayoutOffset(); refresh: function(duration) {
matrix.translate(offset.x, offset.y); this.getRoot().renderTree();
this.layout(duration).fire('contentchange')._interactChange();
return this;
},
matrix.m.e = Math.round(matrix.m.e); applyLayoutResult: function(root, duration, callback) {
matrix.m.f = Math.round(matrix.m.f); root = root || this.getRoot();
var me = this;
var complex = root.getComplex();
// 如果当前有动画,停止动画 function consume() {
if (node._layoutTimeline) { if (!--complex) {
node._layoutTimeline.stop(); if (callback) {
node._layoutTimeline = null; callback();
}
}
} }
// 如果要求以动画形式来更新,创建动画 // 节点复杂度大于 100,关闭动画
if (duration) { if (complex > 200) duration = 0;
node._layoutTimeline = new kity.Animator(lastMatrix, matrix, applyMatrix)
.start(node, duration, 'ease')
.on('finish', function() {
//可能性能低的时候会丢帧,手动添加一帧
setTimeout(function() {
applyMatrix(node, matrix);
me.fire('layoutfinish', {
node: node,
matrix: matrix
});
consume();
}, 150);
});
}
// 否则直接更新 function applyMatrix(node, matrix) {
else { node.setGlobalLayoutTransform(matrix);
applyMatrix(node, matrix);
me.fire('layoutfinish', { me.fire('layoutapply', {
node: node, node: node,
matrix: matrix matrix: matrix
}); });
consume();
} }
for (var i = 0; i < node.children.length; i++) { function apply(node, pMatrix) {
apply(node.children[i], matrix); var matrix = node.getLayoutTransform().merge(pMatrix);
} var lastMatrix = node.getGlobalLayoutTransform() || new kity.Matrix();
}
apply(root, root.parent ? root.parent.getGlobalLayoutTransform() : new kity.Matrix()); var offset = node.getLayoutOffset();
return promise; matrix.translate(offset.x, offset.y);
},
});
matrix.m.e = Math.round(matrix.m.e);
matrix.m.f = Math.round(matrix.m.f);
/**
* @class Layout 布局基类,具体布局需要从该类派生
*/
var Layout = kity.createClass('Layout', {
/**
* @abstract
*
* 子类需要实现的布局算法,该算法输入一个节点,排布该节点的子节点(相对父节点的变换)
*
* @param {MinderNode} node 需要布局的节点
*
* @example
*
* doLayout: function(node) {
* var children = node.getChildren();
* // layout calculation
* children[i].setLayoutTransform(new kity.Matrix().translate(x, y));
* }
*/
doLayout: function(node) {
throw new Error('Not Implement: Layout.doLayout()');
},
/**
* 对齐指定的节点
*
* @param {Array<MinderNode>} nodes 要对齐的节点
* @param {string} border 对齐边界,允许取值 left, right, top, bottom
*
*/
align: function(nodes, border, offset) {
var me = this;
offset = offset || 0;
nodes.forEach(function(node) {
var tbox = me.getTreeBox([node]);
var matrix = node.getLayoutTransform();
switch (border) {
case 'left':
return matrix.translate(offset - tbox.left, 0);
case 'right':
return matrix.translate(offset - tbox.right, 0);
case 'top':
return matrix.translate(0, offset - tbox.top);
case 'bottom':
return matrix.translate(0, offset - tbox.bottom);
}
});
},
stack: function(nodes, axis, distance) {
var me = this;
var position = 0;
distance = distance || function(node, next, axis) {
return node.getStyle({
x: 'margin-right',
y: 'margin-bottom'
}[axis]) + next.getStyle({
x: 'margin-left',
y: 'margin-top'
}[axis]);
};
nodes.forEach(function(node, index, nodes) {
var tbox = me.getTreeBox([node]);
var size = {
x: tbox.width,
y: tbox.height
}[axis];
var offset = {
x: tbox.left,
y: tbox.top
}[axis];
var matrix = node.getLayoutTransform();
if (axis == 'x') {
matrix.translate(position - offset, 0);
} else {
matrix.translate(0, position - offset);
}
position += size;
if (nodes[index + 1])
position += distance(node, nodes[index + 1], axis);
});
return position;
},
move: function(nodes, dx, dy) {
nodes.forEach(function(node) {
node.getLayoutTransform().translate(dx, dy);
});
},
/**
* 工具方法:获取给点的节点所占的布局区域
*
* @param {MinderNode[]} nodes 需要计算的节点
*
* @return {Box} 计算结果
*/
getBranchBox: function(nodes) {
var box = new kity.Box();
var i, node, matrix, contentBox;
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
matrix = node.getLayoutTransform();
contentBox = node.getContentBox();
box = box.merge(matrix.transformBox(contentBox));
}
return box; // 如果当前有动画,停止动画
}, if (node._layoutTimeline) {
node._layoutTimeline.stop();
/** node._layoutTimeline = null;
* 工具方法:计算给定的节点的子树所占的布局区域 }
*
* @param {MinderNode} nodes 需要计算的节点
*
* @return {Box} 计算的结果
*/
getTreeBox: function(nodes) {
var i, node, matrix, treeBox;
var g = KityMinder.Geometry;
var box = {
x: 0,
y: 0,
height: 0,
width: 0
};
if (!(nodes instanceof Array)) nodes = [nodes];
for (i = 0; i < nodes.length; i++) { // 如果要求以动画形式来更新,创建动画
node = nodes[i]; if (duration) {
matrix = node.getLayoutTransform(); node._layoutTimeline = new kity.Animator(lastMatrix, matrix, applyMatrix)
.start(node, duration, 'ease')
.on('finish', function() {
//可能性能低的时候会丢帧,手动添加一帧
setTimeout(function() {
applyMatrix(node, matrix);
me.fire('layoutfinish', {
node: node,
matrix: matrix
});
consume();
}, 150);
});
}
treeBox = node.getContentBox(); // 否则直接更新
else {
applyMatrix(node, matrix);
me.fire('layoutfinish', {
node: node,
matrix: matrix
});
consume();
}
if (node.isExpanded() && node.children.length) { for (var i = 0; i < node.children.length; i++) {
treeBox = g.mergeBox(treeBox, this.getTreeBox(node.children)); apply(node.children[i], matrix);
}
} }
box = g.mergeBox(box, matrix.transformBox(treeBox)); apply(root, root.parent ? root.parent.getGlobalLayoutTransform() : new kity.Matrix());
} return this;
},
return box; });
},
getOrderHint: function(node) {
return [];
}
});
var LayoutCommand = kity.createClass('LayoutCommand', {
base: Command,
execute: function(minder, name) {
var nodes = minder.getSelectedNodes();
nodes.forEach(function(node) {
node.layout(name);
});
},
queryValue: function(minder) {
var node = minder.getSelectedNode();
if (node) {
return node.getData('layout');
}
},
queryState: function(minder) {
return minder.getSelectedNode() ? 0 : -1;
}
});
var ResetLayoutCommand = kity.createClass('ResetLayoutCommand', {
base: Command,
execute: function(minder, name) {
var nodes = minder.getSelectedNodes();
if (!nodes.length) nodes = [minder.getRoot()];
nodes.forEach(function(node) { module.exports = Layout;
node.traverse(function(child) {
child.resetLayoutOffset();
if (!child.isRoot()) {
child.setData('layout', null);
}
});
});
minder.layout(300);
},
enableReadOnly: true
});
KityMinder.registerModule('LayoutModule', {
commands: {
'layout': LayoutCommand,
'resetlayout': ResetLayoutCommand
},
contextmenu: [{
command: 'resetlayout'
}, {
divider: true
}],
commandShortcutKeys: {
'resetlayout': 'Ctrl+Shift+L'
}
}); });
\ No newline at end of file
/**
* @fileOverview
*
* KityMinder 类,暴露在 window 上的唯一变量
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kity = require('./kity');
var utils = require('./utils');
var _initHooks = [];
var Minder = kity.createClass('Minder', {
constructor: function(options) {
this._options = utils.extend({}, options);
var initHooks = _initHooks.slice();
var initHook;
while (initHooks.length) {
initHook = initHooks.shift();
if (typeof(initHook) == 'function') {
initHook.call(this, this._options);
}
}
this.fire('ready');
}
});
Minder.version = '1.3.6';
Minder.registerInitHook = function(hook) {
_initHooks.push(hook);
};
module.exports = Minder;
});
//模块注册&暴露模块接口 define(function(require, exports, module) {
( function () { var kity = require('./kity');
var _modules; var utils = require('./utils');
KityMinder.registerModule = function ( name, module ) { var Minder = require('./minder');
//初始化模块列表
if ( !_modules ) { /* 已注册的模块 */
_modules = {}; var _modules = {};
}
_modules[ name ] = module; exports.register = function(name, module) {
}; _modules[name] = module;
KityMinder.getModules = function () {
return _modules;
}; };
} )();
KityMinder.registerInit(function() { /* 模块初始化 */
this._initModules(); Minder.registerInitHook(function() {
}); this._initModules();
});
// 模块声明周期维护 // 模块声明周期维护
kity.extendClass(KityMinder, { kity.extendClass(Minder, {
_initModules: function() { _initModules: function() {
var modulesPool = KityMinder.getModules(); var modulesPool = _modules;
var modulesToLoad = this._options.modules || Utils.keys(modulesPool); var modulesToLoad = this._options.modules || utils.keys(modulesPool);
this._commands = {}; this._commands = {};
this._query = {}; this._query = {};
this._modules = {}; this._modules = {};
this._rendererClasses = {}; this._rendererClasses = {};
var i, name, type, module, moduleDeals, var i, name, type, module, moduleDeals,
dealCommands, dealEvents, dealRenderers; dealCommands, dealEvents, dealRenderers;
var me = this; var me = this;
for (i = 0; i < modulesToLoad.length; i++) { for (i = 0; i < modulesToLoad.length; i++) {
name = modulesToLoad[i]; name = modulesToLoad[i];
if (!modulesPool[name]) continue; if (!modulesPool[name]) continue;
// 执行模块初始化,抛出后续处理对象 // 执行模块初始化,抛出后续处理对象
if (typeof(modulesPool[name]) == 'function') { if (typeof(modulesPool[name]) == 'function') {
moduleDeals = modulesPool[name].call(me); moduleDeals = modulesPool[name].call(me);
} else { } else {
moduleDeals = modulesPool[name]; moduleDeals = modulesPool[name];
} }
this._modules[name] = moduleDeals; this._modules[name] = moduleDeals;
if (!moduleDeals) continue; if (!moduleDeals) continue;
if (moduleDeals.init) { if (moduleDeals.init) {
moduleDeals.init.call(me, this._options); moduleDeals.init.call(me, this._options);
} }
// command加入命令池子 // command加入命令池子
dealCommands = moduleDeals.commands; dealCommands = moduleDeals.commands;
for (name in dealCommands) { for (name in dealCommands) {
this._commands[name.toLowerCase()] = new dealCommands[name](); this._commands[name.toLowerCase()] = new dealCommands[name]();
} }
// 绑定事件 // 绑定事件
dealEvents = moduleDeals.events; dealEvents = moduleDeals.events;
if (dealEvents) { if (dealEvents) {
for (type in dealEvents) { for (type in dealEvents) {
me.on(type, dealEvents[type]); me.on(type, dealEvents[type]);
}
} }
}
// 渲染器 // 渲染器
dealRenderers = moduleDeals.renderers; dealRenderers = moduleDeals.renderers;
if (dealRenderers) { if (dealRenderers) {
for (type in dealRenderers) { for (type in dealRenderers) {
this._rendererClasses[type] = this._rendererClasses[type] || []; this._rendererClasses[type] = this._rendererClasses[type] || [];
if (Utils.isArray(dealRenderers[type])) { if (utils.isArray(dealRenderers[type])) {
this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]); this._rendererClasses[type] = this._rendererClasses[type].concat(dealRenderers[type]);
} else { } else {
this._rendererClasses[type].push(dealRenderers[type]); this._rendererClasses[type].push(dealRenderers[type]);
}
} }
} }
}
} //添加模块的快捷键
}, if (moduleDeals.commandShortcutKeys) {
this.addCommandShortcutKeys(moduleDeals.commandShortcutKeys);
}
_garbage: function() { }
this.clearSelect(); },
while (this._root.getChildren().length) { _garbage: function() {
this._root.removeChild(0); this.clearSelect();
}
},
destroy: function() { while (this._root.getChildren().length) {
var modules = this._modules; this._root.removeChild(0);
}
},
this._resetEvents(); destroy: function() {
this._garbage(); var modules = this._modules;
for (var key in modules) { this._resetEvents();
if (!modules[key].destroy) continue; this._garbage();
modules[key].destroy.call(this);
}
},
reset: function() { for (var key in modules) {
var modules = this._modules; if (!modules[key].destroy) continue;
modules[key].destroy.call(this);
}
},
this._garbage(); reset: function() {
var modules = this._modules;
for (var key in modules) { this._garbage();
if (!modules[key].reset) continue;
modules[key].reset.call(this); for (var key in modules) {
if (!modules[key].reset) continue;
modules[key].reset.call(this);
}
} }
} });
}); });
\ No newline at end of file
var MinderNode = KityMinder.MinderNode = kity.createClass('MinderNode', { define(function(require, exports, module) {
var kity = require('./kity');
var utils = require('./utils');
var Minder = require('./minder');
/** /**
* 创建一个节点 * @class MinderNode
* *
* @param {KityMinder} minder * 表示一个脑图节点
* 节点绑定的脑图的实例
*
* @param {String|Object} unknown
* 节点的初始数据或文本
*/ */
constructor: function(unknown) { var MinderNode = kity.createClass('MinderNode', {
this.parent = null;
this.root = this; /**
this.children = []; * 创建一个游离的脑图节点
this.data = {}; *
this.tmpData = {}; * @param {String|Object} textOrData
* 节点的初始数据或文本
this.initContainers(); */
constructor: function(textOrData) {
if (Utils.isString(unknown)) {
this.setText(unknown); // 指针
} else { this.parent = null;
this.setData(unknown); this.root = this;
} this.children = [];
},
// 数据
this.data = {
id: utils.guid(),
created: +new Date()
};
// 绘图容器
this.initContainers();
if (utils.isString(textOrData)) {
this.setText(textOrData);
} else if (utils.isObject(textOrData)) {
utils.extend(this.data, textOrData);
}
},
initContainers: function() {
this.rc = new kity.Group().setId(utils.uuid('minder_node'));
this.rc.minderNode = this;
},
/**
* 判断节点是否根节点
*/
isRoot: function() {
return this.root === this;
},
/**
* 判断节点是否叶子
*/
isLeaf: function() {
return this.children.length === 0;
},
/**
* 获取节点的根节点
*/
getRoot: function() {
return this.root || this;
},
/**
* 获得节点的父节点
*/
getParent: function() {
return this.parent;
},
/**
* 获得节点的深度
*/
getLevel: function() {
var level = 0,
ancestor = this.parent;
while (ancestor) {
level++;
ancestor = ancestor.parent;
}
return level;
},
/**
* 获得节点的复杂度(即子树中节点的数量)
*/
getComplex: function() {
var complex = 0;
this.traverse(function() {
complex++;
});
return complex;
},
/**
* 获得节点的类型(root|main|sub)
*/
getType: function(type) {
this.type = ['root', 'main', 'sub'][Math.min(this.getLevel(), 2)];
return this.type;
},
/**
* 判断当前节点是否被测试节点的祖先
* @param {MinderNode} test 被测试的节点
*/
isAncestorOf: function(test) {
var ancestor = test.parent;
while (ancestor) {
if (ancestor == this) return true;
ancestor = ancestor.parent;
}
return false;
},
getData: function(key) {
return this.data[key];
},
setData: function(key, value) {
this.data[key] = value;
},
/**
* 设置节点的文本数据
* @param {String} text 文本数据
*/
setText: function(text) {
return this.data.text = text;
},
/**
* 获取节点的文本数据
* @return {String}
*/
getText: function() {
return this.data.text || '';
},
/**
* 先序遍历当前节点树
* @param {Function} fn 遍历函数
*/
preTraverse: function(fn, excludeThis) {
var children = this.getChildren();
if (!excludeThis) fn(this);
for (var i = 0; i < children.length; i++) {
children[i].preTraverse(fn);
}
},
/**
* 后序遍历当前节点树
* @param {Function} fn 遍历函数
*/
postTraverse: function(fn, excludeThis) {
var children = this.getChildren();
for (var i = 0; i < children.length; i++) {
children[i].postTraverse(fn);
}
if (!excludeThis) fn(this);
},
initContainers: function() { traverse: function(fn, excludeThis) {
this.rc = new kity.Group().setId(KityMinder.uuid('minder_node')); return this.postTraverse(fn, excludeThis);
this.rc.minderNode = this; },
},
/** getChildren: function() {
* 判断节点是否根节点 return this.children;
*/ },
isRoot: function() {
return this.root === this;
},
/**
* 判断节点是否叶子
*/
isLeaf: function() {
return this.children.length === 0;
},
/** getIndex: function() {
* 获取节点的根节点 return this.parent ? this.parent.children.indexOf(this) : -1;
*/ },
getRoot: function() {
return this.root || this;
},
/** insertChild: function(node, index) {
* 获得节点的父节点 if (index === undefined) {
*/ index = this.children.length;
getParent: function() { }
return this.parent; if (node.parent) {
}, node.parent.removeChild(node);
}
node.parent = this;
node.root = this.root;
/** this.children.splice(index, 0, node);
* 获得节点的深度 },
*/
getLevel: function() {
var level = 0,
parent = this.parent;
while (parent) {
level++;
parent = parent.parent;
}
return level;
},
/** appendChild: function(node) {
* 获得节点的复杂度(即子树中节点的数量) return this.insertChild(node);
*/ },
getComplex: function() {
var complex = 0;
this.traverse(function() {
complex++;
});
return complex;
},
/** prependChild: function(node) {
* 获得节点的类型(root|main|sub) return this.insertChild(node, 0);
*/ },
getType: function(type) {
this.type = ['root', 'main', 'sub'][Math.min(this.getLevel(), 2)];
return this.type;
},
/** removeChild: function(elem) {
* 判断当前节点是否被测试节点的祖先 var index = elem,
* @param {MinderNode} test 被测试的节点 removed;
*/ if (elem instanceof MinderNode) {
isAncestorOf: function(test) { index = this.children.indexOf(elem);
var p = test.parent; }
while (p) { if (index >= 0) {
if (p == this) return true; removed = this.children.splice(index, 1)[0];
p = p.parent; removed.parent = null;
} removed.root = removed;
return false; }
}, },
/** clearChildren: function() {
* 设置节点的文本数据 this.children = [];
* @param {String} text 文本数据 },
*/
setText: function(text) {
if(utils.isArray(text)){
text = text.join('\n');
}
return this.setData('text', text);
},
/** getChild: function(index) {
* 获取节点的文本数据 return this.children[index];
* @return {String} },
*/
getText: function(str2arr) {
var text = this.getData('text') || '';
text = text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'); getRenderContainer: function() {
return this.rc;
},
if(str2arr){ getCommonAncestor: function(node) {
text = text.split('\n'); return MinderNode.getNodeCommonAncestor(this, node);
} },
return text; contains: function(node) {
}, return this == node || this.isAncestorOf(node);
},
/** clone: function() {
* 先序遍历当前节点树 var cloned = new MinderNode();
* @param {Function} fn 遍历函数
*/
preTraverse: function(fn, excludeThis) {
var children = this.getChildren();
if (!excludeThis) fn(this);
for (var i = 0; i < children.length; i++) {
children[i].preTraverse(fn);
}
},
/** cloned.data = utils.clone(this.data);
* 后序遍历当前节点树
* @param {Function} fn 遍历函数
*/
postTraverse: function(fn, excludeThis) {
var children = this.getChildren();
for (var i = 0; i < children.length; i++) {
children[i].postTraverse(fn);
}
if (!excludeThis) fn(this);
},
traverse: function(fn, excludeThis) { this.children.forEach(function(child) {
return this.postTraverse(fn, excludeThis); cloned.appendChild(child.clone());
}, });
getChildren: function() {
return this.children;
},
getIndex: function() { return cloned;
return this.parent ? this.parent.children.indexOf(this) : -1; },
},
insertChild: function(node, index) { compareTo: function(node) {
if (index === undefined) {
index = this.children.length;
}
if (node.parent) {
node.parent.removeChild(node);
}
node.parent = this;
node.root = this.root;
this.children.splice(index, 0, node); if (!utils.comparePlainObject(this.data, node.data)) return false;
}, if (!utils.comparePlainObject(this.temp, node.temp)) return false;
if (this.children.length != node.children.length) return false;
appendChild: function(node) { var i = 0;
return this.insertChild(node); while (this.children[i]) {
}, if (!this.children[i].compareTo(node.children[i])) return false;
i++;
}
prependChild: function(node) { return true;
return this.insertChild(node, 0); },
},
removeChild: function(elem) { getMinder: function() {
var index = elem, return this.getRoot().minder;
removed;
if (elem instanceof MinderNode) {
index = this.children.indexOf(elem);
} }
if (index >= 0) { });
removed = this.children.splice(index, 1)[0];
removed.parent = null;
removed.root = removed;
}
},
getChild: function(index) {
return this.children[index];
},
getFirstChild: function() {
return this.children[0];
},
getLastChild: function() { MinderNode.getCommonAncestor = function(nodeA, nodeB) {
return this.children[this.children.length - 1]; if (nodeA instanceof Array) {
}, return MinderNode.getCommonAncestor.apply(this, nodeA);
getData: function(name) {
if (name === undefined) {
return this.data;
} }
return this.data[name]; switch (arguments.length) {
}, case 1:
return nodeA.parent || nodeA;
setData: function(name, value) {
if (name === undefined) { case 2:
this.data = {}; if (nodeA.isAncestorOf(nodeB)) {
return nodeA;
} else if (utils.isObject(name)) { }
Utils.extend(this.data, name); if (nodeB.isAncestorOf(nodeA)) {
} else { return nodeB;
if (value === undefined) { }
this.data[name] = null; var ancestor = nodeA.parent;
delete this.data[name]; while (ancestor && !ancestor.isAncestorOf(nodeB)) {
} else { ancestor = ancestor.parent;
this.data[name] = value; }
} return ancestor;
default:
return Array.prototype.reduce.call(arguments,
function(prev, current) {
return MinderNode.getCommonAncestor(prev, current);
},
nodeA
);
} }
return this; };
},
getRenderContainer: function() {
return this.rc;
},
getCommonAncestor: function(node) { kity.extendClass(Minder, {
return Utils.getNodeCommonAncestor(this, node);
},
contains: function(node) { getRoot: function() {
return this == node || this.isAncestorOf(node); return this._root;
}, },
clone: function() { setRoot: function(root) {
function cloneNode(parent, isClonedNode) { this._root = root;
var cloned = new KityMinder.MinderNode(); root.minder = this;
},
cloned.data = Utils.clonePlainObject(isClonedNode.getData()); createNode: function(textOrData, parent, index) {
cloned.tmpData = Utils.clonePlainObject(isClonedNode.getTmpData()); var node = new MinderNode(textOrData);
this.fire('nodecreate', {
if (parent) { node: node,
parent.appendChild(cloned); parent: parent,
} index: index
for (var i = 0, ci; });
(ci = isClonedNode.children[i++]);) { this.appendNode(node, parent, index);
cloneNode(cloned, ci); return node;
} },
return cloned;
} appendNode: function(node, parent, index) {
return cloneNode(null, this); if (parent) parent.insertChild(node, index);
}, this.attachNode(node);
return this;
equals: function(node,ignoreSelected) { },
var me = this;
function restoreSelected(){ removeNode: function(node) {
if(isSelectedA){ if (node.parent) {
me.setSelectedFlag(); node.parent.removeChild(node);
} this.detachNode(node);
if(isSelectedB){ this.fire('noderemove', {
node.setSelectedFlag(); node: node
} });
}
if(ignoreSelected){
var isSelectedA = false;
var isSelectedB = false;
if(me.isSelected()){
isSelectedA = true;
me.clearSelectedFlag();
}
if(node.isSelected()){
isSelectedB = true;
node.clearSelectedFlag();
}
}
if (node.children.length != this.children.length) {
restoreSelected();
return false;
}
if (utils.compareObject(node.getData(), me.getData()) === false) {
restoreSelected();
return false;
}
if (utils.compareObject(node.getTmpData(), me.getTmpData()) === false) {
restoreSelected();
return false;
}
for (var i = 0, ci;
(ci = me.children[i]); i++) {
if (ci.equals(node.children[i],ignoreSelected) === false) {
restoreSelected();
return false;
} }
} },
restoreSelected();
return true;
}, attachNode: function(node) {
var rc = this.getRenderContainer();
clearChildren: function() { node.traverse(function(current) {
this.children = []; current.attached = true;
}, rc.addShape(current.getRenderContainer());
});
rc.addShape(node.getRenderContainer());
this.fire('nodeattach', {
node: node
});
},
setTmpData: function(a, v) { detachNode: function(node) {
var me = this; var rc = this.getRenderContainer();
if (utils.isObject(a)) { node.traverse(function(current) {
utils.each(a, function(key, val) { current.attached = false;
me.setTmpData(key, val); rc.removeShape(current.getRenderContainer());
}); });
} this.fire('nodedetach', {
if (v === undefined || v === null || v === '') { node: node
delete this.tmpData[a]; });
} else { },
this.tmpData[a] = v;
}
},
getTmpData: function(a) { getMinderTitle: function() {
if (a === undefined) { return this.getRoot().getText();
return this.tmpData;
} }
return this.tmpData[a];
}, });
setValue: function(node) { module.exports = MinderNode;
this.data = {}; });
this.setData(utils.clonePlainObject(node.getData())); \ No newline at end of file
this.tmpData = {};
this.setTmpData(utils.clonePlainObject(node.getTmpData()));
return this;
}
});
MinderNode.getCommonAncestor = function(nodeA, nodeB) {
if (nodeA instanceof Array) {
return MinderNode.getCommonAncestor.apply(this, nodeA);
}
switch (arguments.length) {
case 1:
return nodeA.parent || nodeA;
case 2:
if (nodeA.isAncestorOf(nodeB)) {
return nodeA;
}
if (nodeB.isAncestorOf(nodeA)) {
return nodeB;
}
var ancestor = nodeA.parent;
while (ancestor && !ancestor.isAncestorOf(nodeB)) {
ancestor = ancestor.parent;
}
return ancestor;
default:
return Array.prototype.reduce.call(arguments, function(prev, current) {
return MinderNode.getCommonAncestor(prev, current);
}, nodeA);
}
};
kity.extendClass(KityMinder, {
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;
}
});
/**
* @fileOverview
*
* 提供脑图选项支持
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kity = require('./kity');
var Minder = require('./minder');
kity.extendClass(Minder, {
getOption: function(key) {
if (key) {
return this._options[key];
} else {
return this._options;
}
}
});
});
\ No newline at end of file
/**
* @fileOverview
*
* 提供脑图选项支持
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
kity.extendClass(KityMinder, {
getOptions: function(key) {
if (key) {
return this._options[key];
} else {
return this._options;
}
}
});
\ No newline at end of file
...@@ -6,51 +6,61 @@ ...@@ -6,51 +6,61 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerInit(function() { define(function(require, exports, module) {
this._initPaper(); var kity = require('./kity');
}); var utils = require('./utils');
kity.extendClass(KityMinder, { var Minder = require('./minder');
_initPaper: function() { Minder.registerInitHook(function() {
this._initPaper();
this._paper = new kity.Paper(); });
this._paper.getNode().setAttribute('contenteditable', true);
this._paper.getNode().ondragstart = function(e) { kity.extendClass(Minder, {
e.preventDefault();
}; _initPaper: function() {
this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
this._paper = new kity.Paper();
this._addRenderContainer(); this._paper.getNode().ondragstart = function(e) {
e.preventDefault();
this.setRoot(this.createNode()); };
this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
if (this._options.renderTo) {
this.renderTo(this._options.renderTo); this._addRenderContainer();
}
}, this.setRoot(this.createNode());
_addRenderContainer: function() { if (this._options.renderTo) {
this._rc = new kity.Group().setId(KityMinder.uuid('minder')); this.renderTo(this._options.renderTo);
this._paper.addShape(this._rc); }
}, },
renderTo: function(target) { _addRenderContainer: function() {
if (typeof(target) == 'string') { this._rc = new kity.Group().setId(utils.uuid('minder'));
target = document.getElementById(target); this._paper.addShape(this._rc);
} },
this._paper.renderTo(this._renderTarget = target);
this._bindEvents(); renderTo: function(target) {
}, if (typeof(target) == 'string') {
target = document.getElementById(target);
getRenderContainer: function() { }
return this._rc; if (target) {
}, this._paper.renderTo(this._renderTarget = target);
this._bindEvents();
getPaper: function() { this.fire('paperrender');
return this._paper; }
}, return this;
},
getRenderTarget: function() {
return this._renderTarget; getRenderContainer: function() {
}, return this._rc;
},
getPaper: function() {
return this._paper;
},
getRenderTarget: function() {
return this._renderTarget;
},
});
}); });
\ No newline at end of file
/** /**
* @fileOverview * @fileOverview
* *
* * 只读模式支持
* *
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerInit(function(options) {
if (options.readOnly) { define(function(require, exports, module) {
this.setDisabled(); var kity = require('./kity');
} var Minder = require('./minder');
});
kity.extendClass(KityMinder, { Minder.registerInitHook(function(options) {
if (options.readOnly) {
disable: function() { this.setDisabled();
var me = this; }
//禁用命令 });
me.bkqueryCommandState = me.queryCommandState;
me.bkqueryCommandValue = me.queryCommandValue; kity.extendClass(Minder, {
me.queryCommandState = function(type) {
var cmd = this._getCommand(type); disable: function() {
if (cmd && cmd.enableReadOnly) { var me = this;
return me.bkqueryCommandState.apply(me, arguments); //禁用命令
me.bkqueryCommandState = me.queryCommandState;
me.bkqueryCommandValue = me.queryCommandValue;
me.queryCommandState = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly) {
return me.bkqueryCommandState.apply(me, arguments);
}
return -1;
};
me.queryCommandValue = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly) {
return me.bkqueryCommandValue.apply(me, arguments);
}
return null;
};
this.setStatus('readonly');
me._interactChange();
},
enable: function() {
var me = this;
if (me.bkqueryCommandState) {
me.queryCommandState = me.bkqueryCommandState;
delete me.bkqueryCommandState;
} }
return -1; if (me.bkqueryCommandValue) {
}; me.queryCommandValue = me.bkqueryCommandValue;
me.queryCommandValue = function(type) { delete me.bkqueryCommandValue;
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly) {
return me.bkqueryCommandValue.apply(me, arguments);
} }
return null;
};
this.setStatus('readonly');
me._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.setStatus('normal'); this.setStatus('normal');
me._interactChange(); me._interactChange();
} }
});
}); });
\ No newline at end of file
var Renderer = KityMinder.Renderer = kity.createClass('Renderer', { define(function(require, exports, module) {
constructor: function(node) {
this.node = node;
},
create: function(node) {
throw new Error('Not implement: Renderer.create()');
},
shouldRender: function(node) {
return true;
},
watchChange: function(data) {
var changed;
if (this.watchingData === undefined) {
changed = true;
} else if (this.watchingData != data) {
changed = true;
} else {
changed = false;
}
this.watchingData = data; var kity = require('./kity');
}, var Minder = require('./minder');
var MinderNode = require('./node');
shouldDraw: function(node) { var Renderer = kity.createClass('Renderer', {
return true; constructor: function(node) {
}, this.node = node;
},
update: function(shape, node, box) { create: function(node) {
if (this.shouldDraw()) this.draw(shape, node); throw new Error('Not implement: Renderer.create()');
return this.place(shape, node, box); },
},
draw: function(shape, node) { shouldRender: function(node) {
throw new Error('Not implement: Renderer.draw()'); return true;
}, },
place: function(shape, node, box) { watchChange: function(data) {
throw new Error('Not implement: Renderer.place()'); var changed;
},
getRenderShape: function() { if (this.watchingData === undefined) {
return this._renderShape || null; changed = true;
}, } else if (this.watchingData != data) {
changed = true;
} else {
changed = false;
}
setRenderShape: function(shape) { this.watchingData = data;
this._renderShape = shape; },
}
});
kity.extendClass(KityMinder, (function() { shouldDraw: function(node) {
return true;
},
function createRendererForNode(node, registered) { update: function(shape, node, box) {
var renderers = []; if (this.shouldDraw()) this.draw(shape, node);
return this.place(shape, node, box);
},
['center', 'left', 'right', 'top', 'bottom', 'outline', 'outside'].forEach(function(section) { draw: function(shape, node) {
var before = 'before' + section; throw new Error('Not implement: Renderer.draw()');
var after = 'after' + section; },
if (registered[before]) { place: function(shape, node, box) {
renderers = renderers.concat(registered[before]); throw new Error('Not implement: Renderer.place()');
} },
if (registered[section]) {
renderers = renderers.concat(registered[section]);
}
if (registered[after]) {
renderers = renderers.concat(registered[after]);
}
});
node._renderers = renderers.map(function(Renderer) { getRenderShape: function() {
return new Renderer(node); return this._renderShape || null;
}); },
}
return { setRenderShape: function(shape) {
this._renderShape = shape;
}
});
renderNodeBatch: function(nodes) { function createMinderExtension() {
var rendererClasses = this._rendererClasses;
var lastBoxes = [];
var rendererCount = 0;
var i, j, renderer, node;
if (!nodes.length) return; function createRendererForNode(node, registered) {
var renderers = [];
for (j = 0; j < nodes.length; j++) { ['center', 'left', 'right', 'top', 'bottom', 'outline', 'outside'].forEach(function(section) {
node = nodes[j]; var before = 'before' + section;
if (!node._renderers) { var after = 'after' + section;
createRendererForNode(node, rendererClasses);
if (registered[before]) {
renderers = renderers.concat(registered[before]);
} }
node._contentBox = new kity.Box(); if (registered[section]) {
this.fire('beforerender', { renderers = renderers.concat(registered[section]);
node: node }
}); if (registered[after]) {
} renderers = renderers.concat(registered[after]);
}
});
// 所有节点渲染器数量是一致的 node._renderers = renderers.map(function(Renderer) {
rendererCount = nodes[0]._renderers.length; return new Renderer(node);
});
}
return {
renderNodeBatch: function(nodes) {
var rendererClasses = this._rendererClasses;
var lastBoxes = [];
var rendererCount = 0;
var i, j, renderer, node;
for (i = 0; i < rendererCount; i++) { if (!nodes.length) return;
// 获取延迟盒子数据
for (j = 0; j < nodes.length; j++) { for (j = 0; j < nodes.length; j++) {
if (typeof(lastBoxes[j]) == 'function') { node = nodes[j];
lastBoxes[j] = lastBoxes[j](); if (!node._renderers) {
createRendererForNode(node, rendererClasses);
} }
if (!(lastBoxes[j] instanceof kity.Box)) { node._contentBox = new kity.Box();
lastBoxes[j] = new kity.Box(lastBoxes[j]); this.fire('beforerender', {
node: node
});
}
// 所有节点渲染器数量是一致的
rendererCount = nodes[0]._renderers.length;
for (i = 0; i < rendererCount; i++) {
// 获取延迟盒子数据
for (j = 0; j < nodes.length; j++) {
if (typeof(lastBoxes[j]) == 'function') {
lastBoxes[j] = lastBoxes[j]();
}
if (!(lastBoxes[j] instanceof kity.Box)) {
lastBoxes[j] = new kity.Box(lastBoxes[j]);
}
}
for (j = 0; j < nodes.length; j++) {
node = nodes[j];
renderer = node._renderers[i];
// 合并盒子
if (lastBoxes[j]) {
node._contentBox = node._contentBox.merge(lastBoxes[j]);
}
// 判断当前上下文是否应该渲染
if (renderer.shouldRender(node)) {
// 应该渲染,但是渲染图形没创建过,需要创建
if (!renderer.getRenderShape()) {
renderer.setRenderShape(renderer.create(node));
if (renderer.bringToBack) {
node.getRenderContainer().prependShape(renderer.getRenderShape());
} else {
node.getRenderContainer().appendShape(renderer.getRenderShape());
}
}
// 强制让渲染图形显示
renderer.getRenderShape().setVisible(true);
// 更新渲染图形
lastBoxes[j] = renderer.update(renderer.getRenderShape(), node, node._contentBox);
}
// 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来
else if (renderer.getRenderShape()) {
renderer.getRenderShape().setVisible(false);
lastBoxes[j] = null;
}
} }
} }
for (j = 0; j < nodes.length; j++) { for (j = 0; j < nodes.length; j++) {
node = nodes[j]; this.fire('noderender', {
renderer = node._renderers[i]; node: nodes[j]
});
}
},
// 合并盒子 renderNode: function(node) {
if (lastBoxes[j]) { var rendererClasses = this._rendererClasses;
node._contentBox = node._contentBox.merge(lastBoxes[j]); var i, latestBox, renderer;
}
if (!node._renderers) {
createRendererForNode(node, rendererClasses);
}
this.fire('beforerender', {
node: node
});
node._contentBox = new kity.Box();
node._renderers.forEach(function(renderer) {
// 判断当前上下文是否应该渲染 // 判断当前上下文是否应该渲染
if (renderer.shouldRender(node)) { if (renderer.shouldRender(node)) {
...@@ -138,106 +194,59 @@ kity.extendClass(KityMinder, (function() { ...@@ -138,106 +194,59 @@ kity.extendClass(KityMinder, (function() {
renderer.getRenderShape().setVisible(true); renderer.getRenderShape().setVisible(true);
// 更新渲染图形 // 更新渲染图形
lastBoxes[j] = renderer.update(renderer.getRenderShape(), node, node._contentBox); latestBox = renderer.update(renderer.getRenderShape(), node, node._contentBox);
if (typeof(latestBox) == 'function') latestBox = latestBox();
// 合并渲染区域
if (latestBox) {
node._contentBox = node._contentBox.merge(latestBox);
}
} }
// 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来 // 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来
else if (renderer.getRenderShape()) { else if (renderer.getRenderShape()) {
renderer.getRenderShape().setVisible(false); renderer.getRenderShape().setVisible(false);
lastBoxes[j] = null;
} }
}
}
for (j = 0; j < nodes.length; j++) {
this.fire('noderender', {
node: nodes[j]
}); });
}
},
renderNode: function(node) {
var rendererClasses = this._rendererClasses;
var g = KityMinder.Geometry;
var i, latestBox, renderer;
if (!node._renderers) { this.fire('noderender', {
createRendererForNode(node, rendererClasses); node: node
});
} }
};
}
this.fire('beforerender', { kity.extendClass(Minder, createMinderExtension());
node: node
});
node._contentBox = new kity.Box();
node._renderers.forEach(function(renderer) {
// 判断当前上下文是否应该渲染
if (renderer.shouldRender(node)) {
// 应该渲染,但是渲染图形没创建过,需要创建
if (!renderer.getRenderShape()) {
renderer.setRenderShape(renderer.create(node));
if (renderer.bringToBack) {
node.getRenderContainer().prependShape(renderer.getRenderShape());
} else {
node.getRenderContainer().appendShape(renderer.getRenderShape());
}
}
// 强制让渲染图形显示
renderer.getRenderShape().setVisible(true);
// 更新渲染图形
latestBox = renderer.update(renderer.getRenderShape(), node, node._contentBox);
if (typeof(latestBox) == 'function') latestBox = latestBox();
// 合并渲染区域
if (latestBox) {
node._contentBox = node._contentBox.merge(latestBox);
}
}
// 如果不应该渲染,但是渲染图形创建过了,需要隐藏起来
else if (renderer.getRenderShape()) {
renderer.getRenderShape().setVisible(false);
}
});
this.fire('noderender', { kity.extendClass(MinderNode, {
node: node render: function() {
if (!this.attached) return;
this.getMinder().renderNode(this);
return this;
},
renderTree: function() {
if (!this.attached) return;
var list = [];
this.traverse(function(node) {
list.push(node);
}); });
this.getMinder().renderNodeBatch(list);
return this;
},
getRenderer: function(type) {
var rs = this._renderers;
for (var i = 0; i < rs.length; i++) {
if (rs[i].getType() == type) return rs[i];
}
return null;
},
getContentBox: function() {
//if (!this._contentBox) this.render();
return this.parent && this.parent.isCollapsed() ? new kity.Box() : (this._contentBox || new kity.Box());
} }
}; });
})());
module.exports = Renderer;
kity.extendClass(MinderNode, {
render: function() {
if (!this.attached) return;
this.getMinder().renderNode(this);
return this;
},
renderTree: function() {
if (!this.attached) return;
var list = [];
this.traverse(function(node) {
list.push(node);
});
this.getMinder().renderNodeBatch(list);
return this;
},
getRenderer: function(type) {
var rs = this._renderers;
for (var i = 0; i < rs.length; i++) {
if (rs[i].getType() == type) return rs[i];
}
return null;
},
getContentBox: function() {
//if (!this._contentBox) this.render();
return this.parent && this.parent.isCollapsed() ? new kity.Box() : (this._contentBox || new kity.Box());
}
}); });
\ No newline at end of file
KityMinder.registerInit(function() { define(function(require, exports, module) {
this._initSelection(); var kity = require('./kity');
}); var utils = require('./utils');
var Minder = require('./minder');
// 选区管理 var MinderNode = require('./node');
kity.extendClass(KityMinder, {
_initSelection: function() { Minder.registerInitHook(function() {
this._selectedNodes = []; this._initSelection();
}, });
renderChangedSelection: function(last) {
var current = this.getSelectedNodes(); // 选区管理
var changed = []; kity.extendClass(Minder, {
var i = 0; _initSelection: function() {
this._selectedNodes = [];
current.forEach(function(node) { },
if (last.indexOf(node) == -1) { renderChangedSelection: function(last) {
changed.push(node); var current = this.getSelectedNodes();
node.setTmpData('selected', true); var changed = [];
current.forEach(function(node) {
if (last.indexOf(node) == -1) {
changed.push(node);
}
});
last.forEach(function(node) {
if (current.indexOf(node) == -1) {
changed.push(node);
}
});
if (changed.length) {
this._interactChange();
this.fire('selectionchange');
} }
}); while (changed.length) {
changed.shift().render();
}
},
getSelectedNodes: function() {
//不能克隆返回,会对当前选区操作,从而影响querycommand
return this._selectedNodes;
},
getSelectedNode: function() {
return this.getSelectedNodes()[0] || null;
},
removeAllSelectedNodes: function() {
var me = this;
var last = this._selectedNodes.splice(0);
this._selectedNodes = [];
this.renderChangedSelection(last);
return this.fire('selectionclear');
},
removeSelectedNodes: function(nodes) {
var me = this;
var last = this._selectedNodes.slice(0);
nodes = utils.isArray(nodes) ? nodes : [nodes];
nodes.forEach(function(node) {
var index;
if ((index = me._selectedNodes.indexOf(node)) === -1) return;
me._selectedNodes.splice(index, 1);
});
last.forEach(function(node) { this.renderChangedSelection(last);
if (current.indexOf(node) == -1) { return this;
changed.push(node); },
node.setTmpData('selected', false); select: function(nodes, isSingleSelect) {
var lastSelect = this.getSelectedNodes().slice(0);
if (isSingleSelect) {
this._selectedNodes = [];
} }
}); var me = this;
nodes = utils.isArray(nodes) ? nodes : [nodes];
nodes.forEach(function(node) {
if (me._selectedNodes.indexOf(node) !== -1) return;
me._selectedNodes.push(node);
});
this.renderChangedSelection(lastSelect);
return this;
},
if (changed.length) { //当前选区中的节点在给定的节点范围内的保留选中状态,
this._interactChange(); //没在给定范围的取消选中,给定范围中的但没在当前选中范围的也做选中效果
this.fire('selectionchange'); toggleSelect: function(node) {
} if (utils.isArray(node)) {
while (i < changed.length) changed[i++].render(); node.forEach(this.toggleSelect.bind(this));
}, } else {
getSelectedNodes: function() { if (node.isSelected()) this.removeSelectedNodes(node);
//不能克隆返回,会对当前选区操作,从而影响querycommand else this.select(node);
return this._selectedNodes; }
}, return this;
getSelectedNode: function() { },
return this.getSelectedNodes()[0] || null;
},
removeAllSelectedNodes: function() {
var me = this;
var last = this._selectedNodes.splice(0);
this._selectedNodes = [];
this.renderChangedSelection(last);
return this.fire('selectionclear');
},
removeSelectedNodes: function(nodes) {
var me = this;
var last = this._selectedNodes.slice(0);
nodes = Utils.isArray(nodes) ? nodes : [nodes];
Utils.each(nodes, function(i, n) {
var index;
if ((index = me._selectedNodes.indexOf(n)) === -1) return;
me._selectedNodes.splice(index, 1);
});
this.renderChangedSelection(last);
return this;
},
select: function(nodes, isSingleSelect) {
var lastSelect = this.getSelectedNodes().slice(0);
if (isSingleSelect) {
this._selectedNodes = [];
}
var me = this;
nodes = Utils.isArray(nodes) ? nodes : [nodes];
Utils.each(nodes, function(i, n) {
if (me._selectedNodes.indexOf(n) !== -1) return;
me._selectedNodes.push(n);
});
this.renderChangedSelection(lastSelect);
return this;
},
//当前选区中的节点在给定的节点范围内的保留选中状态,
//没在给定范围的取消选中,给定范围中的但没在当前选中范围的也做选中效果
toggleSelect: function(node) {
if (Utils.isArray(node)) {
node.forEach(this.toggleSelect.bind(this));
} else {
if (node.isSelected()) this.removeSelectedNodes(node);
else this.select(node);
}
return this;
},
isSingleSelect: function() {
return this._selectedNodes.length == 1;
},
getSelectedAncestors: function(includeRoot) {
var nodes = this.getSelectedNodes().slice(0),
ancestors = [],
judge;
// 根节点不参与计算
var rootIndex = nodes.indexOf(this.getRoot());
if (~rootIndex && !includeRoot) {
nodes.splice(rootIndex, 1);
}
// 判断 nodes 列表中是否存在 judge 的祖先 isSingleSelect: function() {
function hasAncestor(nodes, judge) { return this._selectedNodes.length == 1;
for (var i = nodes.length - 1; i >= 0; --i) { },
if (nodes[i].isAncestorOf(judge)) return true;
getSelectedAncestors: function(includeRoot) {
var nodes = this.getSelectedNodes().slice(0),
ancestors = [],
judge;
// 根节点不参与计算
var rootIndex = nodes.indexOf(this.getRoot());
if (~rootIndex && !includeRoot) {
nodes.splice(rootIndex, 1);
} }
return false;
}
// 按照拓扑排序 // 判断 nodes 列表中是否存在 judge 的祖先
nodes.sort(function(node1, node2) { function hasAncestor(nodes, judge) {
return node1.getLevel() - node2.getLevel(); for (var i = nodes.length - 1; i >= 0; --i) {
}); if (nodes[i].isAncestorOf(judge)) return true;
}
return false;
}
// 按照拓扑排序
nodes.sort(function(node1, node2) {
return node1.getLevel() - node2.getLevel();
});
// 因为是拓扑有序的,所以只需往上查找 // 因为是拓扑有序的,所以只需往上查找
while ((judge = nodes.pop())) { while ((judge = nodes.pop())) {
if (!hasAncestor(nodes, judge)) { if (!hasAncestor(nodes, judge)) {
ancestors.push(judge); ancestors.push(judge);
}
} }
return ancestors;
}
});
kity.extendClass(MinderNode, {
isSelected: function() {
return this.getMinder().getSelectedNodes().indexOf(this) != -1;
} }
});
return ancestors;
}
});
kity.extendClass(MinderNode, {
isSelected: function() {
return this.getTmpData('selected');
},
clearSelectedFlag:function(){
this.setTmpData('selected');
},
setSelectedFlag:function(){
this.setTmpData('selected',true);
}
}); });
\ No newline at end of file
...@@ -7,23 +7,26 @@ ...@@ -7,23 +7,26 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerInit(function() { define(function(require, exports, module) {
this._initStatus(); var kity = require('./kity');
}); var Minder = require('./minder');
kity.extendClass(KityMinder, { var sf = ~window.location.href.indexOf('status');
var tf = ~window.location.href.indexOf('trace');
_initStatus: function() { Minder.registerInitHook(function() {
this._status = 'normal'; this._initStatus();
this._rollbackStatus = 'normal'; });
},
setStatus: (function() { kity.extendClass(Minder, {
var sf = ~window.location.href.indexOf('status');
var tf = ~window.location.href.indexOf('trace');
// 在 readonly 模式下,只有 force 为 true 才能切换回来 _initStatus: function() {
return function(status, force) { this._status = 'normal';
this._rollbackStatus = 'normal';
},
setStatus: function(status, force) {
// 在 readonly 模式下,只有 force 为 true 才能切换回来
if (this._status == 'readonly' && !force) return this; if (this._status == 'readonly' && !force) return this;
if (status != this._status) { if (status != this._status) {
this._rollbackStatus = this._status; this._rollbackStatus = this._status;
...@@ -33,6 +36,7 @@ kity.extendClass(KityMinder, { ...@@ -33,6 +36,7 @@ kity.extendClass(KityMinder, {
currentStatus: this._status currentStatus: this._status
}); });
if (sf) { if (sf) {
/* global console: true */
console.log(window.event.type, this._rollbackStatus, '->', this._status); console.log(window.event.type, this._rollbackStatus, '->', this._status);
if (tf) { if (tf) {
console.trace(); console.trace();
...@@ -40,16 +44,17 @@ kity.extendClass(KityMinder, { ...@@ -40,16 +44,17 @@ kity.extendClass(KityMinder, {
} }
} }
return this; return this;
}; },
})(),
rollbackStatus: function() {
rollbackStatus: function() { this.setStatus(this._rollbackStatus);
this.setStatus(this._rollbackStatus); },
}, getRollbackStatus:function(){
getRollbackStatus:function(){ return this._rollbackStatus;
return this._rollbackStatus; },
}, getStatus: function() {
getStatus: function() { return this._status;
return this._status; }
} });
}); });
\ No newline at end of file
utils.extend(KityMinder, { define(function(require, exports, module) {
_templates: {}, var kity = require('./kity');
registerTemplate: function(name, supports) { var utils = require('./utils');
KityMinder._templates[name] = supports; var Minder = require('./minder');
}, var Command = require('./command');
getTemplateList: function() { var MinderNode = require('./node');
return KityMinder._templates; var Module = require('./module');
}
});
kity.extendClass(KityMinder, (function() { var _templates = {};
var originGetTheme = KityMinder.prototype.getTheme;
return {
useTemplate: function(name, duration) {
this.setTemplate(name);
this.refresh(duration || 800);
},
getTemplate: function() { function register(name, supports) {
return this._template || 'default'; _templates[name] = supports;
}, }
exports.register = register;
setTemplate: function(name) { utils.extend(Minder, {
this._template = name || null; getTemplateList: function() {
}, return _templates;
}
});
getTemplateSupport: function(method) { kity.extendClass(Minder, (function() {
var supports = KityMinder._templates[this.getTemplate()]; var originGetTheme = Minder.prototype.getTheme;
return supports && supports[method]; return {
}, useTemplate: function(name, duration) {
this.setTemplate(name);
this.refresh(duration || 800);
},
getTheme: function(node) { getTemplate: function() {
var support = this.getTemplateSupport('getTheme') || originGetTheme; return this._template || 'default';
return support.call(this, node); },
}
};
})());
setTemplate: function(name) {
this._template = name || null;
},
kity.extendClass(MinderNode, (function() { getTemplateSupport: function(method) {
var originGetLayout = MinderNode.prototype.getLayout; var supports = _templates[this.getTemplate()];
var originGetConnect = MinderNode.prototype.getConnect; return supports && supports[method];
return { },
getLayout: function() {
var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
return support.call(this, this);
},
getConnect: function() { getTheme: function(node) {
var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect; var support = this.getTemplateSupport('getTheme') || originGetTheme;
return support.call(this, this); return support.call(this, node);
} }
}; };
})()); })());
KityMinder.registerModule('TemplateModule', {
commands: {
'template': kity.createClass('TemplateCommand', {
base: Command,
execute: function(minder, name) { kity.extendClass(MinderNode, (function() {
minder.useTemplate(name); var originGetLayout = MinderNode.prototype.getLayout;
minder.execCommand('camera'); var originGetConnect = MinderNode.prototype.getConnect;
return {
getLayout: function() {
var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
return support.call(this, this);
}, },
queryValue: function(minder) { getConnect: function() {
return minder.getTemplate() || 'default'; var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
return support.call(this, this);
} }
}) };
} })());
Module.register('TemplateModule', {
commands: {
'template': kity.createClass('TemplateCommand', {
base: Command,
execute: function(minder, name) {
minder.useTemplate(name);
minder.execCommand('camera');
},
queryValue: function(minder) {
return minder.getTemplate() || 'default';
}
})
}
});
}); });
\ No newline at end of file
var cssLikeValueMatcher = { define(function(require, exports, module) {
left: function(value) { var kity = require('./kity');
return 3 in value && value[3] || var utils = require('./utils');
1 in value && value[1] || var Minder = require('./minder');
value[0]; var MinderNode = require('./node');
}, var Module = require('./module');
right: function(value) { var Command = require('./command');
return 1 in value && value[1] || value[0];
}, var cssLikeValueMatcher = {
top: function(value) { left: function(value) {
return value[0]; return 3 in value && value[3] ||
}, 1 in value && value[1] ||
bottom: function(value) { value[0];
return 2 in value && value[2] || value[0]; },
} right: function(value) {
}; return 1 in value && value[1] || value[0];
},
top: function(value) {
return value[0];
},
bottom: function(value) {
return 2 in value && value[2] || value[0];
}
};
Utils.extend(KityMinder, { var _themes = {};
_themes: {},
/** /**
* 注册一个主题 * 注册一个主题
...@@ -25,121 +32,125 @@ Utils.extend(KityMinder, { ...@@ -25,121 +32,125 @@ Utils.extend(KityMinder, {
* @param {Plain} theme 主题的样式描述 * @param {Plain} theme 主题的样式描述
* *
* @example * @example
* KityMinder.registerTheme('default', { * Minder.registerTheme('default', {
* 'root-color': 'red', * 'root-color': 'red',
* 'root-stroke': 'none', * 'root-stroke': 'none',
* 'root-padding': [10, 20] * 'root-padding': [10, 20]
* }); * });
*/ */
registerTheme: function(name, theme) { function register(name, theme) {
KityMinder._themes[name] = theme; _themes[name] = theme;
},
getThemeList: function() {
return KityMinder._themes;
} }
}); exports.register = register;
kity.extendClass(KityMinder, {
/**
* 切换脑图实例上的主题
* @param {String} name 要使用的主题的名称
*/
useTheme: function(name) {
this.setTheme(name);
this.refresh(800);
return true;
},
setTheme: function(name) {
this._theme = name || null;
this.getRenderTarget().style.background = this.getStyle('background');
this.fire('themechange', {
theme: name
});
},
/**
* 获取脑图实例上的当前主题
* @return {[type]} [description]
*/
getTheme: function(node) {
return this._theme || this.getOptions('defaultTheme') || 'fresh-blue';
},
getThemeItems: function(node) {
var theme = this.getTheme(node);
return KityMinder._themes[this.getTheme(node)];
},
/**
* 获得脑图实例上的样式
* @param {String} item 样式名称
*/
getStyle: function(item, node) {
var items = this.getThemeItems(node);
var segment, dir, selector, value, matcher;
if (item in items) return items[item]; utils.extend(Minder, {
getThemeList: function() {
// 尝试匹配 CSS 数组形式的值 return _themes;
// 比如 item 为 'pading-left' }
// theme 里有 {'padding': [10, 20]} 的定义,则可以返回 20 });
segment = item.split('-');
if (segment.length < 2) return null; kity.extendClass(Minder, {
/**
* 切换脑图实例上的主题
* @param {String} name 要使用的主题的名称
*/
useTheme: function(name) {
this.setTheme(name);
this.refresh(800);
return true;
},
setTheme: function(name) {
this._theme = name || null;
this.getRenderTarget().style.background = this.getStyle('background');
this.fire('themechange', {
theme: name
});
},
/**
* 获取脑图实例上的当前主题
* @return {[type]} [description]
*/
getTheme: function(node) {
return this._theme || this.getOption('defaultTheme') || 'fresh-blue';
},
getThemeItems: function(node) {
var theme = this.getTheme(node);
return _themes[this.getTheme(node)];
},
/**
* 获得脑图实例上的样式
* @param {String} item 样式名称
*/
getStyle: function(item, node) {
var items = this.getThemeItems(node);
var segment, dir, selector, value, matcher;
if (item in items) return items[item];
// 尝试匹配 CSS 数组形式的值
// 比如 item 为 'pading-left'
// theme 里有 {'padding': [10, 20]} 的定义,则可以返回 20
segment = item.split('-');
if (segment.length < 2) return null;
dir = segment.pop();
item = segment.join('-');
if (item in items) {
value = items[item];
if (utils.isArray(value) && (matcher = cssLikeValueMatcher[dir])) {
return matcher(value);
}
if (!isNaN(value)) return value;
}
dir = segment.pop(); return null;
item = segment.join('-'); },
if (item in items) { /**
value = items[item]; * 获取指定节点的样式
if (Utils.isArray(value) && (matcher = cssLikeValueMatcher[dir])) { * @param {String} name 样式名称,可以不加节点类型的前缀
return matcher(value); */
} getNodeStyle: function(node, name) {
if (!isNaN(value)) return value; var value = this.getStyle(node.getType() + '-' + name, node);
return value !== null ? value : this.getStyle(name, node);
} }
});
return null; kity.extendClass(MinderNode, {
}, getStyle: function(name) {
return this.getMinder().getNodeStyle(this, name);
/** }
* 获取指定节点的样式 });
* @param {String} name 样式名称,可以不加节点类型的前缀
*/ Module.register('Theme', {
getNodeStyle: function(node, name) { defaultOptions: {
var value = this.getStyle(node.getType() + '-' + name, node); defaultTheme: 'fresh-blue'
return value !== null ? value : this.getStyle(name, node); },
} commands: {
}); 'theme': kity.createClass('ThemeCommand', {
base: Command,
execute: function(km, name) {
return km.useTheme(name);
},
queryValue: function(km) {
return km.getTheme() || 'default';
}
})
}
});
kity.extendClass(MinderNode, { Minder.registerInitHook(function() {
getStyle: function(name) { this.setTheme();
return this.getMinder().getNodeStyle(this, name); });
}
});
KityMinder.registerModule('Theme', {
defaultOptions: {
defaultTheme: 'fresh-blue'
},
commands: {
'theme': kity.createClass('ThemeCommand', {
base: Command,
execute: function(km, name) {
return km.useTheme(name);
},
queryValue: function(km) {
return km.getTheme() || 'default';
}
})
}
});
KityMinder.registerInit(function() {
this.setTheme();
}); });
\ No newline at end of file
var utils = Utils = KityMinder.Utils = { define(function(require, exports) {
extend: kity.Utils.extend.bind(kity.Utils), var kity = require('../../lib/kity/src/kity.js');
var uuidMap = {};
listen: function(element, type, handler) { exports.extend = kity.Utils.extend.bind(kity.Utils);
var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/), exports.each = kity.Utils.each.bind(kity.Utils);
k = types.length;
if (k)
while (k--) {
type = types[k];
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
if (!handler._d) {
handler._d = {
els: []
};
}
var key = type + handler.toString(),
index = utils.indexOf(handler._d.els, element);
if (!handler._d[key] || index == -1) {
if (index == -1) {
handler._d.els.push(element);
}
if (!handler._d[key]) {
handler._d[key] = function(evt) {
return handler.call(evt.srcElement, evt || window.event);
};
}
element.attachEvent('on' + type, handler._d[key]);
}
}
}
element = null;
},
trim: function(str) {
return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
},
each: function(obj, iterator, context) {
if (obj == null) return;
if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, i, obj[i], obj) === false)
return false;
}
} else {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (iterator.call(context, key, obj[key], obj) === false)
return false;
}
}
}
},
addCssRule: function(key, style, doc) {
var head, node;
if (style === undefined || style && style.nodeType && style.nodeType == 9) {
//获取样式
doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
node = doc.getElementById(key);
return node ? node.innerHTML : undefined;
}
doc = doc || document;
node = doc.getElementById(key);
//清除样式 exports.uuid = function(group) {
if (style === '') { return uuidMap[group] = uuidMap[group] ? uuidMap[group] + 1 : 1;
if (node) { };
node.parentNode.removeChild(node);
return true
}
return false;
}
//添加样式 exports.guid = function() {
if (node) { return (+new Date() * 1e6 + Math.floor(Math.random() * 1e6)).toString(36);
node.innerHTML = style; };
} else {
node = doc.createElement('style'); exports.trim = function(str) {
node.id = key; return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
node.innerHTML = style; };
doc.getElementsByTagName('head')[0].appendChild(node);
} exports.keys = function(plain) {
},
keys: function(plain) {
var keys = []; var keys = [];
for (var key in plain) { for (var key in plain) {
if (plain.hasOwnProperty(key)) { if (plain.hasOwnProperty(key)) {
...@@ -89,172 +25,17 @@ var utils = Utils = KityMinder.Utils = { ...@@ -89,172 +25,17 @@ var utils = Utils = KityMinder.Utils = {
} }
} }
return keys; return keys;
}, };
proxy: function(fn, context) {
return function() {
return fn.apply(context, arguments);
};
},
indexOf: function(array, item, start) {
var index = -1;
start = this.isNumber(start) ? start : 0;
this.each(array, function(v, i) {
if (i >= start && v === item) {
index = i;
return false;
}
});
return index;
},
argsToArray: function(args, index) {
return Array.prototype.slice.call(args, index || 0);
},
clonePlainObject: function(source, target) {
var tmp;
target = target || {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
tmp = source[i];
if (utils.isObject(tmp) || utils.isArray(tmp)) {
target[i] = utils.isArray(tmp) ? [] : {};
utils.clonePlainObject(source[i], target[i])
} else {
target[i] = tmp;
}
}
}
return target;
},
compareObject: function(source, target) {
var tmp;
if (this.isEmptyObject(source) !== this.isEmptyObject(target)) {
return false
}
if (this.getObjectLength(source) != this.getObjectLength(target)) {
return false;
}
for (var p in source) {
if (source.hasOwnProperty(p)) {
tmp = source[p];
if (target[p] === undefined) {
return false;
}
if (this.isObject(tmp) || this.isArray(tmp)) {
if (this.isObject(target[p]) !== this.isObject(tmp)) {
return false;
}
if (this.isArray(tmp) !== this.isArray(target[p])) {
return false;
}
if (this.compareObject(tmp, target[p]) === false) {
return false
}
} else {
if (tmp != target[p]) {
return false
}
}
}
}
return true;
},
getObjectLength: function(obj) {
if (this.isArray(obj) || this.isString(obj)) return obj.length;
var count = 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) count++;
return count;
},
isEmptyObject: function(obj) {
if (obj == null) return true;
if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) return false;
return true;
},
loadFile: function() {
var tmpList = [];
function getItem(doc, obj) { exports.clone = function(source) {
try { return JSON.parse(JSON.stringify(source));
for (var i = 0, ci; ci = tmpList[i++];) { };
if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
return ci;
}
}
} catch (e) {
return null;
}
} exports.comparePlainObject = function(a, b) {
return JSON.stringify(a) == JSON.stringify(b);
};
return function(doc, obj, fn) { exports.encodeHtml = function(str, reg) {
var item = getItem(doc, obj);
if (item) {
if (item.ready) {
fn && fn();
} else {
item.funs.push(fn)
}
return;
}
tmpList.push({
doc: doc,
url: obj.src || obj.href,
funs: [fn]
});
if (!doc.body) {
var html = [];
for (var p in obj) {
if (p == 'tag') continue;
html.push(p + '="' + obj[p] + '"')
}
doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
return;
}
if (obj.id && doc.getElementById(obj.id)) {
return;
}
var element = doc.createElement(obj.tag);
delete obj.tag;
for (var p in obj) {
element.setAttribute(p, obj[p]);
}
element.onload = element.onreadystatechange = function() {
if (!this.readyState || /loaded|complete/.test(this.readyState)) {
item = getItem(doc, obj);
if (item.funs.length > 0) {
item.ready = 1;
for (var fi; fi = item.funs.pop();) {
fi();
}
}
element.onload = element.onreadystatechange = null;
}
};
// element.onerror = function () {
// throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file ')
// };
doc.getElementsByTagName("head")[0].appendChild(element);
}
}(),
clone: function(source, target) {
var tmp;
target = target || {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
tmp = source[i];
if (typeof tmp == 'object') {
target[i] = utils.isArray(tmp) ? [] : {};
utils.clone(source[i], target[i])
} else {
target[i] = tmp;
}
}
}
return target;
},
unhtml: function(str, reg) {
return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function(a, b) { return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function(a, b) {
if (b) { if (b) {
return a; return a;
...@@ -264,64 +45,20 @@ var utils = Utils = KityMinder.Utils = { ...@@ -264,64 +45,20 @@ var utils = Utils = KityMinder.Utils = {
'&': '&amp;', '&': '&amp;',
'"': '&quot;', '"': '&quot;',
'>': '&gt;', '>': '&gt;',
"'": '&#39;' '\'': '&#39;'
}[a] }[a];
} }
}) : ''; }) : '';
}, };
cloneArr:function(arr){
return [].concat(arr);
},
clearWhitespace:function(str){
return str.replace(/[\u200b\t\r\n]/g, '');
},
getValueByIndex:function(data,index){
var initIndex = 0,result = 0; exports.clearWhiteSpace = function(str) {
return str.replace(/[\u200b\t\r\n]/g, '');
utils.each(data,function(i,arr){ };
if(initIndex + arr.length >= index){
if(index - initIndex == arr.length){
if(arr.length == 1 && arr[0].width === 0){
initIndex++;
return;
}
result = {
x: arr[arr.length - 1].x + arr[arr.length - 1].width,
y: arr[arr.length - 1].y
};
}else{
result = arr[index - initIndex];
}
return false;
}else{
initIndex += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
}
});
return result;
},
getNodeIndex:function (node, ignoreTextNode) {
var preNode = node,
i = 0;
while (preNode = preNode.previousSibling) {
if (ignoreTextNode && preNode.nodeType == 3) {
if(preNode.nodeType != preNode.nextSibling.nodeType ){
i++;
}
continue;
}
i++;
}
return i;
}
};
Utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function(i, v) { exports.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function(v) {
KityMinder.Utils['is' + v] = function(obj) { var toString = Object.prototype.toString;
return Object.prototype.toString.apply(obj) == '[object ' + v + ']'; exports['is' + v] = function(obj) {
} return toString.apply(obj) == '[object ' + v + ']';
}); };
\ No newline at end of file });
});
/**
* @fileOverview
*
* 默认导出(全部模块)
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kityminder = {
version: require('core/minder').version
};
// 核心导出,大写的部分导出类,小写的部分简单 require 一下
require('core/kity');
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.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');
// 模块依赖
require('module/arrange');
require('module/basestyle');
require('module/clipboard');
require('module/dragtree');
require('module/expand');
require('module/font');
require('module/history');
require('module/hyperlink');
require('module/image');
require('module/keynav');
require('module/layout');
require('module/node');
require('module/note');
require('module/outline');
require('module/priority');
require('module/progress');
require('module/resource');
require('module/select');
require('module/style');
require('module/text');
require('module/view');
require('module/zoom');
require('layout/mind');
require('layout/btree');
require('layout/filetree');
require('layout/fish-bone-master');
require('layout/fish-bone-slave');
require('theme/default');
require('theme/snow');
require('theme/fresh');
require('theme/fish');
require('theme/snow');
require('connect/arc');
require('connect/bezier');
require('connect/fish-bone-master');
require('connect/l');
require('connect/poly');
require('connect/under');
require('template/default');
require('template/structure');
require('template/filetree');
require('template/right');
require('template/fish-bone');
module.exports = kityminder;
});
\ No newline at end of file
/* global Layout:true */ define(function(require, exports, module) {
var kity = require('core/kity');
var layouts = ['left', 'right', 'top', 'bottom']; var Layout = require('core/layout');
layouts.forEach(function(name) { ['left', 'right', 'top', 'bottom'].forEach(registerLayoutForDirection);
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({ function registerLayoutForDirection(name) {
base: Layout, var axis = (name == 'left' || name == 'right') ? 'x' : 'y';
var dir = (name == 'left' || name == 'top') ? -1 : 1;
doLayout: function(parent, children) { var oppsite = {
'left': 'right',
'right': 'left',
'top': 'bottom',
'bottom': 'top',
'x': 'y',
'y': 'x'
};
var pbox = parent.getContentBox(); function getOrderHint(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = 5;
if (axis == 'x') { if (axis == 'x') {
parent.setVertexOut(new kity.Point(pbox[name], pbox.cy)); hint.push({
parent.setLayoutVectorOut(new kity.Vector(dir, 0)); 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 { } else {
parent.setVertexOut(new kity.Point(pbox.cx, pbox[name])); hint.push({
parent.setLayoutVectorOut(new kity.Vector(0, dir)); 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;
}
if (!children.length) { Layout.register(name, kity.createClass({
return false;
}
children.forEach(function(child) { base: Layout,
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix()); doLayout: function(parent, children) {
var pbox = parent.getContentBox();
if (axis == 'x') { if (axis == 'x') {
child.setVertexIn(new kity.Point(cbox[oppsite[name]], cbox.cy)); parent.setVertexOut(new kity.Point(pbox[name], pbox.cy));
child.setLayoutVectorIn(new kity.Vector(dir, 0)); parent.setLayoutVectorOut(new kity.Vector(dir, 0));
} else { } else {
child.setVertexIn(new kity.Point(cbox.cx, cbox[oppsite[name]])); parent.setVertexOut(new kity.Point(pbox.cx, pbox[name]));
child.setLayoutVectorIn(new kity.Vector(0, dir)); parent.setLayoutVectorOut(new kity.Vector(0, dir));
} }
});
this.align(children, oppsite[name]); if (!children.length) {
this.stack(children, oppsite[axis]); return false;
}
var bbox = this.getBranchBox(children); children.forEach(function(child) {
var xAdjust, yAdjust; var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
if (axis == 'x') { if (axis == 'x') {
xAdjust = pbox[name]; child.setVertexIn(new kity.Point(cbox[oppsite[name]], cbox.cy));
xAdjust += dir * parent.getStyle('margin-' + name); child.setLayoutVectorIn(new kity.Vector(dir, 0));
xAdjust += dir * children[0].getStyle('margin-' + oppsite[name]); } else {
child.setVertexIn(new kity.Point(cbox.cx, cbox[oppsite[name]]));
yAdjust = pbox.bottom; child.setLayoutVectorIn(new kity.Vector(0, dir));
yAdjust -= pbox.height / 2; }
yAdjust -= bbox.height / 2; });
yAdjust -= bbox.y;
} else { this.align(children, oppsite[name]);
xAdjust = pbox.right; this.stack(children, oppsite[axis]);
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); var bbox = this.getBranchBox(children);
}, var xAdjust, yAdjust;
getOrderHint: getOrderHint 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
/* global Layout:true */ define(function(require, exports, module) {
var kity = require('core/kity');
[-1, 1].forEach(function (dir) { var Layout = require('core/layout');
var name = 'filetree-' + (dir > 0 ? 'down' : 'up');
[-1, 1].forEach(registerLayoutForDir);
KityMinder.registerLayout(name, kity.createClass({
base: Layout, function registerLayoutForDir(dir) {
var name = 'filetree-' + (dir > 0 ? 'down' : 'up');
doLayout: function(parent, children, round) {
var pBox = parent.getContentBox(); Layout.register(name, kity.createClass({
var indent = 20; base: Layout,
parent.setVertexOut(new kity.Point(pBox.left + indent, dir > 0 ? pBox.bottom : pBox.top)); doLayout: function(parent, children, round) {
parent.setLayoutVectorOut(new kity.Vector(0, dir)); var pBox = parent.getContentBox();
var indent = 20;
if (!children.length) return;
parent.setVertexOut(new kity.Point(pBox.left + indent, dir > 0 ? pBox.bottom : pBox.top));
children.forEach(function(child) { parent.setLayoutVectorOut(new kity.Vector(0, dir));
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix()); if (!children.length) return;
child.setVertexIn(new kity.Point(cbox.left, cbox.cy)); children.forEach(function(child) {
child.setLayoutVectorIn(new kity.Vector(1, 0)); var cbox = child.getContentBox();
}); child.setLayoutTransform(new kity.Matrix());
this.align(children, 'left'); child.setVertexIn(new kity.Point(cbox.left, cbox.cy));
this.stack(children, 'y'); child.setLayoutVectorIn(new kity.Vector(1, 0));
});
var xAdjust = 0;
xAdjust += pBox.left; this.align(children, 'left');
xAdjust += indent; this.stack(children, 'y');
xAdjust += children[0].getStyle('margin-left');
var xAdjust = 0;
var yAdjust = 0; xAdjust += pBox.left;
xAdjust += indent;
if (dir > 0) { xAdjust += children[0].getStyle('margin-left');
yAdjust += pBox.bottom;
yAdjust += parent.getStyle('margin-bottom'); var yAdjust = 0;
yAdjust += children[0].getStyle('margin-top');
} else { if (dir > 0) {
yAdjust -= this.getTreeBox(children).bottom; yAdjust += pBox.bottom;
yAdjust += pBox.top; yAdjust += parent.getStyle('margin-bottom');
yAdjust -= parent.getStyle('margin-top'); yAdjust += children[0].getStyle('margin-top');
yAdjust -= children[0].getStyle('margin-bottom'); } else {
yAdjust -= this.getTreeBox(children).bottom;
yAdjust += pBox.top;
yAdjust -= parent.getStyle('margin-top');
yAdjust -= children[0].getStyle('margin-bottom');
}
this.move(children, xAdjust, yAdjust);
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = node.getLevel() > 1 ? 3 : 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;
} }
}));
this.move(children, xAdjust, yAdjust); }
},
getOrderHint: function(node) {
var hint = [];
var box = node.getLayoutBox();
var offset = node.getLevel() > 1 ? 3 : 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
...@@ -6,68 +6,63 @@ ...@@ -6,68 +6,63 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
/* global Layout:true */
KityMinder.registerLayout('fish-bone-master', kity.createClass('FishBoneMasterLayout', {
base: Layout,
doLayout: function(parent, children, round) { define(function(require, exports, module) {
var kity = require('core/kity');
var Layout = require('core/layout');
var upPart = [], Layout.register('fish-bone-master', kity.createClass('FishBoneMasterLayout', {
downPart = []; base: Layout,
var child = children[0]; doLayout: function(parent, children, round) {
var pBox = parent.getContentBox();
parent.setVertexOut(new kity.Point(pBox.right, pBox.cy)); var upPart = [],
parent.setLayoutVectorOut(new kity.Vector(1, 0)); downPart = [];
if (!child) return; var child = children[0];
var pBox = parent.getContentBox();
var cBox = child.getContentBox(); parent.setVertexOut(new kity.Point(pBox.right, pBox.cy));
var pMarginRight = parent.getStyle('margin-right'); parent.setLayoutVectorOut(new kity.Vector(1, 0));
var cMarginLeft = child.getStyle('margin-left');
var cMarginTop = child.getStyle('margin-top'); if (!child) return;
var cMarginBottom = child.getStyle('margin-bottom');
children.forEach(function(child, index) {
child.setLayoutTransform(new kity.Matrix());
var cBox = child.getContentBox(); var cBox = child.getContentBox();
var pMarginRight = parent.getStyle('margin-right');
var cMarginLeft = child.getStyle('margin-left');
var cMarginTop = child.getStyle('margin-top');
var cMarginBottom = child.getStyle('margin-bottom');
children.forEach(function(child, index) {
child.setLayoutTransform(new kity.Matrix());
var cBox = child.getContentBox();
if (index % 2) {
downPart.push(child);
child.setVertexIn(new kity.Point(cBox.left, cBox.top));
child.setLayoutVectorIn(new kity.Vector(1, 1));
}
else {
upPart.push(child);
child.setVertexIn(new kity.Point(cBox.left, cBox.bottom));
child.setLayoutVectorIn(new kity.Vector(1, -1));
}
});
this.stack(upPart, 'x');
this.stack(downPart, 'x');
this.align(upPart, 'bottom');
this.align(downPart, 'top');
var xAdjust = pBox.right + pMarginRight + cMarginLeft;
var yAdjustUp = pBox.cy - cMarginBottom - parent.getStyle('margin-top');
var yAdjustDown = pBox.cy + cMarginTop + parent.getStyle('margin-bottom');
this.move(upPart, xAdjust, yAdjustUp);
this.move(downPart, xAdjust + cMarginLeft, yAdjustDown);
}
}));
if (index % 2) { });
downPart.push(child); \ No newline at end of file
child.setVertexIn(new kity.Point(cBox.left, cBox.top));
child.setLayoutVectorIn(new kity.Vector(1, 1));
}
else {
upPart.push(child);
child.setVertexIn(new kity.Point(cBox.left, cBox.bottom));
child.setLayoutVectorIn(new kity.Vector(1, -1));
}
});
this.stack(upPart, 'x');
this.stack(downPart, 'x');
this.align(upPart, 'bottom');
this.align(downPart, 'top');
var xAdjust = pBox.right + pMarginRight + cMarginLeft;
var yAdjustUp = pBox.cy - cMarginBottom - parent.getStyle('margin-top');
var yAdjustDown = pBox.cy + cMarginTop + parent.getStyle('margin-bottom');
this.move(upPart, xAdjust, yAdjustUp);
this.move(downPart, xAdjust + cMarginLeft, yAdjustDown);
// children.forEach(function(child, index) {
// var matrix = child.getLayoutTransform();
// var dx, dy;
// dx = matrix.getMatrix().e;
// dy = matrix.getMatrix().f;
// matrix.translate(-dx, -dy);
// matrix.rotate(index % 2 ? 45 : -45);
// matrix.translate(dx, dy);
// });
}
}));
\ No newline at end of file
...@@ -7,62 +7,66 @@ ...@@ -7,62 +7,66 @@
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
/* global Layout: true */ define(function(require, exports, module) {
KityMinder.registerLayout('fish-bone-slave', kity.createClass('FishBoneSlaveLayout', { var kity = require('core/kity');
base: Layout, var Layout = require('core/layout');
doLayout: function (parent, children, round) { Layout.register('fish-bone-slave', kity.createClass('FishBoneSlaveLayout', {
base: Layout,
var layout = this; doLayout: function (parent, children, round) {
var abs = Math.abs;
var GOLD_CUT = 1 - 0.618;
var pBox = parent.getContentBox(); var layout = this;
var vi = parent.getLayoutVectorIn(); var abs = Math.abs;
var GOLD_CUT = 1 - 0.618;
parent.setLayoutVectorOut(vi); var pBox = parent.getContentBox();
var vi = parent.getLayoutVectorIn();
var goldX = pBox.left + pBox.width * GOLD_CUT; parent.setLayoutVectorOut(vi);
var pout = new kity.Point(goldX, vi.y > 0 ? pBox.bottom : pBox.top);
parent.setVertexOut(pout);
var child = children[0]; var goldX = pBox.left + pBox.width * GOLD_CUT;
if (!child) return; var pout = new kity.Point(goldX, vi.y > 0 ? pBox.bottom : pBox.top);
parent.setVertexOut(pout);
var cBox = child.getContentBox(); var child = children[0];
if (!child) return;
children.forEach(function(child, index) { var cBox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
child.setLayoutVectorIn(new kity.Vector(1, 0));
child.setVertexIn(new kity.Point(cBox.left, cBox.cy));
});
this.stack(children, 'y'); children.forEach(function(child, index) {
this.align(children, 'left'); child.setLayoutTransform(new kity.Matrix());
var xAdjust = 0, yAdjust = 0; child.setLayoutVectorIn(new kity.Vector(1, 0));
child.setVertexIn(new kity.Point(cBox.left, cBox.cy));
xAdjust += pout.x; });
if (parent.getLayoutVectorOut().y < 0) { this.stack(children, 'y');
yAdjust -= this.getTreeBox(children).bottom; this.align(children, 'left');
yAdjust += parent.getContentBox().top;
yAdjust -= parent.getStyle('margin-top');
yAdjust -= child.getStyle('margin-bottom');
} else {
yAdjust += parent.getContentBox().bottom;
yAdjust += parent.getStyle('margin-bottom');
yAdjust += child.getStyle('margin-top');
}
this.move(children, xAdjust, yAdjust); var xAdjust = 0, yAdjust = 0;
xAdjust += pout.x;
if (round == 2) { if (parent.getLayoutVectorOut().y < 0) {
children.forEach(function(child) { yAdjust -= this.getTreeBox(children).bottom;
var m = child.getLayoutTransform(); yAdjust += parent.getContentBox().top;
var cbox = child.getContentBox(); yAdjust -= parent.getStyle('margin-top');
var pin = m.transformPoint(new kity.Point(cbox.left, 0)); yAdjust -= child.getStyle('margin-bottom');
layout.move([child], abs(pin.y - pout.y), 0); } else {
}); yAdjust += parent.getContentBox().bottom;
yAdjust += parent.getStyle('margin-bottom');
yAdjust += child.getStyle('margin-top');
}
this.move(children, xAdjust, yAdjust);
if (round == 2) {
children.forEach(function(child) {
var m = child.getLayoutTransform();
var cbox = child.getContentBox();
var pin = m.transformPoint(new kity.Point(cbox.left, 0));
layout.move([child], abs(pin.y - pout.y), 0);
});
}
} }
} }));
})); });
\ No newline at end of file \ No newline at end of file
/* global Layout:true */ define(function(require, exports, module) {
KityMinder.registerLayout('mind', kity.createClass({ var kity = require('core/kity');
base: Layout, var Layout = require('core/layout');
var Minder = require('core/minder');
doLayout: function(node, children) {
var layout = this; Layout.register('mind', kity.createClass({
var half = Math.ceil(node.children.length / 2); base: Layout,
var right = [];
var left = []; doLayout: function(node, children) {
var layout = this;
children.forEach(function(child) { var half = Math.ceil(node.children.length / 2);
if (child.getIndex() < half) right.push(child); var right = [];
else left.push(child); var left = [];
});
children.forEach(function(child) {
var leftLayout = KityMinder.getLayoutInstance('left'); if (child.getIndex() < half) right.push(child);
var rightLayout = KityMinder.getLayoutInstance('right'); else left.push(child);
});
leftLayout.doLayout(node, left);
rightLayout.doLayout(node, right); var leftLayout = Minder.getLayoutInstance('left');
var rightLayout = Minder.getLayoutInstance('right');
var box = node.getContentBox();
node.setVertexOut(new kity.Point(box.cx, box.cy)); leftLayout.doLayout(node, left);
node.setLayoutVectorOut(new kity.Vector(0, 0)); rightLayout.doLayout(node, right);
},
var box = node.getContentBox();
getOrderHint: function(node) { node.setVertexOut(new kity.Point(box.cx, box.cy));
var hint = []; node.setLayoutVectorOut(new kity.Vector(0, 0));
var box = node.getLayoutBox(); },
var offset = 5;
getOrderHint: function(node) {
hint.push({ var hint = [];
type: 'up', var box = node.getLayoutBox();
node: node, var offset = 5;
area: {
x: box.x, hint.push({
y: box.top - node.getStyle('margin-top') - offset, type: 'up',
width: box.width, node: node,
height: node.getStyle('margin-top') area: {
}, x: box.x,
path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset] y: box.top - node.getStyle('margin-top') - offset,
}); width: box.width,
height: node.getStyle('margin-top')
hint.push({ },
type: 'down', path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
node: node, });
area: {
x: box.x, hint.push({
y: box.bottom + offset, type: 'down',
width: box.width, node: node,
height: node.getStyle('margin-bottom') area: {
}, x: box.x,
path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset] y: box.bottom + offset,
}); width: box.width,
return hint; height: node.getStyle('margin-bottom')
} },
})); path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
\ No newline at end of file });
return hint;
}
}));
});
\ No newline at end of file
kity.extendClass(MinderNode, {
arrange: function(index) { define(function(require, exports, module) {
var parent = this.parent; var kity = require('core/kity');
if (!parent) return; var MinderNode = require('core/node');
var sibling = parent.children; var Command = require('core/command');
var Module = require('core/module');
if (index < 0 || index >= sibling.length) return;
sibling.splice(this.getIndex(), 1); kity.extendClass(MinderNode, {
sibling.splice(index, 0, this); arrange: function(index) {
return this; var parent = this.parent;
} if (!parent) return;
}); var sibling = parent.children;
function asc(nodeA, nodeB) { if (index < 0 || index >= sibling.length) return;
return nodeA.getIndex() - nodeB.getIndex(); sibling.splice(this.getIndex(), 1);
} sibling.splice(index, 0, this);
function desc(nodeA, nodeB) { return this;
return -asc(nodeA, nodeB); }
} });
function canArrange(km) { function asc(nodeA, nodeB) {
var selected = km.getSelectedNode(); return nodeA.getIndex() - nodeB.getIndex();
return selected && selected.parent && selected.parent.children.length > 1;
}
var ArrangeUpCommand = kity.createClass('ArrangeUpCommand', {
base: Command,
execute: function(km) {
var nodes = km.getSelectedNodes();
nodes.sort(asc);
var lastIndexes = nodes.map(function(node) {
return node.getIndex();
});
nodes.forEach(function(node, index) {
node.arrange(lastIndexes[index] - 1);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode();
return selected ? 0 : -1;
} }
}); function desc(nodeA, nodeB) {
return -asc(nodeA, nodeB);
var ArrangeDownCommand = kity.createClass('ArrangeUpCommand', {
base: Command,
execute: function(km) {
var nodes = km.getSelectedNodes();
nodes.sort(desc);
var lastIndexes = nodes.map(function(node) {
return node.getIndex();
});
nodes.forEach(function(node, index) {
node.arrange(lastIndexes[index] + 1);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode();
return selected ? 0 : -1;
} }
});
var ArrangeCommand = kity.createClass('ArrangeCommand', {
base: Command,
execute: function(km, nodes, index) {
nodes = nodes && nodes.slice() || km.getSelectedNodes().slice();
if (!nodes.length) return;
var ancestor = MinderNode.getCommonAncestor(nodes);
if (ancestor != nodes[0].parent) return; function canArrange(km) {
var indexed = nodes.map(function(node) {
return {
index: node.getIndex(),
node: node
};
});
var asc = Math.min.apply(Math, indexed.map(function(one) { return one.index; })) >= index;
indexed.sort(function(a, b) {
return asc ? (b.index - a.index) : (a.index - b.index);
});
indexed.forEach(function(one) {
one.node.arrange(index);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode(); var selected = km.getSelectedNode();
return selected ? 0 : -1; return selected && selected.parent && selected.parent.children.length > 1;
}
});
KityMinder.registerModule('ArrangeModule', {
commands: {
'arrangeup': ArrangeUpCommand,
'arrangedown': ArrangeDownCommand,
'arrange': ArrangeCommand
},
contextmenu: [{
command: 'arrangeup'
}, {
command: 'arrangedown'
}, {
divider: true
}],
commandShortcutKeys: {
'arrangeup': 'normal::alt+Up',
'arrangedown': 'normal::alt+Down'
} }
var ArrangeUpCommand = kity.createClass('ArrangeUpCommand', {
base: Command,
execute: function(km) {
var nodes = km.getSelectedNodes();
nodes.sort(asc);
var lastIndexes = nodes.map(function(node) {
return node.getIndex();
});
nodes.forEach(function(node, index) {
node.arrange(lastIndexes[index] - 1);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode();
return selected ? 0 : -1;
}
});
var ArrangeDownCommand = kity.createClass('ArrangeUpCommand', {
base: Command,
execute: function(km) {
var nodes = km.getSelectedNodes();
nodes.sort(desc);
var lastIndexes = nodes.map(function(node) {
return node.getIndex();
});
nodes.forEach(function(node, index) {
node.arrange(lastIndexes[index] + 1);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode();
return selected ? 0 : -1;
}
});
var ArrangeCommand = kity.createClass('ArrangeCommand', {
base: Command,
execute: function(km, nodes, index) {
nodes = nodes && nodes.slice() || km.getSelectedNodes().slice();
if (!nodes.length) return;
var ancestor = MinderNode.getCommonAncestor(nodes);
if (ancestor != nodes[0].parent) return;
var indexed = nodes.map(function(node) {
return {
index: node.getIndex(),
node: node
};
});
var asc = Math.min.apply(Math, indexed.map(function(one) { return one.index; })) >= index;
indexed.sort(function(a, b) {
return asc ? (b.index - a.index) : (a.index - b.index);
});
indexed.forEach(function(one) {
one.node.arrange(index);
});
km.layout(300);
},
queryState: function(km) {
var selected = km.getSelectedNode();
return selected ? 0 : -1;
}
});
Module.register('ArrangeModule', {
commands: {
'arrangeup': ArrangeUpCommand,
'arrangedown': ArrangeDownCommand,
'arrange': ArrangeCommand
},
contextmenu: [{
command: 'arrangeup'
}, {
command: 'arrangedown'
}, {
divider: true
}],
commandShortcutKeys: {
'arrangeup': 'normal::alt+Up',
'arrangedown': 'normal::alt+Down'
}
});
}); });
\ No newline at end of file
KityMinder.registerModule('basestylemodule', function() {
var km = this;
function getNodeDataOrStyle(node, name) { define(function(require, exports, module) {
return node.getData(name) || node.getStyle(name); var kity = require('core/kity');
} var utils = require('core/utils');
KityMinder.TextRenderer.registerStyleHook(function(node, textGroup) { var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
var fontWeight = getNodeDataOrStyle(node,'font-weight'); var TextRenderer = require('./text');
var fontStyle = getNodeDataOrStyle(node, 'font-style');
var styleHash = [fontWeight, fontStyle].join('/');
textGroup.eachItem(function(index,item){ Module.register('basestylemodule', function() {
item.setFont({ var km = this;
'weight': fontWeight,
'style': fontStyle function getNodeDataOrStyle(node, name) {
return node.getData(name) || node.getStyle(name);
}
TextRenderer.registerStyleHook(function(node, textGroup) {
var fontWeight = getNodeDataOrStyle(node,'font-weight');
var fontStyle = getNodeDataOrStyle(node, 'font-style');
var styleHash = [fontWeight, fontStyle].join('/');
textGroup.eachItem(function(index,item) {
item.setFont({
'weight': fontWeight,
'style': fontStyle
});
}); });
});
}); });
return { return {
'commands': { 'commands': {
'bold': kity.createClass('boldCommand', { 'bold': kity.createClass('boldCommand', {
base: Command, base: Command,
execute: function(km) { execute: function(km) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
if (this.queryState('bold') == 1) { if (this.queryState('bold') == 1) {
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-weight').render(); n.setData('font-weight').render();
}); });
} else { } else {
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-weight', 'bold').render(); n.setData('font-weight', 'bold').render();
});
}
km.layout();
},
queryState: function() {
var nodes = km.getSelectedNodes(),
result = 0;
if (nodes.length === 0) {
return -1;
}
nodes.forEach(function(n) {
if (n && n.getData('font-weight')) {
result = 1;
return false;
}
}); });
return result;
} }
km.layout(); }),
}, 'italic': kity.createClass('italicCommand', {
queryState: function() { base: Command,
var nodes = km.getSelectedNodes(),
result = 0;
if (nodes.length === 0) {
return -1;
}
utils.each(nodes, function(i, n) {
if (n && n.getData('font-weight')) {
result = 1;
return false;
}
});
return result;
}
}),
'italic': kity.createClass('italicCommand', {
base: Command,
execute: function(km) { execute: function(km) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
if (this.queryState('italic') == 1) { if (this.queryState('italic') == 1) {
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-style').render(); n.setData('font-style').render();
}); });
} else { } else {
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-style', 'italic').render(); n.setData('font-style', 'italic').render();
}); });
} }
km.layout(); km.layout();
}, },
queryState: function() { queryState: function() {
var nodes = km.getSelectedNodes(), var nodes = km.getSelectedNodes(),
result = 0; result = 0;
if (nodes.length === 0) { if (nodes.length === 0) {
return -1; return -1;
}
utils.each(nodes, function(i, n) {
if (n && n.getData('font-style')) {
result = 1;
return false;
} }
}); nodes.forEach(function(n) {
return result; if (n && n.getData('font-style')) {
} result = 1;
}) return false;
}, }
commandShortcutKeys: { });
'bold': 'ctrl+b', //bold return result;
'italic': 'ctrl+i' //italic }
} })
}; },
commandShortcutKeys: {
'bold': 'ctrl+b', //bold
'italic': 'ctrl+i' //italic
}
};
});
}); });
\ No newline at end of file
KityMinder.registerModule( "ClipboardModule", function () { define(function(require, exports, module) {
var km = this, var kity = require('core/kity');
var utils = require('core/utils');
_clipboardNodes = [], var MinderNode = require('core/node');
var Command = require('core/command');
_selectedNodes = []; var Module = require('core/module');
Module.register('ClipboardModule', function() {
var km = this,
_clipboardNodes = [],
_selectedNodes = [];
function appendChildNode(parent, child) {
_selectedNodes.push(child);
km.appendNode(child, parent);
child.render();
child.setLayoutOffset(null);
var children = utils.cloneArr(child.children);
for (var i = 0, ci;
(ci = children[i]); i++) {
appendChildNode(child, ci);
}
}
function appendChildNode(parent, child) { function sendToClipboard(nodes) {
_selectedNodes.push(child); if (!nodes.length) return;
km.appendNode(child, parent); _clipboardNodes = nodes.map(function(node) {
child.render(); return node.clone();
child.setLayoutOffset(null); });
var children = utils.cloneArr(child.children);
for (var i = 0, ci; (ci = children[i]); i++) {
appendChildNode(child, ci);
} }
}
function sendToClipboard(nodes) { var CopyCommand = kity.createClass('CopyCommand', {
if (!nodes.length) return; base: Command,
_clipboardNodes = nodes.map(function(node) {
return node.clone(); execute: function(km) {
sendToClipboard(km.getSelectedAncestors(true));
this.setContentChanged(false);
}
}); });
}
var CopyCommand = kity.createClass('CopyCommand', { var CutCommand = kity.createClass('CutCommand', {
base: Command, base: Command,
execute: function(km) { execute: function(km) {
sendToClipboard(km.getSelectedAncestors(true)); var ancestors = km.getSelectedAncestors();
this.setContentChanged(false);
}
});
var CutCommand = kity.createClass('CutCommand', { if (ancestors.length === 0) return;
base: Command,
execute: function(km) { sendToClipboard(ancestors);
var ancestors = km.getSelectedAncestors();
if (ancestors.length === 0) return; km.select(MinderNode.getCommonAncestor(ancestors), true);
sendToClipboard(ancestors); ancestors.slice().forEach(function(node) {
km.removeNode(node);
});
km.select(MinderNode.getCommonAncestor(ancestors), true); km.layout(300);
}
});
ancestors.slice().forEach(function(node) { var PasteCommand = kity.createClass('PasteCommand', {
km.removeNode(node); base: Command,
});
km.layout(300); execute: function(km) {
} if (_clipboardNodes.length) {
}); var node = km.getSelectedNode();
if (!node) return;
var PasteCommand = kity.createClass('PasteCommand', { for (var i = 0, ni;
base: Command, (ni = _clipboardNodes[i]); i++) {
appendChildNode(node, ni.clone());
}
execute: function(km) { km.select(_selectedNodes, true);
if (_clipboardNodes.length) { _selectedNodes = [];
var node = km.getSelectedNode();
if (!node) return;
for(var i= 0, ni; (ni = _clipboardNodes[i]); i++) { km.layout(300);
appendChildNode(node, ni.clone());
} }
},
km.select(_selectedNodes, true); queryState: function(km) {
_selectedNodes = []; return km.getSelectedNode() ? 0 : -1;
km.layout(300);
} }
}, });
queryState: function(km) { return {
return km.getSelectedNode() ? 0 : -1; 'commands': {
} 'copy': CopyCommand,
'cut': CutCommand,
'paste': PasteCommand
},
'commandShortcutKeys': {
'copy': 'normal::ctrl+c|',
'cut': 'normal::ctrl+x',
'paste': 'normal::ctrl+v'
}
};
}); });
});
return { \ No newline at end of file
'commands': {
'copy': CopyCommand,
'cut': CutCommand,
'paste': PasteCommand
},
'commandShortcutKeys': {
'copy': 'normal::ctrl+c|',
'cut': 'normal::ctrl+x',
'paste': 'normal::ctrl+v'
}
};
} );
\ No newline at end of file
var GM = KityMinder.Geometry; define(function(require, exports, module) {
var kity = require('core/kity');
// 矩形的变形动画定义 var utils = require('core/utils');
var MinderNode = require('core/node');
var MoveToParentCommand = kity.createClass('MoveToParentCommand', { var Command = require('core/command');
base: Command, var Module = require('core/module');
execute: function(minder, nodes, parent) {
var node; // 矩形的变形动画定义
for (var i = nodes.length - 1; i >= 0; i--) {
node = nodes[i]; var MoveToParentCommand = kity.createClass('MoveToParentCommand', {
if (node.parent) { base: Command,
node.parent.removeChild(node); execute: function(minder, nodes, parent) {
parent.appendChild(node); var node;
node.render(); for (var i = nodes.length - 1; i >= 0; i--) {
node = nodes[i];
if (node.parent) {
node.parent.removeChild(node);
parent.appendChild(node);
node.render();
}
} }
parent.expand();
minder.select(nodes, true);
} }
parent.expand(); });
minder.select(nodes, true);
} var DropHinter = kity.createClass('DropHinter', {
}); base: kity.Group,
var DropHinter = kity.createClass('DropHinter', { constructor: function() {
base: kity.Group, this.callBase();
this.rect = new kity.Rect();
constructor: function() { this.addShape(this.rect);
this.callBase(); },
this.rect = new kity.Rect();
this.addShape(this.rect); render: function(target) {
}, this.setVisible(!!target);
if (target) {
render: function(target) { this.rect
this.setVisible(!!target); .setBox(target.getLayoutBox())
if (target) { .setRadius(target.getStyle('radius') || 0)
this.rect .stroke(
.setBox(target.getLayoutBox()) target.getStyle('drop-hint-color') || 'yellow',
.setRadius(target.getStyle('radius') || 0) target.getStyle('drop-hint-width') || 2
.stroke( );
target.getStyle('drop-hint-color') || 'yellow', this.bringTop();
target.getStyle('drop-hint-width') || 2 }
);
this.bringTop();
}
}
});
var OrderHinter = kity.createClass('OrderHinter', {
base: kity.Group,
constructor: function() {
this.callBase();
this.area = new kity.Rect();
this.path = new kity.Path();
this.addShapes([this.area, this.path]);
},
render: function(hint) {
this.setVisible(!!hint);
if (hint) {
this.area.setBox(hint.area);
this.area.fill(hint.node.getStyle('order-hint-area-color') || 'rgba(0, 255, 0, .5)');
this.path.setPathData(hint.path);
this.path.stroke(
hint.node.getStyle('order-hint-path-color') || '#0f0',
hint.node.getStyle('order-hint-path-width') || 1);
} }
} });
});
var OrderHinter = kity.createClass('OrderHinter', {
base: kity.Group,
// 对拖动对象的一个替代盒子,控制整个拖放的逻辑,包括: constructor: function() {
// 1. 从节点列表计算出拖动部分 this.callBase();
// 2. 计算可以 drop 的节点,产生 drop 交互提示 this.area = new kity.Rect();
var TreeDragger = kity.createClass('TreeDragger', { this.path = new kity.Path();
this.addShapes([this.area, this.path]);
},
render: function(hint) {
this.setVisible(!!hint);
if (hint) {
this.area.setBox(hint.area);
this.area.fill(hint.node.getStyle('order-hint-area-color') || 'rgba(0, 255, 0, .5)');
this.path.setPathData(hint.path);
this.path.stroke(
hint.node.getStyle('order-hint-path-color') || '#0f0',
hint.node.getStyle('order-hint-path-width') || 1);
}
}
});
// 对拖动对象的一个替代盒子,控制整个拖放的逻辑,包括:
// 1. 从节点列表计算出拖动部分
// 2. 计算可以 drop 的节点,产生 drop 交互提示
var TreeDragger = kity.createClass('TreeDragger', {
constructor: function(minder) {
this._minder = minder;
this._dropHinter = new DropHinter();
this._orderHinter = new OrderHinter();
minder.getRenderContainer().addShapes([this._dropHinter, this._orderHinter]);
},
constructor: function(minder) { dragStart: function(position) {
this._minder = minder; // 只记录开始位置,不马上开启拖放模式
this._dropHinter = new DropHinter(); // 这个位置同时是拖放范围收缩时的焦点位置(中心)
this._orderHinter = new OrderHinter(); this._startPosition = position;
minder.getRenderContainer().addShapes([this._dropHinter, this._orderHinter]); },
},
dragStart: function(position) { dragMove: function(position) {
// 只记录开始位置,不马上开启拖放模式 // 启动拖放模式需要最小的移动距离
// 这个位置同时是拖放范围收缩时的焦点位置(中心) var DRAG_MOVE_THRESHOLD = 10;
this._startPosition = position;
},
dragMove: function(position) { if (!this._startPosition) return;
// 启动拖放模式需要最小的移动距离
var DRAG_MOVE_THRESHOLD = 10;
if (!this._startPosition) return; var movement = kity.Vector.fromPoints(this._dragPosition || this._startPosition, position);
var minder = this._minder;
var movement = kity.Vector.fromPoints(this._dragPosition || this._startPosition, position); this._dragPosition = position;
var minder = this._minder;
this._dragPosition = position; if (!this._dragMode) {
// 判断拖放模式是否该启动
if (kity.Vector.fromPoints(this._dragPosition, this._startPosition).length() < DRAG_MOVE_THRESHOLD) {
return;
}
if (!this._enterDragMode()) {
return;
}
}
if (!this._dragMode) { for (var i = 0; i < this._dragSources.length; i++) {
// 判断拖放模式是否该启动 this._dragSources[i].setLayoutOffset(this._dragSources[i].getLayoutOffset().offset(movement));
if (GM.getDistance(this._dragPosition, this._startPosition) < DRAG_MOVE_THRESHOLD) { minder.applyLayoutResult(this._dragSources[i]);
return; }
if (!this._dropTest()) {
this._orderTest();
} else {
this._renderOrderHint(this._orderSucceedHint = null);
} }
if (!this._enterDragMode()) { },
dragEnd: function() {
this._startPosition = null;
this._dragPosition = null;
if (!this._dragMode) {
return; return;
} }
}
for (var i = 0; i < this._dragSources.length; i++) { this._fadeDragSources(1);
this._dragSources[i].setLayoutOffset(this._dragSources[i].getLayoutOffset().offset(movement));
minder.applyLayoutResult(this._dragSources[i]);
}
if (!this._dropTest()) {
this._orderTest();
} else {
this._renderOrderHint(this._orderSucceedHint = null);
}
},
dragEnd: function() { if (this._dropSucceedTarget) {
this._startPosition = null;
this._dragPosition = null;
if (!this._dragMode) { this._dragSources.forEach(function(source) {
return; source.setLayoutOffset(null);
} });
this._minder.layout(-1);
this._fadeDragSources(1); this._minder.execCommand('movetoparent', this._dragSources, this._dropSucceedTarget);
if (this._dropSucceedTarget) { } else if (this._orderSucceedHint) {
this._dragSources.forEach(function(source) { var hint = this._orderSucceedHint;
source.setLayoutOffset(null); var index = hint.node.getIndex();
});
this._minder.layout(-1);
this._minder.execCommand('movetoparent', this._dragSources, this._dropSucceedTarget); var sourceIndexes = this._dragSources.map(function(source) {
// 顺便干掉布局偏移
source.setLayoutOffset(null);
return source.getIndex();
});
} else if (this._orderSucceedHint) { var maxIndex = Math.max.apply(Math, sourceIndexes);
var minIndex = Math.min.apply(Math, sourceIndexes);
var hint = this._orderSucceedHint; if (index < minIndex && hint.type == 'down') index++;
var index = hint.node.getIndex(); if (index > maxIndex && hint.type == 'up') index--;
var sourceIndexes = this._dragSources.map(function(source) { hint.node.setLayoutOffset(null);
// 顺便干掉布局偏移
source.setLayoutOffset(null);
return source.getIndex();
});
var maxIndex = Math.max.apply(Math, sourceIndexes); this._minder.execCommand('arrange', this._dragSources, index);
var minIndex = Math.min.apply(Math, sourceIndexes); this._renderOrderHint(null);
} else {
this._minder.fire('savescene');
}
this._minder.layout(300);
this._leaveDragMode();
this._minder.fire('contentchange');
},
if (index < minIndex && hint.type == 'down') index++; // 进入拖放模式:
if (index > maxIndex && hint.type == 'up') index--; // 1. 计算拖放源和允许的拖放目标
// 2. 标记已启动
_enterDragMode: function() {
this._calcDragSources();
if (!this._dragSources.length) {
this._startPosition = null;
return false;
}
this._fadeDragSources(0.5);
this._calcDropTargets();
this._calcOrderHints();
this._dragMode = true;
this._minder.setStatus('dragtree');
return true;
},
hint.node.setLayoutOffset(null); // 从选中的节点计算拖放源
// 并不是所有选中的节点都作为拖放源,如果选中节点中存在 A 和 B,
// 并且 A 是 B 的祖先,则 B 不作为拖放源
//
// 计算过程:
// 1. 将节点按照树高排序,排序后只可能是前面节点是后面节点的祖先
// 2. 从后往前枚举排序的结果,如果发现枚举目标之前存在其祖先,
// 则排除枚举目标作为拖放源,否则加入拖放源
_calcDragSources: function() {
this._dragSources = this._minder.getSelectedAncestors();
},
this._minder.execCommand('arrange', this._dragSources, index); _fadeDragSources: function(opacity) {
this._renderOrderHint(null); var minder = this._minder;
} else { this._dragSources.forEach(function(source) {
this._minder.fire('savescene'); source.getRenderContainer().setOpacity(opacity, 200);
} source.traverse(function(node) {
this._minder.layout(300); if (opacity < 1) {
this._leaveDragMode(); minder.detachNode(node);
this._minder.fire('contentchange'); } else {
}, minder.attachNode(node);
}
// 进入拖放模式: }, true);
// 1. 计算拖放源和允许的拖放目标
// 2. 标记已启动
_enterDragMode: function() {
this._calcDragSources();
if (!this._dragSources.length) {
this._startPosition = null;
return false;
}
this._fadeDragSources(0.5);
this._calcDropTargets();
this._calcOrderHints();
this._dragMode = true;
this._minder.setStatus('dragtree');
return true;
},
// 从选中的节点计算拖放源
// 并不是所有选中的节点都作为拖放源,如果选中节点中存在 A 和 B,
// 并且 A 是 B 的祖先,则 B 不作为拖放源
//
// 计算过程:
// 1. 将节点按照树高排序,排序后只可能是前面节点是后面节点的祖先
// 2. 从后往前枚举排序的结果,如果发现枚举目标之前存在其祖先,
// 则排除枚举目标作为拖放源,否则加入拖放源
_calcDragSources: function() {
this._dragSources = this._minder.getSelectedAncestors();
},
_fadeDragSources: function(opacity) {
var minder = this._minder;
this._dragSources.forEach(function(source) {
source.getRenderContainer().setOpacity(opacity, 200);
source.traverse(function(node) {
if (opacity < 1) {
minder.detachNode(node);
} else {
minder.attachNode(node);
}
}, true);
});
},
// 计算拖放目标可以释放的节点列表(释放意味着成为其子树),存在这条限制规则:
// - 不能拖放到拖放目标的子树上(允许拖放到自身,因为多选的情况下可以把其它节点加入)
//
// 1. 加入当前节点(初始为根节点)到允许列表
// 2. 对于当前节点的每一个子节点:
// (1) 如果是拖放目标的其中一个节点,忽略(整棵子树被剪枝)
// (2) 如果不是拖放目标之一,以当前子节点为当前节点,回到 1 计算
// 3. 返回允许列表
//
_calcDropTargets: function() {
function findAvailableParents(nodes, root) {
var availables = [],
i;
availables.push(root);
root.getChildren().forEach(function(test) {
for (i = 0; i < nodes.length; i++) {
if (nodes[i] == test) return;
}
availables = availables.concat(findAvailableParents(nodes, test));
}); });
return availables; },
}
this._dropTargets = findAvailableParents(this._dragSources, this._minder.getRoot());
this._dropTargetBoxes = this._dropTargets.map(function(source) {
return source.getLayoutBox();
});
},
_calcOrderHints: function() { // 计算拖放目标可以释放的节点列表(释放意味着成为其子树),存在这条限制规则:
var sources = this._dragSources; // - 不能拖放到拖放目标的子树上(允许拖放到自身,因为多选的情况下可以把其它节点加入)
var ancestor = MinderNode.getCommonAncestor(sources); //
// 1. 加入当前节点(初始为根节点)到允许列表
// 2. 对于当前节点的每一个子节点:
// (1) 如果是拖放目标的其中一个节点,忽略(整棵子树被剪枝)
// (2) 如果不是拖放目标之一,以当前子节点为当前节点,回到 1 计算
// 3. 返回允许列表
//
_calcDropTargets: function() {
function findAvailableParents(nodes, root) {
var availables = [],
i;
availables.push(root);
root.getChildren().forEach(function(test) {
for (i = 0; i < nodes.length; i++) {
if (nodes[i] == test) return;
}
availables = availables.concat(findAvailableParents(nodes, test));
});
return availables;
}
// 只有一个元素选中,公共祖先是其父 this._dropTargets = findAvailableParents(this._dragSources, this._minder.getRoot());
if (ancestor == sources[0]) ancestor = sources[0].parent; this._dropTargetBoxes = this._dropTargets.map(function(source) {
return source.getLayoutBox();
});
},
if (sources.length === 0 || ancestor != sources[0].parent) { _calcOrderHints: function() {
this._orderHints = []; var sources = this._dragSources;
return; var ancestor = MinderNode.getCommonAncestor(sources);
}
var siblings = ancestor.children; // 只有一个元素选中,公共祖先是其父
if (ancestor == sources[0]) ancestor = sources[0].parent;
this._orderHints = siblings.reduce(function(hint, sibling) { if (sources.length === 0 || ancestor != sources[0].parent) {
if (sources.indexOf(sibling) == -1) { this._orderHints = [];
hint = hint.concat(sibling.getOrderHint()); return;
} }
return hint;
}, []);
},
_leaveDragMode: function() {
this._dragMode = false;
this._dropSucceedTarget = null;
this._orderSucceedHint = null;
this._renderDropHint(null);
this._renderOrderHint(null);
this._minder.rollbackStatus();
},
_drawForDragMode: function() {
this._text.setContent(this._dragSources.length + ' items');
this._text.setPosition(this._startPosition.x, this._startPosition.y + 5);
this._minder.getRenderContainer().addShape(this);
},
_boxTest: function(targets, targetBoxMapper, judge) {
var sourceBoxes = this._dragSources.map(function(source) {
return source.getLayoutBox();
});
var i, j, target, sourceBox, targetBox;
judge = judge || function(intersectBox, sourceBox, targetBox) {
return intersectBox;
};
for (i = 0; i < targets.length; i++) { var siblings = ancestor.children;
this._orderHints = siblings.reduce(function(hint, sibling) {
if (sources.indexOf(sibling) == -1) {
hint = hint.concat(sibling.getOrderHint());
}
return hint;
}, []);
},
_leaveDragMode: function() {
this._dragMode = false;
this._dropSucceedTarget = null;
this._orderSucceedHint = null;
this._renderDropHint(null);
this._renderOrderHint(null);
this._minder.rollbackStatus();
},
_drawForDragMode: function() {
this._text.setContent(this._dragSources.length + ' items');
this._text.setPosition(this._startPosition.x, this._startPosition.y + 5);
this._minder.getRenderContainer().addShape(this);
},
target = targets[i]; _boxTest: function(targets, targetBoxMapper, judge) {
targetBox = targetBoxMapper.call(this, target, i); var sourceBoxes = this._dragSources.map(function(source) {
return source.getLayoutBox();
});
for (j = 0; j < sourceBoxes.length; j++) { var i, j, target, sourceBox, targetBox;
sourceBox = sourceBoxes[j];
var intersectBox = GM.getIntersectBox(sourceBox, targetBox); judge = judge || function(intersectBox, sourceBox, targetBox) {
if (judge(intersectBox, sourceBox, targetBox)) { return intersectBox;
return target; };
for (i = 0; i < targets.length; i++) {
target = targets[i];
targetBox = targetBoxMapper.call(this, target, i);
for (j = 0; j < sourceBoxes.length; j++) {
sourceBox = sourceBoxes[j];
var intersectBox = sourceBox.intersect(targetBox);
if (judge(intersectBox, sourceBox, targetBox)) {
return target;
}
} }
} }
}
return null; return null;
}, },
_dropTest: function() { _dropTest: function() {
this._dropSucceedTarget = this._boxTest(this._dropTargets, function(target, i) { this._dropSucceedTarget = this._boxTest(this._dropTargets, function(target, i) {
return this._dropTargetBoxes[i]; return this._dropTargetBoxes[i];
}, function(intersectBox, sourceBox, targetBox) { }, function(intersectBox, sourceBox, targetBox) {
function area(box) { function area(box) {
return box.width * box.height; return box.width * box.height;
} }
if (!intersectBox) return false; if (!intersectBox) return false;
// 面积判断 // 面积判断
if (area(intersectBox) > 0.5 * Math.min(area(sourceBox), area(targetBox))) return true; if (area(intersectBox) > 0.5 * Math.min(area(sourceBox), area(targetBox))) return true;
if (intersectBox.width + 1 >= Math.min(sourceBox.width, targetBox.width)) return true; if (intersectBox.width + 1 >= Math.min(sourceBox.width, targetBox.width)) return true;
if (intersectBox.height + 1 >= Math.min(sourceBox.height, targetBox.height)) return true; if (intersectBox.height + 1 >= Math.min(sourceBox.height, targetBox.height)) return true;
return false; return false;
});
this._renderDropHint(this._dropSucceedTarget);
return !!this._dropSucceedTarget;
},
_orderTest: function() {
this._orderSucceedHint = this._boxTest(this._orderHints, function(hint) {
return hint.area;
});
this._renderOrderHint(this._orderSucceedHint);
return !!this._orderSucceedHint;
},
_renderDropHint: function(target) {
this._dropHinter.render(target);
},
_renderOrderHint: function(hint) {
this._orderHinter.render(hint);
},
preventDragMove: function() {
this._startPosition = null;
}
});
KityMinder.registerModule('DragTree', function() {
var dragger;
return {
init: function() {
dragger = new TreeDragger(this);
window.addEventListener('mouseup', function() {
dragger.dragEnd();
}); });
this._renderDropHint(this._dropSucceedTarget);
return !!this._dropSucceedTarget;
}, },
events: {
'normal.mousedown inputready.mousedown': function(e) { _orderTest: function() {
// 单选中根节点也不触发拖拽 this._orderSucceedHint = this._boxTest(this._orderHints, function(hint) {
if (e.originEvent.button) return; return hint.area;
if (e.getTargetNode() && e.getTargetNode() != this.getRoot()) { });
dragger.dragStart(e.getPosition(this.getRenderContainer())); this._renderOrderHint(this._orderSucceedHint);
} return !!this._orderSucceedHint;
}, },
'normal.mousemove dragtree.mousemove': function(e) {
dragger.dragMove(e.getPosition(this.getRenderContainer())); _renderDropHint: function(target) {
}, this._dropHinter.render(target);
'normal.mouseup dragtree.beforemouseup': function(e) { },
dragger.dragEnd();
//e.stopPropagation(); _renderOrderHint: function(hint) {
e.preventDefault(); this._orderHinter.render(hint);
},
preventDragMove: function() {
this._startPosition = null;
}
});
Module.register('DragTree', function() {
var dragger;
return {
init: function() {
dragger = new TreeDragger(this);
window.addEventListener('mouseup', function() {
dragger.dragEnd();
});
}, },
'statuschange': function(e) { events: {
if (e.lastStatus == 'textedit' && e.currentStatus == 'normal') { 'normal.mousedown inputready.mousedown': function(e) {
dragger.preventDragMove(); // 单选中根节点也不触发拖拽
if (e.originEvent.button) return;
if (e.getTargetNode() && e.getTargetNode() != this.getRoot()) {
dragger.dragStart(e.getPosition(this.getRenderContainer()));
}
},
'normal.mousemove dragtree.mousemove': function(e) {
dragger.dragMove(e.getPosition(this.getRenderContainer()));
},
'normal.mouseup dragtree.beforemouseup': function(e) {
dragger.dragEnd();
//e.stopPropagation();
e.preventDefault();
},
'statuschange': function(e) {
if (e.lastStatus == 'textedit' && e.currentStatus == 'normal') {
dragger.preventDragMove();
}
} }
},
commands: {
'movetoparent': MoveToParentCommand
} }
}, };
commands: { });
'movetoparent': MoveToParentCommand
}
};
}); });
\ No newline at end of file
/* global Renderer: true */
KityMinder.registerModule('TextEditModule', function() {
var km = this;
var sel = new KityMinder.Selection();
var range = new KityMinder.Range();
var receiver = new KityMinder.Receiver(this,sel,range);
var keyboarder = new KityMinder.keyboarder(receiver);
this.receiver = receiver;
//鼠标被点击,并未太抬起时为真
var mouseDownStatus = false;
var dblclickEvent = false;
//当前是否有选区存在
var selectionReadyShow = false;
var mousedownNode,mouseupTimer,mousedownTimer;
var lastMinderNode;
function inputStatusReady(node){
if (node && km.isSingleSelect() && node.isSelected()) {
node.getTextGroup().setStyle('cursor','default');
var color = node.getStyle('text-selection-color');
//准备输入状态
receiver.updateByMinderNode(node);
sel.setHide()
.setStartOffset(0)
.setEndOffset(receiver.getTxtOfContainer().length)
.setColor(color);
receiver.updateContainerRangeBySel();
if(kity.Browser.ie ){
var timer = setInterval(function(){
var nativeRange = range.nativeSel.getRangeAt(0);
if(!nativeRange || nativeRange.collapsed){
range.select();
}else {
clearInterval(timer);
}
});
}
km.setStatus('inputready');
}
}
km.textEditNode = function(node){
inputStatusReady(node);
km.setStatus('textedit');
receiver.updateSelection();
};
return {
'events': {
'ready': function() {
document.body.appendChild(receiver.container);
},
'normal.beforemousedown textedit.beforemousedown inputready.beforemousedown': function(e) {
//右键直接退出
if (e.isRightMB()) {
if (!e.getTargetNode()) this.setStatus('normal');
return;
}
mouseDownStatus = true;
selectionReadyShow = sel.isShow();
sel.setHide();
var node = e.getTargetNode();
//点击在之前的选区上
if (!node) {
var selectionShape = e.kityEvent.targetShape;
if (selectionShape && selectionShape.getType() == 'Selection') {
node = receiver.getMinderNode();
e.stopPropagationImmediately();
}
}
if(node){
if (this.isSingleSelect() && node.isSelected()) {
lastMinderNode = node;
mousedownNode = node;
var textGroup = node.getTextGroup();
sel.collapse(true);
sel.setColor(node.getStyle('text-selection-color'));
receiver
.updateByMinderNode(node)
.updateIndexByMouse(e.getPosition(node.getRenderContainer()))
.setRange(range)
.setReady();
if(selectionReadyShow){
sel.setShowStatus();
clearTimeout(mousedownTimer);
mousedownTimer = setTimeout(function() {
if(dblclickEvent){
dblclickEvent = false;
return;
}
sel.collapse(true)
.updatePosition(receiver.getOffsetByIndex())
.setShow();
textGroup.setStyle('cursor','text');
},200);
km.setStatus('textedit');
}
return;
}
}
//模拟光标没有准备好
receiver.clearReady();
//当点击空白处时,光标需要消失
receiver.clear();
if(lastMinderNode){
lastMinderNode.getTextGroup().setStyle('cursor','default');
}
},
'inputready.keyup':function(){
if(sel.isHide()){
inputStatusReady(this.getSelectedNode());
}
},
//当节点选区通过键盘发生变化时,输入状态要准备好
'normal.keyup': function(e) {
var node = this.getSelectedNode();
var keyCode = e.getKeyCode();
if (node) {
if (this.isSingleSelect() && node.isSelected() && !sel.isShow() ) {
var orgEvt = e.originEvent;
if (keymap.isSelectedNodeKey[keyCode] &&
!orgEvt.ctrlKey &&
!orgEvt.metaKey &&
!orgEvt.shiftKey &&
!orgEvt.altKey) {
inputStatusReady(node);
}
}
}
},
'normal.mouseup textedit.mouseup inputready.mouseup': function(e) {
mouseDownStatus = false;
var node = e.getTargetNode();
mousedownNode = null;
if (node && !selectionReadyShow && receiver.isReady()) {
sel.collapse(true);
sel.setColor(node.getStyle('text-selection-color'));
//必须再次focus,要不不能呼出键盘
if(kity.Browser.ipad){
receiver.focus();
}
clearTimeout(mouseupTimer);
mouseupTimer = setTimeout(function() {
if(dblclickEvent){
dblclickEvent = false;
return;
}
sel.collapse(true)
.updatePosition(receiver.getOffsetByIndex())
.setShow();
node.getTextGroup().setStyle('cursor','text');
}, 200);
km.setStatus('textedit');
return;
}
//当选中节点后,输入状态准备
if(sel.isHide()){
inputStatusReady(e.getTargetNode());
}else {
//当有光标时,要同步选区
if(!sel.collapsed){
receiver.updateContainerRangeBySel();
}
}
},
'textedit.beforemousemove inputready.beforemousemove': function(e) {
if(kity.Browser.ipad){
return;
}
//ipad下不做框选
if (mouseDownStatus && receiver.isReady() && selectionReadyShow) {
e.stopPropagationImmediately();
if(mousedownNode){
var offset = e.getPosition( mousedownNode.getRenderContainer());
receiver
.updateSelectionByMousePosition(offset)
.updateSelection(offset);
setTimeout(function(){
receiver.updateContainerRangeBySel();
});
}
}else if(mouseDownStatus && !selectionReadyShow){
//第一次点中,第二次再次点中进行拖拽
km.setStatus('normal');
receiver.clearReady();
}
},
'normal.dblclick textedit.dblclick inputready.dblclick': function(e) {
var node = e.getTargetNode();
dblclickEvent = true;
if(node){
//跟mouseup的timeout有冲突,这里做标记处理
inputStatusReady(node);
km.setStatus('textedit');
receiver.updateSelection();
}
},
'restoreScene': function() {
receiver.clear();
inputStatusReady(this.getSelectedNode());
},
'stopTextEdit': function() {
receiver.clear();
km.setStatus('normal');
},
'resize': function(e) {
sel.setHide();
},
'execCommand': function(e) {
var cmds = {
'appendchildnode': 1,
'appendsiblingnode': 1,
'editnode': 1
};
if (cmds[e.commandName]) {
inputStatusReady(km.getSelectedNode());
receiver.updateSelection();
return;
}
if(sel.isShow()){
receiver.updateTextOffsetData().updateSelection();
}
},
'layoutfinish':function(e){
if (e.node === receiver.minderNode && (this.getStatus() == 'textedit' || this.getStatus() == 'inputready') ) {//&& selectionReadyShow
receiver.setContainerStyle();
}
},
'selectionclear': function() {
var node = km.getSelectedNode();
if(node){
inputStatusReady(node);
}else{
km.setStatus('normal');
receiver.clear();
}
},
'blur': function() {
!/\?debug#?/.test(location.href) && receiver.clear();
},
'textedit.import': function() {
km.setStatus('normal');
receiver.clear();
},
'inputready.mousewheel textedit.mousewheel': function() {
receiver.setContainerStyle();
},
'statuschange':function(e){
if(e.lastStatus == 'textedit'){
this.fire('contentchange');
}
}
}
};
});
\ No newline at end of file
//接收者
KityMinder.keyboarder = kity.createClass('keyboarder', function(){
return {
constructor: function(re) {
this.re = re;
this.container = re.container;
this.selection = re.selection;
this.range = re.range;
this.km = re.km;
this.lastMinderNode = null;
this.isTypeText = false;
this._initEvent();
this.isShortcutCopyKey = false;
},
//给接受容器绑定事件
_initEvent: function(){
var me = this;
if(kity.Browser.ipad) {
utils.listen(this.container, 'keydown keypress keyup input', function(e) {
me._handleEvents.call(me, new MinderEvent(e.type == 'keyup' ? 'beforekeyup' : e.type, e));
if(e.type == 'keyup'){
if(me.km.getStatus() == 'normal'){
me.km.fire( 'keyup', e);
}
}
});
}
this.km.on('inputready.beforekeyup ' +
'inputready.beforekeydown ' +
'textedit.beforekeyup ' +
'normal.keydown ' +
'normal.keyup ' +
'textedit.beforekeydown ' +
'textedit.keypress ' +
'textedit.paste',
utils.proxy(this._handleEvents, this));
},
_handleEvents:function(e){
switch (e.type) {
case 'input':
this._input(e);
break;
case 'beforekeydown':
this._beforeKeydown(e);
break;
case 'beforekeyup':
this._beforeKeyup(e);
break;
case 'keyup':
this._keyup(e);
}
},
_setTextToContainer : function(keyCode,iskeyUp){
var me = this;
//同步节点
me.minderNode = me.re.minderNode;
clearTimeout(me.timer);
if (!me.range.hasNativeRange()) {
return;
}
if(keymap.controlKeys[keyCode] && !iskeyUp ){
return;
}
//当第一次输入内容时进行保存
if(me.lastMinderNode !== me.minderNode && !keymap.notContentChange[keyCode]){
me.km.fire('saveScene',{
inputStatus:true
});
me.lastMinderNode = me.minderNode;
}
var text = me.re.getTxtOfContainer();
// //#46 修复在ff下定位到文字后方空格光标不移动问题
// if (kity.Browser.gecko && /\s$/.test(text)) {
// text += '\u200b';
// }
//重新渲染节点
me.minderNode.setText(text);
me.re.setContainerStyle();
me.minderNode.getRenderContainer().bringTop();
me.minderNode.render();
//移动光标不做layout
if(!keymap.notContentChange[keyCode]){
clearTimeout(me.inputTextTimer);
me.inputTextTimer = setTimeout(function(){
me.km.layout(300);
},300);
}
me.re.updateTextOffsetData()
.updateRange()
.updateSelectionByRange();
me.selection
.updateOffsetByTextData(me.re.textData)
.updatePosition();
//当然inputready状态时,如果输入文字,节点内文本会被先选中然后再消失,体验不好
if(me.km.getStatus() != 'inputready'){
me.selection.setHoldShow();
}
me.timer = setTimeout(function() {
if(me.selection.isShow()){
me.selection.setShow();
}
}, 200);
me.km.setStatus('textedit');
},
_input:function(){
var me = this;
if (kity.Browser.ipad) {
setTimeout(function() {
me._setTextToContainer();
});
}
},
_beforeKeydown:function(e){
var me = this;
var orgEvt = e.originEvent;
var keyCode = orgEvt.keyCode;
this.isTypeText = keyCode == 229 || keyCode === 0;
switch (keyCode) {
case keymap.Enter:
if(e.originEvent.shiftKey && me.selection.isShow()){
me._handlerEnterkey();
e.preventDefault();
return false;
};
case keymap.Tab:
case keymap.Insert:
if(this.selection.isShow()){
this.re.clear();
this.km.setStatus('inputready');
clearTimeout(me.inputTextTimer);
e.preventDefault();
}else{
this.km.setStatus('normal');
this.km.fire('contentchange');
}
return;
case keymap.left:
case keymap.right:
case keymap.up:
case keymap.down:
case keymap.Backspace:
case keymap.Del:
case keymap['/']:
case keymap.F2:
case keymap.Insert:
if(this.selection.isHide()){
this.km.setStatus('normal');
return;
}
break;
case keymap.Control:
case keymap.Alt:
case keymap.Cmd:
if(this.selection.isHide() && this.km.getStatus() != 'textedit' && this.km.getStatus() !='inputready'){
this.km.setStatus('normal');
return;
}
}
if (e.originEvent.ctrlKey || e.originEvent.metaKey) {
//选中节点时的复制粘贴,要变成normal
if(this.selection.isHide() && {
86:1,
88:1,
67:1
}[keyCode]){
//修正在cvs方式下_keyup会把节点文字选中
this.isShortcutCopyKey = true;
this.km.setStatus('normal');
return;
}
//粘贴
if (keyCode == keymap.v) {
setTimeout(function () {
me.range.updateNativeRange().insertNode($('<span>$$_kityminder_bookmark_$$</span>')[0]);
var brArr = [];
utils.each(me.container.getElementsByTagName('br'),function(i,br){
brArr.push(br);
});
utils.each(brArr,function(i,br){
var textNode = document.createTextNode('\n');
br.parentNode.insertBefore(textNode,br);
br.parentNode.removeChild(br);
});
var textContent = me.container.textContent.replace(/[\u200b\t\r]/g,'');
var index = textContent.indexOf('$$_kityminder_bookmark_$$');
me.re.setContainerTxt(textContent.replace('$$_kityminder_bookmark_$$',''));
me.range.setStartOffset(index).collapse(true).select();
me._setTextToContainer(keyCode);
},50);
return;
}
//剪切
if (keyCode == keymap.x) {
setTimeout(function () {
me._setTextToContainer(keyCode);
},50);
return;
}
}
this.isShortcutCopyKey = false;
//针对不能连续删除做处理
//if(keymap.Del == keyCode || keymap.Backspace == keyCode)
// me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode);
},
_beforeKeyup:function(e){
var me = this;
var orgEvt = e.originEvent;
var keyCode = orgEvt.keyCode;
switch (keyCode) {
case keymap.Enter:
case keymap.Tab:
case keymap.Insert:
case keymap.F2:
if(kity.Browser.ipad){
if(this.selection.isShow()){
this.re.clear();
this.km.setStatus('inputready');
clearTimeout(me.inputTextTimer);
e.preventDefault();
}else{
this.km.setStatus('normal');
this.km.fire('contentchange');
}
return;
}
if (keymap.Enter == keyCode && (this.isTypeText || kity.Browser.mac && kity.Browser.gecko)) {
me._setTextToContainer(keyCode,true);
}
if (this.re.keydownNode === this.re.minderNode) {
this.km.rollbackStatus();
this.re.clear();
}
e.preventDefault();
return;
case keymap.Del:
case keymap.Backspace:
case keymap.Spacebar:
if(kity.Browser.ipad){
if(this.selection.isHide()){
this.km.setStatus('normal');
return;
}
}
me._setTextToContainer(keyCode,true);
return;
}
if (this.isTypeText) {
me._setTextToContainer(keyCode,true);
return;
}
if (kity.Browser.mac && kity.Browser.gecko){
me._setTextToContainer(keyCode,true);
return;
}
me._setTextToContainer(keyCode,true);
return true;
},
_keyup:function(e){
var me = this;
var timer;
var node = this.km.getSelectedNode();
if(this.km.getStatus() == 'normal' && node && this.selection.isHide()){
if(this.isShortcutCopyKey){
return;
}
if (node && this.km.isSingleSelect() && node.isSelected()) {
this.re.updateByMinderNode(node);
this.selection.setHide()
.setStartOffset(0)
.setEndOffset(this.re.getTxtOfContainer().length)
.setColor( node.getStyle('text-selection-color'));
setTimeout(function(){
me.re.updateContainerRangeBySel();
});
if(kity.Browser.ie ){
timer = setInterval(function(){
var nativeRange = me.range.nativeSel.getRangeAt(0);
if(!nativeRange || nativeRange.collapsed){
me.range.select();
}else {
clearInterval(timer);
}
});
}
this.km.setStatus('inputready');
}
}
},
//处理软回车操作
_handlerEnterkey:function(){
function removeTmpTextNode(node){
if(node && node.nodeType == 3 && node.nodeValue.length === 0){
node.parentNode.removeChild(node);
}
}
var rng = this.range;
var br = document.createElement('br');
var me = this;
if(!rng.collapsed){
rng.deleteContents();
}
rng.insertNode(br);
removeTmpTextNode(br.previousSibling);
removeTmpTextNode(br.nextSibling);
rng.setStartAfter(br);
rng.collapse(true);
var start = rng.startContainer.childNodes[rng.startOffset];
if(!start){
br = br.cloneNode(false);
rng.startContainer.appendChild(br);
rng.setStartBefore(br);
rng.collapse(true);
}
rng.select();
me._setTextToContainer(keymap.Enter);
}
};
}());
\ No newline at end of file
KityMinder.Range = kity.createClass('Range',function(){
function getOffset(rng,dir){
var node = rng[dir + 'Container'],
offset = rng[dir + 'Offset'],
rOffset = 0;
if(node.nodeType == 1){
//默认不会出现得不到子节点的情况
node = node.childNodes[offset];
if(!node && rng.startContainer && rng.startContainer.nodeName == 'DIV' ) {
rng.startContainer.innerHTML = '<p></p>';
offset = 0;
}else if(node.nodeType == 3){
offset = 0;
}
}
utils.each(rng.container.childNodes,function(index,n){
if(n === node){
if(n.nodeType == 1){
return false;
}else{
rOffset += offset;
return false;
}
}
rOffset += (n.nodeType == 1 ? 1 : utils.clearWhitespace(n.nodeValue).length);
});
return rOffset;
}
function setBoundary(rng,offset,dir){
var rOffset = 0,cont = rng.container;
utils.each(cont.childNodes,function(index,node){
if(node.nodeType == 1){
if(rOffset == offset){
rng['set' + dir](cont,index);
return false;
}
rOffset++;
return;
}
var currentLength = utils.clearWhitespace(node.nodeValue).length;
if(rOffset + currentLength >= offset){
rng['set' + dir](node,offset - rOffset);
return false;
}
rOffset += currentLength;
});
}
return {
constructor : function(container){
this.nativeRange = document.createRange();
this.nativeSel = window.getSelection();
this.startContainer =
this.endContainer =
this.startOffset =
this.endOffset = null;
this.collapsed = false;
this.container = container || null;
},
hasNativeRange : function(){
return this.nativeSel.rangeCount !== 0 ;
},
deleteContents : function(){
this.nativeRange.deleteContents();
return this._updateBoundary();
},
select:function(){
var start = this.nativeRange.startContainer;
if(start.nodeType == 1 && start.childNodes.length === 0){
var char = document.createTextNode('\u200b');
start.appendChild(char);
this.nativeRange.setStart(char,1);
this.nativeRange.collapse(true);
}else if(this.collapsed && start.nodeType == 1){
start = start.childNodes[this.startOffset];
if(start && start.nodeType == 3 && start.nodeValue.length === 0){
this.nativeRange.setStart(start,1);
this.nativeRange.collapse(true);
}
}
try{
this.nativeSel.removeAllRanges();
}catch(e){
}
this.nativeSel.addRange(this.nativeRange);
return this;
},
_updateBoundary : function(){
var nRange = this.nativeRange;
this.startContainer = nRange.startContainer;
this.startContainer = nRange.startContainer;
this.endContainer = nRange.endContainer;
this.startOffset = nRange.startOffset;
this.endOffset = nRange.endOffset;
this.collapsed = nRange.collapsed;
return this;
},
setStartOffset:function(offset){
setBoundary(this,offset,'Start');
return this;
},
setEndOffset:function(offset){
setBoundary(this,offset,'End');
return this;
},
setStart:function(node,offset){
this.nativeRange.setStart(node,offset);
this._updateBoundary();
return this;
},
setStartAfter:function(node){
return this.setStart(node.parentNode,utils.getNodeIndex(node) + 1);
},
setStartBefore:function(node){
return this.setStart(node.parentNode,utils.getNodeIndex(node));
},
setEnd:function(node,offset){
this.nativeRange.setEnd(node,offset);
this._updateBoundary();
return this;
},
update:function(){
this.updateNativeRange()
._updateBoundary();
return this;
},
getStart:function(){
this.update();
return {
startContainer:this.startContainer,
startOffset:this.startOffset
};
},
getStartOffset:function(){
return getOffset(this,'start');
},
getEndOffset:function(){
return getOffset(this,'end');
},
collapse:function(toStart){
this.nativeRange.collapse(toStart === true);
this._updateBoundary();
return this;
},
isCollapsed:function(){
this._updateBoundary();
return this.collapsed;
},
insertNode:function(node){
this.nativeRange.insertNode(node);
return this._updateBoundary();
},
updateNativeRange:function(){
this.nativeRange = this.nativeSel.getRangeAt(0);
return this;
},
clear : function(){
this.nativeSel.removeAllRanges();
return this;
}
};
}());
\ No newline at end of file
//接收者
KityMinder.Receiver = kity.createClass('Receiver', {
clear: function() {
this.container.innerHTML = '';
if (this.selection) {
this.selection.setHide();
}
if (this.range) {
this.range.clear();
}
this.index = 0;
return this;
},
constructor: function(km,sel,range) {
//初始化接收者
this.setKityMinder(km);
//创建接收者容器
var _div = document.createElement('div');
_div.setAttribute('contenteditable', true);
_div.className = 'km_receiver';
this.container = _div;
utils.addCssRule('km_receiver_css',
' .km_receiver{white-space:nowrap;position:absolute;padding:0;margin:0;word-wrap:break-word;'
+ (/\?debug#?/.test(location.href)?'':'clip:rect(1em 1em 1em 1em);'));
this.index = 0;
this.selection = sel;
this.range = range;
this.range.container = _div;
},
setRange: function(range, index) {
this.index = index || this.index;
this.range = range;
range.setStartOffset(this.index);
range.collapse(true);
var me = this;
setTimeout(function() {
me.container.focus();
range.select();
});
return this;
},
setTextGroup: function(textGroup) {
this.textGroup = textGroup;
return this;
},
setKityMinder: function(km) {
this.km = km;
return this;
},
updateByMinderNode:function(node){
this.setMinderNode(node);
//追加selection到节点
this._addSelection();
//更新minderNode下的textGroup
this.setTextGroup(node.getTextGroup());
//更新接受容器的样式
this.setContainerStyle();
//更新textOffsetData数据
this.updateTextOffsetData();
//更新选取高度
this.setSelectionHeight();
//更新接收容器内容
this.setContainerTxt();
return this;
},
setMinderNode: function(node) {
this.minderNode = node;
this.selection.setMinderNode(node);
return this;
},
_addSelection:function(){
if (this.selection.container){
this.selection.remove();
}
this.minderNode.getRenderContainer().addShape(this.selection);
return this;
},
getMinderNode:function(){
return this.minderNode;
},
updateIndex: function() {
this.index = this.range.getStartOffset();
return this;
},
setSelection: function(selection) {
this.selection = selection;
return this;
},
updateSelection: function(offset) {
this.selection.update(this.textData,offset);
return this;
},
getOffsetByIndex:function(index){
return utils.getValueByIndex(this.textData, index !== undefined ? index : this.index);
},
getBaseOffset: function() {
var offset = this.textGroup.getRenderBox('screen');
return offset;
},
setContainerStyle: function() {
var textGroupBox = this.getBaseOffset();
this.container.style.cssText = ';left:' + (kity.Browser.ipad ? '-' : '') +
textGroupBox.x + 'px;top:' + (textGroupBox.y + (/\?debug#?/.test(location.href)?this.textGroup.getItems().length * this.getlineHeight():0)) +
'px;width:' + textGroupBox.width + 'px;height:' + textGroupBox.height + 'px;';
return this;
},
updateTextOffsetData: function() {
var me = this;
var fontHeight = this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size');
var lineHeight = this.minderNode.getStyle('line-height') * fontHeight;
var offsetHeight = (me.textGroup.getShapes().length * lineHeight - (lineHeight - fontHeight)) / 2;
var box;
this.textData = [];
me.textGroup.eachItem(function(index,textShape){
me.textData[index] = [];
var currentLineTop = index * lineHeight + 1;
var text = textShape.getContent();
for (var i = 0, l = text.length; i < l; i++) {
try {
box = textShape.getExtentOfChar(i);
} catch (e) {
console.log(e);
}
me.textData[index].push({
x: box.x ,
y: currentLineTop - offsetHeight,
width: box.width,
height: box.height
});
}
if(text.length === 0){
me.textData[index].push({
x: 0,
y: currentLineTop - offsetHeight,
width: 0,
height:lineHeight
});
}
});
return this;
},
getlineHeight:function(){
return this.minderNode.getStyle('line-height') * (this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size'));
},
updateIndexByMouse : function(offset) {
var me = this;
//更新文本字符坐标
me.updateTextOffsetData();
this.index = 0;
var lineHeight = this.getlineHeight();
utils.each(this.textData,function(l,arr){
var first = arr[0];
//确定行号
if(first.y <= offset.y && first.y + lineHeight >= offset.y){
utils.each(arr,function(i,v){
//点击开始之前
if (i === 0 && offset.x <= v.x) {
return false;
}
if (offset.x >= v.x && offset.x <= v.x + v.width) {
if (offset.x - v.x > v.width / 2) {
me.index += i + 1;
} else {
me.index += i;
}
return false;
}
if (i == arr.length - 1 && offset.x >= v.x) {
me.index += (arr.length == 1 && arr[0].width === 0 ? 0 : arr.length);
return false;
}
});
return false;
}else{
me.index += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
return;
}
});
this.selection.setStartOffset(this.index).collapse(true);
return this;
},
setSelectionHeight: function() {
this.selection.setHeight((this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size')) * 1);
return this;
},
updateSelectionByMousePosition: function(offset) {
var me = this;
var result = 0;
var lineHeight = this.getlineHeight();
utils.each(this.textData,function(l,arr){
var first = arr[0];
//确定行号
if(first.y <= offset.y && first.y + lineHeight >= offset.y){
utils.each(arr,function(i,v){
//点击开始之前
if (i === 0 && offset.x <= v.x) {
return false;
}
if (offset.x >= v.x && offset.x <= v.x + v.width) {
result += i;
if (offset.x - v.x > v.width / 2) {
result += 1;
}
return false;
}
if (i == arr.length - 1 && offset.x >= v.x) {
result += (arr.length == 1 && arr[0].width === 0 ? 0 : arr.length);
return false;
}
});
return false;
}else{
if(first.y > offset.y && l === 0){
result = 0;
return false;
}else if(l == me.textData.length - 1 && first.y + lineHeight < offset.y){
result += arr.length + 1;
return false;
}
result += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
return;
}
});
if(result < me.index){
this.selection.setStartOffset(result);
this.selection.setEndOffset(me.index);
}else if(result == me.index){
this.selection.setStartOffset(result).collapse(true);
}else{
this.selection.setStartOffset(me.index);
this.selection.setEndOffset(result);
}
return this;
},
updateRange: function() {
this.range.update();
return this;
},
updateContainerRangeBySel:function(){
var me = this;
this.range.setStartOffset(this.selection.startOffset);
this.range.setEndOffset(this.selection.endOffset);
if(kity.Browser.gecko){
this.container.focus();
setTimeout(function(){
me.range.select();
});
}else{
this.range.select();
}
return this;
},
updateSelectionByRange:function(){
this.selection.setStartOffset(this.range.getStartOffset());
this.selection.setEndOffset(this.range.getEndOffset());
return this;
},
setIndex: function(index) {
this.index = index;
return this;
},
setContainerTxt: function(txt) {
function encodeHtml(text) {
return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
if(txt){
txt = encodeHtml(txt);
txt = txt.replace(/[\n]/g,'<br\/>');
}else{
txt = '';
this.textGroup.eachItem(function(i,item){
txt += encodeHtml(item.getContent()) + '<br/>';
});
}
this.container.innerHTML = txt;
return this;
},
setReady:function(){
this._ready = true;
},
clearReady:function(){
this._ready = false;
},
isReady:function(){
return this._ready;
},
focus:function(){
this.container.focus();
},
getTxtOfContainer:function(){
var result = '',cont = this.container;
utils.each(cont.childNodes,function(i,n){
if(n.nodeType == 3){
result += n.nodeValue.replace(/[\u200b]/g, '');
}else{
if(n !== cont.lastChild)
result += '\n';
}
});
return result;
}
});
\ No newline at end of file
//模拟光标
KityMinder.Selection = kity.createClass( 'Selection', {
base: kity.Path,
constructor: function ( height, color, width ) {
this.callBase();
this.height = height || 20;
this.setAttr('id','_kity_selection');
this.width = 2;
this.fill('rgb(27,171,255)');
this.setHide();
this.timer = null;
this.collapsed = true;
this.startOffset = this.endOffset = 0;
this.setOpacity(0.5);
this.setStyle('cursor','text');
this._show = false;
this.offset = [];
this.setTranslate(-0.5, -1.5);
},
setMinderNode : function(node){
this.minderNode = node;
},
setColor:function(color){
this.fill(color);
},
updateOffsetByTextData:function(data,offset){
if(this.collapsed){
this.offset = utils.getValueByIndex(data,this.startOffset);
return this;
}else{
var arrOffset = [],tmpOffset = {},
startOffset = this.startOffset,
endOffset = this.endOffset,
cIndex = 0;
utils.each(data,function(l,arr){
tmpOffset = {
width:0,
x:0,
y:0
};
utils.each(arr,function(i,o){
if(cIndex >= startOffset && cIndex <= endOffset){
if(i === 0 || cIndex === startOffset){
tmpOffset.x = o.x;
tmpOffset.y = o.y;
tmpOffset.width = o.width;
//i === 0 && offset && offset.x <= o.x && cIndex != startOffset ? 0 :
}else if(cIndex < endOffset){
tmpOffset.width += o.width;
}else if(cIndex === endOffset){
return false;
}
}
cIndex++;
});
if(tmpOffset.x !== undefined) {
arrOffset.push(tmpOffset);
}
if(cIndex === endOffset) {
return false;
}
if(arr.length == 1 && arr[0].width === 0)
return;
cIndex++;
});
this.offset = arrOffset;
return this;
}
this._show = true;
},
updatePosition: function(offset){
var me = this;
var r = Math.round;
var rect = function (x, y, w, h) {
return ['M', r(x), r(y),
'h', r(w),
'v', r(h),
'h', -r(w),
'v', -r(h),
'z'];
};
offset = offset !== undefined ? offset : this.offset;
if(this.collapsed){
if (isNaN(offset.x) || isNaN(offset.y)) {
if (console) console.warn('editor.selection.js 不正确的偏移位置');
return this;
}
this.setPathData(rect(offset.x, offset.y, this.width, this.height));
} else {
this.setPathData(offset.reduce(function (prev, current) {
return prev.concat(rect(current.x, current.y, current.width, me.height));
}, []));
}
this._show = true;
return this;
},
collapse : function(toStart){
this.setOpacity(1);
this.collapsed = true;
if(toStart){
this.endOffset = this.startOffset;
}else{
this.startOffset = this.endOffset;
}
return this;
},
setStartOffset:function(offset){
this.startOffset = offset;
if(this.startOffset >= this.endOffset){
this.collapse(true);
return this;
}
this.collapsed = false;
this.setOpacity(0.5);
return this;
},
setEndOffset:function(offset){
this.endOffset = offset;
if(this.endOffset <= this.startOffset){
this.startOffset = offset;
this.collapse(true);
return this;
}
this.collapsed = false;
this.setOpacity(0.5);
return this;
},
update : function(data,offset){
if(data){
this.updateOffsetByTextData(data,offset);
}
this.updatePosition();
this.setShow();
return this;
},
setHeight: function ( height ) {
this.height = Math.round(height) + 2;
return this;
},
setHide: function () {
clearInterval( this.timer );
this.setStyle( 'display', 'none' );
this._show = false;
return this;
},
setHoldShow:function(){
this.setStyle('display','');
clearInterval(this.timer);
return this;
},
setShow: function () {
this.bringTop();
clearInterval( this.timer );
var me = this,
state = '';
me.setStyle( 'display', '' );
me._show = true;
if(this.collapsed){
me.setOpacity(1);
this.timer = setInterval( function () {
me.setStyle( 'display', state );
state = state ? '' : 'none';
}, 400 );
}
return this;
},
setShowStatus:function(){
this._show = true;
return this;
},
isShow:function(){
return this._show;
},
isHide:function(){
return !this._show;
}
} );
\ No newline at end of file
/* global Renderer: true */ define(function(require, exports, module) {
var kity = require('core/kity');
KityMinder.registerModule('Expand', function() { var utils = require('core/utils');
var minder = this; var keymap = require('core/keymap');
var EXPAND_STATE_DATA = 'expandState', var MinderNode = require('core/node');
STATE_EXPAND = 'expand', var Command = require('core/command');
STATE_COLLAPSE = 'collapse'; var Module = require('core/module');
var Renderer = require('core/render');
// 将展开的操作和状态读取接口拓展到 MinderNode 上
kity.extendClass(MinderNode, { Module.register('Expand', function() {
var minder = this;
/** var EXPAND_STATE_DATA = 'expandState',
* 展开节点 STATE_EXPAND = 'expand',
* @param {Policy} policy 展开的策略,默认为 KEEP_STATE STATE_COLLAPSE = 'collapse';
*/
expand: function() { // 将展开的操作和状态读取接口拓展到 MinderNode 上
this.setData(EXPAND_STATE_DATA, STATE_EXPAND); kity.extendClass(MinderNode, {
return this;
}, /**
* 展开节点
/** * @param {Policy} policy 展开的策略,默认为 KEEP_STATE
* 收起节点 */
*/ expand: function() {
collapse: function() { this.setData(EXPAND_STATE_DATA, STATE_EXPAND);
this.setData(EXPAND_STATE_DATA, STATE_COLLAPSE); return this;
return this; },
},
/**
* 判断节点当前的状态是否为展开
*/
isExpanded: function() {
var expanded = this.getData(EXPAND_STATE_DATA) !== STATE_COLLAPSE;
return expanded && (this.isRoot() || this.parent.isExpanded());
},
/**
* 判断节点当前的状态是否为收起
*/
isCollapsed: function() {
return !this.isExpanded();
}
});
var ExpandCommand = kity.createClass('ExpandCommand', { /**
base: Command, * 收起节点
*/
collapse: function() {
this.setData(EXPAND_STATE_DATA, STATE_COLLAPSE);
return this;
},
execute: function(km, justParents) { /**
var node = km.getSelectedNode(); * 判断节点当前的状态是否为展开
if (!node) return; */
if (justParents) { isExpanded: function() {
node = node.parent; var expanded = this.getData(EXPAND_STATE_DATA) !== STATE_COLLAPSE;
} return expanded && (this.isRoot() || this.parent.isExpanded());
while(node.parent) { },
node.expand();
node = node.parent;
}
node.renderTree();
km.layout(100);
},
queryState: function(km) { /**
return km.getSelectedNode() ? 0 : -1; * 判断节点当前的状态是否为收起
} */
}); isCollapsed: function() {
return !this.isExpanded();
}
});
var ExpandToLevelCommand = kity.createClass('ExpandToLevelCommand', { var ExpandCommand = kity.createClass('ExpandCommand', {
base: Command, base: Command,
execute: function(km, level) {
km.getRoot().traverse(function(node) {
if (node.getLevel() < level) node.expand();
if (node.getLevel() == level) node.collapse();
});
km.refresh(100);
},
enableReadOnly: true
});
var Expander = kity.createClass('Expander', { execute: function(km, justParents) {
base: kity.Group, var node = km.getSelectedNode();
if (!node) return;
constructor: function(node) { if (justParents) {
this.callBase(); node = node.parent;
this.radius = 6; }
this.outline = new kity.Circle(this.radius).stroke('gray').fill('white'); while(node.parent) {
this.sign = new kity.Path().stroke('gray');
this.addShapes([this.outline, this.sign]);
this.initEvent(node);
this.setId(KityMinder.uuid('node_expander'));
this.setStyle('cursor', 'pointer');
},
initEvent: function(node) {
this.on('mousedown', function(e) {
if (node.isExpanded()) {
node.collapse();
} else {
node.expand(); node.expand();
node = node.parent;
} }
node.renderTree().getMinder().layout(100); node.renderTree();
node.getMinder().fire('contentchange'); km.layout(100);
e.stopPropagation(); },
e.preventDefault();
}); queryState: function(km) {
this.on('dblclick click mouseup', function(e) { return km.getSelectedNode() ? 0 : -1;
e.stopPropagation();
e.preventDefault();
});
},
setState: function(state) {
if (state == 'hide') {
this.setVisible(false);
return;
}
this.setVisible(true);
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); });
}
}); var ExpandToLevelCommand = kity.createClass('ExpandToLevelCommand', {
base: Command,
execute: function(km, level) {
km.getRoot().traverse(function(node) {
if (node.getLevel() < level) node.expand();
if (node.getLevel() == level) node.collapse();
});
km.refresh(100);
},
enableReadOnly: true
});
var Expander = kity.createClass('Expander', {
base: kity.Group,
constructor: function(node) {
this.callBase();
this.radius = 6;
this.outline = new kity.Circle(this.radius).stroke('gray').fill('white');
this.sign = new kity.Path().stroke('gray');
this.addShapes([this.outline, this.sign]);
this.initEvent(node);
this.setId(utils.uuid('node_expander'));
this.setStyle('cursor', 'pointer');
},
var ExpanderRenderer = kity.createClass('ExpanderRenderer', { initEvent: function(node) {
base: Renderer, this.on('mousedown', function(e) {
if (node.isExpanded()) {
node.collapse();
} else {
node.expand();
}
node.renderTree().getMinder().layout(100);
node.getMinder().fire('contentchange');
e.stopPropagation();
e.preventDefault();
});
this.on('dblclick click mouseup', function(e) {
e.stopPropagation();
e.preventDefault();
});
},
create: function(node) { setState: function(state) {
if (node.isRoot()) return; if (state == 'hide') {
this.expander = new Expander(node); this.setVisible(false);
node.getRenderContainer().prependShape(this.expander); return;
node.expanderRenderer = this; }
this.node = node; this.setVisible(true);
return this.expander; 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);
}
});
var ExpanderRenderer = kity.createClass('ExpanderRenderer', {
base: Renderer,
create: function(node) {
if (node.isRoot()) return;
this.expander = new Expander(node);
node.getRenderContainer().prependShape(this.expander);
node.expanderRenderer = this;
this.node = node;
return this.expander;
},
shouldRender: function(node) { shouldRender: function(node) {
return !node.isRoot(); return !node.isRoot();
}, },
update: function(expander, node, box) { update: function(expander, node, box) {
if (!node.parent) return; if (!node.parent) return;
var visible = node.parent.isExpanded(); var visible = node.parent.isExpanded();
expander.setState(visible && node.children.length ? node.getData(EXPAND_STATE_DATA) : 'hide'); expander.setState(visible && node.children.length ? node.getData(EXPAND_STATE_DATA) : 'hide');
var vector = node.getLayoutVectorIn().normalize(expander.radius + node.getStyle('stroke-width')); var vector = node.getLayoutVectorIn().normalize(expander.radius + node.getStyle('stroke-width'));
var position = node.getVertexIn().offset(vector.reverse()); var position = node.getVertexIn().offset(vector.reverse());
this.expander.setTranslate(position); this.expander.setTranslate(position);
} }
}); });
return { return {
commands: { commands: {
'expand': ExpandCommand, 'expand': ExpandCommand,
'expandtolevel': ExpandToLevelCommand 'expandtolevel': ExpandToLevelCommand
}, },
events: { events: {
'layoutapply': function(e) { 'layoutapply': function(e) {
var r = e.node.getRenderer('ExpanderRenderer'); var r = e.node.getRenderer('ExpanderRenderer');
if (r.getRenderShape()) { if (r.getRenderShape()) {
r.update(r.getRenderShape(), e.node); r.update(r.getRenderShape(), e.node);
}
},
'beforerender': function(e) {
var node = e.node;
var visible = !node.parent || node.parent.isExpanded();
var minder = this;
node.getRenderContainer().setVisible(visible);
if (!visible) e.stopPropagation();
},
'normal.keydown': function(e) {
if (this.getStatus() == 'textedit') return;
if (e.originEvent.keyCode == keymap['/']) {
var node = this.getSelectedNode();
if (!node || node == this.getRoot()) return;
var expanded = node.isExpanded();
this.getSelectedNodes().forEach(function(node) {
if (expanded) node.collapse();
else node.expand();
node.renderTree();
});
this.layout(100);
this.fire('contentchange');
e.preventDefault();
e.stopPropagationImmediately();
}
if (e.isShortcutKey('Alt+`')) {
this.execCommand('expandtolevel', 9999);
}
for (var i = 1; i < 6; i++) {
if (e.isShortcutKey('Alt+' + i)) {
this.execCommand('expandtolevel', i);
}
}
} }
}, },
'beforerender': function(e) { renderers: {
var node = e.node; outside: ExpanderRenderer
var visible = !node.parent || node.parent.isExpanded();
var minder = this;
node.getRenderContainer().setVisible(visible);
if (!visible) e.stopPropagation();
}, },
'normal.keydown': function(e) { contextmenu: [{
if (this.getStatus() == 'textedit') return; command: 'expandtoleaf',
if (e.originEvent.keyCode == keymap['/']) { query: function() {
var node = this.getSelectedNode(); return !minder.getSelectedNode();
if (!node || node == this.getRoot()) return; },
var expanded = node.isExpanded(); fn: function(minder) {
this.getSelectedNodes().forEach(function(node) { minder.execCommand('expandtolevel', 9999);
if (expanded) node.collapse();
else node.expand();
node.renderTree();
});
this.layout(100);
this.fire('contentchange');
e.preventDefault();
e.stopPropagationImmediately();
} }
if (e.isShortcutKey('Alt+`')) { }, {
this.execCommand('expandtolevel', 9999); command: 'expandtolevel1',
query: function() {
return !minder.getSelectedNode();
},
fn: function(minder) {
minder.execCommand('expandtolevel', 1);
} }
for (var i = 1; i < 6; i++) { }, {
if (e.isShortcutKey('Alt+' + i)) { command: 'expandtolevel2',
this.execCommand('expandtolevel', i); query: function() {
} return !minder.getSelectedNode();
},
fn: function(minder) {
minder.execCommand('expandtolevel', 2);
} }
} },{
}, command: 'expandtolevel3',
renderers: { query: function() {
outside: ExpanderRenderer return !minder.getSelectedNode();
}, },
contextmenu: [{ fn: function(minder) {
command: 'expandtoleaf', minder.execCommand('expandtolevel', 3);
query: function() { }
return !minder.getSelectedNode(); }, {
}, divider: true
fn: function(minder) { }]
minder.execCommand('expandtolevel', 9999); };
} });
}, {
command: 'expandtolevel1',
query: function() {
return !minder.getSelectedNode();
},
fn: function(minder) {
minder.execCommand('expandtolevel', 1);
}
}, {
command: 'expandtolevel2',
query: function() {
return !minder.getSelectedNode();
},
fn: function(minder) {
minder.execCommand('expandtolevel', 2);
}
},{
command: 'expandtolevel3',
query: function() {
return !minder.getSelectedNode();
},
fn: function(minder) {
minder.execCommand('expandtolevel', 3);
}
}, {
divider: true
}]
};
}); });
\ No newline at end of file
KityMinder.registerModule("fontmodule", function() { define(function(require, exports, module) {
var kity = require('core/kity');
var utils = require('core/utils');
var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
var TextRenderer = require('./text');
function getNodeDataOrStyle(node, name) { function getNodeDataOrStyle(node, name) {
return node.getData(name) || node.getStyle(name); return node.getData(name) || node.getStyle(name);
} }
KityMinder.TextRenderer.registerStyleHook(function(node, textGroup) { TextRenderer.registerStyleHook(function(node, textGroup) {
var dataColor = node.getData('color'); var dataColor = node.getData('color');
var selectedColor = node.getStyle('selected-color'); var selectedColor = node.getStyle('selected-color');
var styleColor = node.getStyle('color'); var styleColor = node.getStyle('color');
...@@ -11,144 +21,102 @@ KityMinder.registerModule("fontmodule", function() { ...@@ -11,144 +21,102 @@ KityMinder.registerModule("fontmodule", function() {
var foreColor = dataColor || (node.isSelected() && selectedColor ? selectedColor : styleColor); var foreColor = dataColor || (node.isSelected() && selectedColor ? selectedColor : styleColor);
var fontFamily = getNodeDataOrStyle(node, 'font-family'); var fontFamily = getNodeDataOrStyle(node, 'font-family');
var fontSize = getNodeDataOrStyle(node, 'font-size'); var fontSize = getNodeDataOrStyle(node, 'font-size');
var fontHash = [fontFamily, fontSize].join('/');
textGroup.fill(foreColor); textGroup.fill(foreColor);
node.setTmpData('fore-color', foreColor.toString());
textGroup.eachItem(function(index,item){ textGroup.eachItem(function(index, item) {
item.setFont({ item.setFont({
'family': fontFamily, 'family': fontFamily,
'size': fontSize 'size': fontSize
}); });
}); });
node.setTmpData('font-hash', fontHash);
}); });
return {
defaultOptions: {
'fontfamily': [{
name: '宋体',
val: '宋体,SimSun'
}, {
name: '微软雅黑',
val: '微软雅黑,Microsoft YaHei'
}, {
name: '楷体',
val: '楷体,楷体_GB2312,SimKai'
}, {
name: '黑体',
val: '黑体, SimHei'
}, {
name: '隶书',
val: '隶书, SimLi'
}, {
name: 'Andale Mono',
val: 'andale mono'
}, {
name: 'Arial',
val: 'arial,helvetica,sans-serif'
}, {
name: 'arialBlack',
val: 'arial black,avant garde'
}, {
name: 'Comic Sans Ms',
val: 'comic sans ms'
}, {
name: 'Impact',
val: 'impact,chicago'
}, {
name: 'Times New Roman',
val: 'times new roman'
}, {
name: 'Sans-Serif',
val: 'sans-serif'
}],
'fontsize': [10, 12, 16, 18, 24, 32, 48]
},
"commands": {
"forecolor": kity.createClass("fontcolorCommand", {
base: Command,
execute: function(km, color) { Module.register('fontmodule', {
var nodes = km.getSelectedNodes(); defaultOptions: {
utils.each(nodes, function(i, n) { 'commands': {
n.setData('color', color); 'forecolor': kity.createClass('fontcolorCommand', {
n.render(); base: Command,
}); execute: function(km, color) {
}, var nodes = km.getSelectedNodes();
queryState: function(km) { nodes.forEach(function(n) {
return km.getSelectedNodes().length == 0 ? -1 : 0 n.setData('color', color);
}, n.render();
queryValue: function(km) { });
if (km.getSelectedNodes().length == 1) { },
return km.getSelectedNodes()[0].getData('color'); queryState: function(km) {
return km.getSelectedNodes().length === 0 ? -1 : 0;
},
queryValue: function(km) {
if (km.getSelectedNodes().length == 1) {
return km.getSelectedNodes()[0].getData('color');
}
return 'mixed';
} }
return 'mixed';
}
}), }),
"background": kity.createClass("backgroudCommand", { 'background': kity.createClass('backgroudCommand', {
base: Command, base: Command,
execute: function(km, color) { execute: function(km, color) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('background', color); n.setData('background', color);
n.render(); n.render();
}); });
}, },
queryState: function(km) { queryState: function(km) {
return km.getSelectedNodes().length == 0 ? -1 : 0 return km.getSelectedNodes().length === 0 ? -1 : 0;
}, },
queryValue: function(km) { queryValue: function(km) {
if (km.getSelectedNodes().length == 1) { if (km.getSelectedNodes().length == 1) {
return km.getSelectedNodes()[0].getData('background'); return km.getSelectedNodes()[0].getData('background');
}
return 'mixed';
} }
return 'mixed'; }),
} 'fontfamily': kity.createClass('fontfamilyCommand', {
base: Command,
}),
"fontfamily": kity.createClass("fontfamilyCommand", {
base: Command,
execute: function(km, family) { execute: function(km, family) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-family', family); n.setData('font-family', family);
n.render(); n.render();
km.layout(); km.layout();
}); });
}, },
queryState: function(km) { queryState: function(km) {
return km.getSelectedNodes().length === 0 ? -1 : 0 return km.getSelectedNodes().length === 0 ? -1 : 0;
}, },
queryValue: function(km) { queryValue: function(km) {
var node = km.getSelectedNode(); var node = km.getSelectedNode();
if (node) return node.getData('font-family'); if (node) return node.getData('font-family');
return null; return null;
} }
}), }),
"fontsize": kity.createClass("fontsizeCommand", { 'fontsize': kity.createClass('fontsizeCommand', {
base: Command, base: Command,
execute: function(km, size) { execute: function(km, size) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('font-size', size); n.setData('font-size', size);
n.render(); n.render();
km.layout(300); km.layout(300);
}); });
}, },
queryState: function(km) { queryState: function(km) {
return km.getSelectedNodes().length == 0 ? -1 : 0 return km.getSelectedNodes().length === 0 ? -1 : 0;
}, },
queryValue: function(km) { queryValue: function(km) {
var node = km.getSelectedNode(); var node = km.getSelectedNode();
if (node) return node.getData('font-size'); if (node) return node.getData('font-size');
return null; return null;
} }
}) })
}
} }
}; });
}); });
\ No newline at end of file
KityMinder.registerModule("HistoryModule", function() { define(function(require, exports, module) {
var kity = require('core/kity');
var utils = require('core/utils');
var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
function compareObject(source, target) {
var tmp;
if (isEmptyObject(source) !== isEmptyObject(target)) {
return false;
}
if (getObjectLength(source) != getObjectLength(target)) {
return false;
}
for (var p in source) {
if (source.hasOwnProperty(p)) {
tmp = source[p];
if (target[p] === undefined) {
return false;
}
if (this.isObject(tmp) || this.isArray(tmp)) {
if (this.isObject(target[p]) !== this.isObject(tmp)) {
return false;
}
if (this.isArray(tmp) !== this.isArray(target[p])) {
return false;
}
if (this.compareObject(tmp, target[p]) === false) {
return false;
}
} else {
if (tmp != target[p]) {
return false;
}
}
}
}
return true;
}
function getObjectLength(obj) {
if (utils.isArray(obj) || utils.isString(obj)) return obj.length;
var count = 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) count++;
return count;
}
function isEmptyObject(obj) {
if (obj === null || obj === undefined) return true;
if (utils.isArray(obj) || utils.isString(obj)) return obj.length === 0;
for (var key in obj)
if (obj.hasOwnProperty(key)) return false;
return true;
}
function getValueByIndex(data, index) {
var initIndex = 0,
result = 0;
data.forEach(function(arr, i) {
if (initIndex + arr.length >= index) {
if (index - initIndex == arr.length) {
if (arr.length == 1 && arr[0].width === 0) {
initIndex++;
return;
}
result = {
x: arr[arr.length - 1].x + arr[arr.length - 1].width,
y: arr[arr.length - 1].y
};
} else {
result = arr[index - initIndex];
}
return false;
} else {
initIndex += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
}
});
return result;
}
function getNodeIndex(node, ignoreTextNode) {
var preNode = node,
i = 0;
while (preNode = preNode.previousSibling) {
if (ignoreTextNode && preNode.nodeType == 3) {
if (preNode.nodeType != preNode.nextSibling.nodeType) {
i++;
}
continue;
}
i++;
}
return i;
}
var km = this; var km = this;
var Scene = kity.createClass('Scene', { var Scene = kity.createClass('Scene', {
constructor: function(root,inputStatus) { constructor: function(root, inputStatus) {
this.data = root.clone(); this.data = root.clone();
this.inputStatus = inputStatus; this.inputStatus = inputStatus;
}, },
...@@ -14,12 +115,12 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -14,12 +115,12 @@ KityMinder.registerModule("HistoryModule", function() {
return this.getData().clone(); return this.getData().clone();
}, },
equals: function(scene) { equals: function(scene) {
return this.getData().equals(scene.getData()); return this.getData().compareTo(scene.getData());
}, },
isInputStatus:function(){ isInputStatus: function() {
return this.inputStatus; return this.inputStatus;
}, },
setInputStatus:function(status){ setInputStatus: function(status) {
this.inputStatus = status; this.inputStatus = status;
} }
}); });
...@@ -35,13 +136,13 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -35,13 +136,13 @@ KityMinder.registerModule("HistoryModule", function() {
if (this.hasUndo) { if (this.hasUndo) {
var currentScene = this.list[this.index]; var currentScene = this.list[this.index];
//如果是输入文字时的保存,直接回复当前场景 //如果是输入文字时的保存,直接回复当前场景
if(currentScene && currentScene.isInputStatus()){ if (currentScene && currentScene.isInputStatus()) {
this.saveScene(); this.saveScene();
this.restore(--this.index); this.restore(--this.index);
currentScene.setInputStatus(false); currentScene.setInputStatus(false);
return; return;
} }
if(this.list.length == 1){ if (this.list.length == 1) {
this.restore(0); this.restore(0);
return; return;
} }
...@@ -71,14 +172,12 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -71,14 +172,12 @@ KityMinder.registerModule("HistoryModule", function() {
}, },
partialRenewal: function(target) { partialRenewal: function(target) {
var selectedNodes = []; var selectedNodes = [];
function compareNode(source, target) { function compareNode(source, target) {
if (source.getText() != target.getText()) { if (source.getText() != target.getText()) {
return false; return false;
} }
if (utils.compareObject(source.getData(), target.getData()) === false) { if (compareObject(source.getData(), target.getData()) === false) {
return false;
}
if (utils.compareObject(source.getTmpData(), target.getTmpData()) === false) {
return false; return false;
} }
return true; return true;
...@@ -91,7 +190,7 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -91,7 +190,7 @@ KityMinder.registerModule("HistoryModule", function() {
km.appendNode(child, parent); km.appendNode(child, parent);
child.render(); child.render();
var children = utils.cloneArr(child.children); var children = child.children.slice();
for (var i = 0, ci; ci = children[i++];) { for (var i = 0, ci; ci = children[i++];) {
appendChildNode(child, ci); appendChildNode(child, ci);
} }
...@@ -121,10 +220,11 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -121,10 +220,11 @@ KityMinder.registerModule("HistoryModule", function() {
} }
} }
var km = this.km;
traverseNode(km.getRoot(), target); traverseNode(km.getRoot(), target);
km.layout(200); km.layout(200);
km.select(selectedNodes,true); km.select(selectedNodes, true);
selectedNodes = []; selectedNodes = [];
...@@ -138,13 +238,13 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -138,13 +238,13 @@ KityMinder.registerModule("HistoryModule", function() {
this.km.fire('contentChange'); this.km.fire('contentChange');
}, },
getScene: function(inputStatus) { getScene: function(inputStatus) {
return new Scene(this.km.getRoot(),inputStatus); return new Scene(this.km.getRoot(), inputStatus);
}, },
saveScene: function(inputStatus) { saveScene: function(inputStatus) {
var currentScene = this.getScene(inputStatus); var currentScene = this.getScene(inputStatus);
var lastScene = this.list[this.index]; var lastScene = this.list[this.index];
if (lastScene && lastScene.equals(currentScene)) { if (lastScene && lastScene.equals(currentScene)) {
if(inputStatus){ if (inputStatus) {
lastScene.setInputStatus(true); lastScene.setInputStatus(true);
this.update(); this.update();
} }
...@@ -153,7 +253,7 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -153,7 +253,7 @@ KityMinder.registerModule("HistoryModule", function() {
this.list = this.list.slice(0, this.index + 1); this.list = this.list.slice(0, this.index + 1);
this.list.push(currentScene); this.list.push(currentScene);
//如果大于最大数量了,就把最前的剔除 //如果大于最大数量了,就把最前的剔除
if (this.list.length > this.km.getOptions('maxUndoCount')) { if (this.list.length > this.km.getOption('maxUndoCount')) {
this.list.shift(); this.list.shift();
} }
this.index = this.list.length - 1; this.index = this.list.length - 1;
...@@ -165,7 +265,7 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -165,7 +265,7 @@ KityMinder.registerModule("HistoryModule", function() {
this.hasRedo = !!this.list[this.index + 1]; this.hasRedo = !!this.list[this.index + 1];
this.hasUndo = !!this.list[this.index - 1]; this.hasUndo = !!this.list[this.index - 1];
var currentScene = this.list[this.index]; var currentScene = this.list[this.index];
if(currentScene && currentScene.isInputStatus()){ if (currentScene && currentScene.isInputStatus()) {
this.hasUndo = true; this.hasUndo = true;
} }
...@@ -177,57 +277,61 @@ KityMinder.registerModule("HistoryModule", function() { ...@@ -177,57 +277,61 @@ KityMinder.registerModule("HistoryModule", function() {
this.hasRedo = false; this.hasRedo = false;
} }
}); });
//为km实例添加history管理
this.historyManager = new HistoryManager(this);
Module.register('HistoryModule', function() {
return { //为km实例添加history管理
defaultOptions: { this.historyManager = new HistoryManager(this);
maxUndoCount: 20,
maxInputCount: 20
},
"commands": {
"undo": kity.createClass("UndoCommand", {
base: Command,
execute: function(km) { return {
km.historyManager.undo(); defaultOptions: {
}, maxUndoCount: 20,
maxInputCount: 20
},
"commands": {
"undo": kity.createClass("UndoCommand", {
base: Command,
queryState: function(km) { execute: function(km) {
return km.historyManager.hasUndo ? 0 : -1; km.historyManager.undo();
}, },
isNeedUndo: function() { queryState: function(km) {
return false; return km.historyManager.hasUndo ? 0 : -1;
} },
}),
"redo": kity.createClass("RedoCommand", {
base: Command,
execute: function(km) { isNeedUndo: function() {
km.historyManager.redo(); return false;
}, }
}),
"redo": kity.createClass("RedoCommand", {
base: Command,
execute: function(km) {
km.historyManager.redo();
},
queryState: function(km) { queryState: function(km) {
return km.historyManager.hasRedo ? 0 : -1; return km.historyManager.hasRedo ? 0 : -1;
},
isNeedUndo: function() {
return false;
}
})
},
commandShortcutKeys: {
"undo": "ctrl+z", //undo
"redo": "ctrl+y" //redo
},
"events": {
"saveScene": function(e) {
this.historyManager.saveScene(e.inputStatus);
}, },
isNeedUndo: function() { "import": function() {
return false; this.historyManager.reset();
} }
})
},
commandShortcutKeys: {
"undo": "ctrl+z", //undo
"redo": "ctrl+y" //redo
},
"events": {
"saveScene": function(e) {
this.historyManager.saveScene(e.inputStatus);
},
"import": function() {
this.historyManager.reset();
} }
} };
}; });
}); });
\ No newline at end of file
KityMinder.registerModule("hyperlink", function() { define(function(require, exports, module) {
var linkShapePath = "M16.614,10.224h-1.278c-1.668,0-3.07-1.07-3.599-2.556h4.877c0.707,0,1.278-0.571,1.278-1.278V3.834 c0-0.707-0.571-1.278-1.278-1.278h-4.877C12.266,1.071,13.668,0,15.336,0h1.278c2.116,0,3.834,1.716,3.834,3.834V6.39 C20.448,8.508,18.73,10.224,16.614,10.224z M5.112,5.112c0-0.707,0.573-1.278,1.278-1.278h7.668c0.707,0,1.278,0.571,1.278,1.278 S14.765,6.39,14.058,6.39H6.39C5.685,6.39,5.112,5.819,5.112,5.112z M2.556,3.834V6.39c0,0.707,0.573,1.278,1.278,1.278h4.877 c-0.528,1.486-1.932,2.556-3.599,2.556H3.834C1.716,10.224,0,8.508,0,6.39V3.834C0,1.716,1.716,0,3.834,0h1.278 c1.667,0,3.071,1.071,3.599,2.556H3.834C3.129,2.556,2.556,3.127,2.556,3.834z"; var kity = require('core/kity');
return { var utils = require('core/utils');
"commands": {
"hyperlink": kity.createClass("hyperlink", { var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
var Renderer = require('core/render');
// jscs:disable maximumLineLength
var linkShapePath = 'M16.614,10.224h-1.278c-1.668,0-3.07-1.07-3.599-2.556h4.877c0.707,0,1.278-0.571,1.278-1.278V3.834 c0-0.707-0.571-1.278-1.278-1.278h-4.877C12.266,1.071,13.668,0,15.336,0h1.278c2.116,0,3.834,1.716,3.834,3.834V6.39 C20.448,8.508,18.73,10.224,16.614,10.224z M5.112,5.112c0-0.707,0.573-1.278,1.278-1.278h7.668c0.707,0,1.278,0.571,1.278,1.278 S14.765,6.39,14.058,6.39H6.39C5.685,6.39,5.112,5.819,5.112,5.112z M2.556,3.834V6.39c0,0.707,0.573,1.278,1.278,1.278h4.877 c-0.528,1.486-1.932,2.556-3.599,2.556H3.834C1.716,10.224,0,8.508,0,6.39V3.834C0,1.716,1.716,0,3.834,0h1.278 c1.667,0,3.071,1.071,3.599,2.556H3.834C3.129,2.556,2.556,3.127,2.556,3.834z';
Module.register('hyperlink',{
'commands': {
'hyperlink': kity.createClass('hyperlink', {
base: Command, base: Command,
execute: function(km, url, title) { execute: function(km, url, title) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('hyperlink', url); n.setData('hyperlink', url);
n.setData('hyperlinkTitle', title); n.setData('hyperlinkTitle', title);
n.render(); n.render();
...@@ -20,7 +31,7 @@ KityMinder.registerModule("hyperlink", function() { ...@@ -20,7 +31,7 @@ KityMinder.registerModule("hyperlink", function() {
if (nodes.length === 0) { if (nodes.length === 0) {
return -1; return -1;
} }
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
if (n && n.getData('hyperlink')) { if (n && n.getData('hyperlink')) {
result = 0; result = 0;
return false; return false;
...@@ -36,12 +47,12 @@ KityMinder.registerModule("hyperlink", function() { ...@@ -36,12 +47,12 @@ KityMinder.registerModule("hyperlink", function() {
}; };
} }
}), }),
"unhyperlink": kity.createClass("hyperlink", { 'unhyperlink': kity.createClass('hyperlink', {
base: Command, base: Command,
execute: function(km) { execute: function(km) {
var nodes = km.getSelectedNodes(); var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
n.setData('hyperlink'); n.setData('hyperlink');
n.render(); n.render();
}); });
...@@ -54,7 +65,7 @@ KityMinder.registerModule("hyperlink", function() { ...@@ -54,7 +65,7 @@ KityMinder.registerModule("hyperlink", function() {
return -1; return -1;
} }
var link = false; var link = false;
utils.each(nodes, function(i, n) { nodes.forEach(function(n) {
if (n.getData('hyperlink')) { if (n.getData('hyperlink')) {
link = true; link = true;
return false; return false;
...@@ -69,7 +80,7 @@ KityMinder.registerModule("hyperlink", function() { ...@@ -69,7 +80,7 @@ KityMinder.registerModule("hyperlink", function() {
}, },
'renderers': { 'renderers': {
right: kity.createClass('hyperlinkrender', { right: kity.createClass('hyperlinkrender', {
base: KityMinder.Renderer, base: Renderer,
create: function() { create: function() {
...@@ -122,6 +133,5 @@ KityMinder.registerModule("hyperlink", function() { ...@@ -122,6 +133,5 @@ KityMinder.registerModule("hyperlink", function() {
} }
}) })
} }
});
};
}); });
\ No newline at end of file
KityMinder.registerModule('image', function() { define(function(require, exports, module) {
function loadImageSize(url, callback) { var kity = require('core/kity');
var img = document.createElement('img'); var utils = require('core/utils');
img.onload = function() {
callback(img.width, img.height); var Minder = require('core/minder');
}; var MinderNode = require('core/node');
img.onerror = function() { var Command = require('core/command');
callback(null); var Module = require('core/module');
}; var Renderer = require('core/render');
img.src = url;
} Module.register('image', function() {
function loadImageSize(url, callback) {
function fitImageSize(width, height, maxWidth, maxHeight) { var img = document.createElement('img');
var ratio = width / height, img.onload = function() {
fitRatio = maxWidth / maxHeight; callback(img.width, img.height);
};
// 宽高比大于最大尺寸的宽高比,以宽度为标准适应 img.onerror = function() {
if (width > maxWidth && ratio > fitRatio) { callback(null);
width = maxWidth; };
height = width / ratio; img.src = url;
} else if (height > maxHeight) {
height = maxHeight;
width = height * ratio;
} }
return { function fitImageSize(width, height, maxWidth, maxHeight) {
width: width | 0, var ratio = width / height,
height: height | 0 fitRatio = maxWidth / maxHeight;
};
} // 宽高比大于最大尺寸的宽高比,以宽度为标准适应
if (width > maxWidth && ratio > fitRatio) {
var ImageCommand = kity.createClass('ImageCommand', { width = maxWidth;
base: Command, height = width / ratio;
} else if (height > maxHeight) {
execute: function(km, url, title) { height = maxHeight;
var nodes = km.getSelectedNodes(); width = height * ratio;
loadImageSize(url, function(width, height) {
if (!width) return;
utils.each(nodes, function(i, n) {
var size = fitImageSize(
width, height,
km.getOptions('maxImageWidth'),
km.getOptions('maxImageHeight'));
n.setData('image', url);
n.setData('imageTitle', title);
n.setData('imageSize', size);
n.render();
});
km.fire("saveScene");
km.layout(300);
});
},
queryState: function(km) {
var nodes = km.getSelectedNodes(),
result = 0;
if (nodes.length === 0) {
return -1;
} }
utils.each(nodes, function(i, n) {
if (n && n.getData('image')) {
result = 0;
return false;
}
});
return result;
},
queryValue: function(km) {
var node = km.getSelectedNode();
return { return {
url: node.getData('image'), width: width | 0,
title: node.getData('imageTitle') height: height | 0
}; };
} }
});
var RemoveImageCommand = kity.createClass('RemoveImageCommand', {
base: Command,
execute: function(km) { var ImageCommand = kity.createClass('ImageCommand', {
var nodes = km.getSelectedNodes(); base: Command,
utils.each(nodes, function(i, n) {
n.setData('image').render(); execute: function(km, url, title) {
}); var nodes = km.getSelectedNodes();
km.layout(300);
}, loadImageSize(url, function(width, height) {
queryState: function(km) { if (!width) return;
var nodes = km.getSelectedNodes(); nodes.forEach(function(n) {
var size = fitImageSize(
width, height,
km.getOption('maxImageWidth'),
km.getOption('maxImageHeight'));
n.setData('image', url);
n.setData('imageTitle', title);
n.setData('imageSize', size);
n.render();
});
km.fire('saveScene');
km.layout(300);
});
if (nodes.length === 0) { },
return -1; queryState: function(km) {
var nodes = km.getSelectedNodes(),
result = 0;
if (nodes.length === 0) {
return -1;
}
nodes.forEach(function(n) {
if (n && n.getData('image')) {
result = 0;
return false;
}
});
return result;
},
queryValue: function(km) {
var node = km.getSelectedNode();
return {
url: node.getData('image'),
title: node.getData('imageTitle')
};
} }
var image = false; });
utils.each(nodes, function(i, n) {
if (n.getData('image')) { var RemoveImageCommand = kity.createClass('RemoveImageCommand', {
image = true; base: Command,
return false;
execute: function(km) {
var nodes = km.getSelectedNodes();
nodes.forEach(function(n) {
n.setData('image').render();
});
km.layout(300);
},
queryState: function(km) {
var nodes = km.getSelectedNodes();
if (nodes.length === 0) {
return -1;
} }
}); var image = false;
if (image) { nodes.forEach(function(n) {
return 0; if (n.getData('image')) {
image = true;
return false;
}
});
if (image) {
return 0;
}
return -1;
} }
return -1; });
}
});
var ImageRenderer = kity.createClass('ImageRenderer', { var ImageRenderer = kity.createClass('ImageRenderer', {
base: KityMinder.Renderer, base: Renderer,
create: function(node) { create: function(node) {
return new kity.Image(node.getData('image')); return new kity.Image(node.getData('image'));
}, },
shouldRender: function(node) { shouldRender: function(node) {
return node.getData('image'); return node.getData('image');
}, },
update: function(image, node, box) { update: function(image, node, box) {
var url = node.getData('image'); var url = node.getData('image');
var title = node.getData('imageTitle'); var title = node.getData('imageTitle');
var size = node.getData('imageSize'); var size = node.getData('imageSize');
var spaceTop = node.getStyle('space-top'); var spaceTop = node.getStyle('space-top');
if (!size) return; if (!size) return;
if (title) { if (title) {
image.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title); image.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title);
} }
var x = box.cx - size.width / 2; var x = box.cx - size.width / 2;
var y = box.y - size.height - spaceTop; var y = box.y - size.height - spaceTop;
image image
.setUrl(url) .setUrl(url)
.setX(x | 0) .setX(x | 0)
.setY(y | 0) .setY(y | 0)
.setWidth(size.width | 0) .setWidth(size.width | 0)
.setHeight(size.height | 0); .setHeight(size.height | 0);
return new kity.Box(x | 0, y | 0, size.width | 0, size.height | 0); return new kity.Box(x | 0, y | 0, size.width | 0, size.height | 0);
} }
}); });
return { return {
'defaultOptions': { 'defaultOptions': {
'maxImageWidth': 200, 'maxImageWidth': 200,
'maxImageHeight': 200 'maxImageHeight': 200
}, },
'commands': { 'commands': {
'image': ImageCommand, 'image': ImageCommand,
'removeimage': RemoveImageCommand 'removeimage': RemoveImageCommand
}, },
'renderers': { 'renderers': {
'top': ImageRenderer 'top': ImageRenderer
} }
}; };
});
}); });
\ No newline at end of file
KityMinder.registerModule('KeyboardModule', function() { define(function(require, exports, module) {
var min = Math.min, var kity = require('core/kity');
max = Math.max, var utils = require('core/utils');
abs = Math.abs, var keymap = require('core/keymap');
sqrt = Math.sqrt,
exp = Math.exp; var Minder = require('core/minder');
var MinderNode = require('core/node');
function buildPositionNetwork(root) { var Command = require('core/command');
var pointIndexes = [], var Module = require('core/module');
p; var Renderer = require('core/render');
root.traverse(function(node) {
p = node.getLayoutBox(); Module.register('KeyboardModule', function() {
var min = Math.min,
// bugfix: 不应导航到收起的节点(判断其尺寸是否存在) max = Math.max,
if (p.width && p.height) { abs = Math.abs,
pointIndexes.push({ sqrt = Math.sqrt,
left: p.x, exp = Math.exp;
top: p.y,
right: p.x + p.width, function buildPositionNetwork(root) {
bottom: p.y + p.height, var pointIndexes = [],
width: p.width, p;
height: p.height, root.traverse(function(node) {
node: node, p = node.getLayoutBox();
text: node.getText()
}); // bugfix: 不应导航到收起的节点(判断其尺寸是否存在)
if (p.width && p.height) {
pointIndexes.push({
left: p.x,
top: p.y,
right: p.x + p.width,
bottom: p.y + p.height,
width: p.width,
height: p.height,
node: node,
text: node.getText()
});
}
});
for (var i = 0; i < pointIndexes.length; i++) {
findClosestPointsFor(pointIndexes, i);
} }
});
for (var i = 0; i < pointIndexes.length; i++) {
findClosestPointsFor(pointIndexes, i);
} }
}
// 这是金泉的点子,赞!
// 求两个不相交矩形的最近距离
function getCoefedDistance(box1, box2) {
var xMin, xMax, yMin, yMax, xDist, yDist, dist, cx, cy;
xMin = min(box1.left, box2.left);
xMax = max(box1.right, box2.right);
yMin = min(box1.top, box2.top);
yMax = max(box1.bottom, box2.bottom);
xDist = xMax - xMin - box1.width - box2.width; // 这是金泉的点子,赞!
yDist = yMax - yMin - box1.height - box2.height; // 求两个不相交矩形的最近距离
function getCoefedDistance(box1, box2) {
if (xDist < 0) dist = yDist; var xMin, xMax, yMin, yMax, xDist, yDist, dist, cx, cy;
else if (yDist < 0) dist = xDist; xMin = min(box1.left, box2.left);
else dist = sqrt(xDist * xDist + yDist * yDist); xMax = max(box1.right, box2.right);
yMin = min(box1.top, box2.top);
return { yMax = max(box1.bottom, box2.bottom);
cx: dist,
cy: dist xDist = xMax - xMin - box1.width - box2.width;
}; yDist = yMax - yMin - box1.height - box2.height;
}
if (xDist < 0) dist = yDist;
else if (yDist < 0) dist = xDist;
else dist = sqrt(xDist * xDist + yDist * yDist);
return {
cx: dist,
cy: dist
};
}
function findClosestPointsFor(pointIndexes, iFind) { function findClosestPointsFor(pointIndexes, iFind) {
var find = pointIndexes[iFind]; var find = pointIndexes[iFind];
var most = {}, var most = {},
quad; quad;
var current, dist; var current, dist;
for (var i = 0; i < pointIndexes.length; i++) { for (var i = 0; i < pointIndexes.length; i++) {
if (i == iFind) continue; if (i == iFind) continue;
current = pointIndexes[i]; current = pointIndexes[i];
dist = getCoefedDistance(current, find); dist = getCoefedDistance(current, find);
// left check // left check
if (current.right < find.left) { if (current.right < find.left) {
if (!most.left || dist.cx < most.left.dist) { if (!most.left || dist.cx < most.left.dist) {
most.left = { most.left = {
dist: dist.cx, dist: dist.cx,
node: current.node node: current.node
}; };
}
} }
}
// right check // right check
if (current.left > find.right) { if (current.left > find.right) {
if (!most.right || dist.cx < most.right.dist) { if (!most.right || dist.cx < most.right.dist) {
most.right = { most.right = {
dist: dist.cx, dist: dist.cx,
node: current.node node: current.node
}; };
}
} }
}
// top check // top check
if (current.bottom < find.top) { if (current.bottom < find.top) {
if (!most.top || dist.cy < most.top.dist) { if (!most.top || dist.cy < most.top.dist) {
most.top = { most.top = {
dist: dist.cy, dist: dist.cy,
node: current.node node: current.node
}; };
}
} }
}
// bottom check // bottom check
if (current.top > find.bottom) { if (current.top > find.bottom) {
if (!most.down || dist.cy < most.down.dist) { if (!most.down || dist.cy < most.down.dist) {
most.down = { most.down = {
dist: dist.cy, dist: dist.cy,
node: current.node node: current.node
}; };
}
} }
} }
find.node._nearestNodes = {
right: most.right && most.right.node || null,
top: most.top && most.top.node || null,
left: most.left && most.left.node || null,
down: most.down && most.down.node || null
};
} }
find.node._nearestNodes = {
right: most.right && most.right.node || null,
top: most.top && most.top.node || null,
left: most.left && most.left.node || null,
down: most.down && most.down.node || null
};
}
function navigateTo(km, direction) {
var referNode = km.getSelectedNode();
if (!referNode) {
km.select(km.getRoot());
buildPositionNetwork(km.getRoot());
return;
}
if (!referNode._nearestNodes) {
buildPositionNetwork(km.getRoot());
}
var nextNode = referNode._nearestNodes[direction];
if (nextNode) {
km.select(nextNode, true);
}
}
var NavigateToParentCommand = kity.createClass({ function navigateTo(km, direction) {
base: Command, var referNode = km.getSelectedNode();
if (!referNode) {
execute: function(km) { km.select(km.getRoot());
var node = km.getSelectedNode(); buildPositionNetwork(km.getRoot());
if (node && node.parent) { return;
km.select(node.parent, true);
} }
this.setContentChanged(false); if (!referNode._nearestNodes) {
}, buildPositionNetwork(km.getRoot());
}
queryState: function(km) { var nextNode = referNode._nearestNodes[direction];
return km.getSelectedNode() ? 0 : -1; if (nextNode) {
}, km.select(nextNode, true);
}
}
enableReadOnly: true var NavigateToParentCommand = kity.createClass({
}); base: Command,
// 稀释用 execute: function(km) {
var lastFrame; var node = km.getSelectedNode();
return { if (node && node.parent) {
'commands': { km.select(node.parent, true);
'navparent': NavigateToParentCommand }
}, this.setContentChanged(false);
'commandShortcutKeys': {
'navparent': 'shift+tab'
},
'events': {
'layoutallfinish': function() {
var root = this.getRoot();
buildPositionNetwork(root);
},
'normal.keydown readonly.keydown': function(e) {
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 (kity.Browser.ipad) {
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) return;
switch (keyEvent.keyCode) { queryState: function(km) {
case keys.Enter: return km.getSelectedNode() ? 0 : -1;
this.execCommand('AppendSiblingNode', lang.topic); },
e.preventDefault();
break;
case keys.Backspace: enableReadOnly: true
case keys.Del: });
e.preventDefault();
this.execCommand('RemoveNode');
break;
// 稀释用
var lastFrame;
return {
'commands': {
'navparent': NavigateToParentCommand
},
'commandShortcutKeys': {
'navparent': 'shift+tab'
},
'events': {
'layoutallfinish': function() {
var root = this.getRoot();
buildPositionNetwork(root);
},
'normal.keydown readonly.keydown': function(e) {
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 (kity.Browser.ipad) {
var keys = keymap;
var node = e.getTargetNode();
if (this.receiver) this.receiver.keydownNode = node;
var keyEvent = e.originEvent;
if (keyEvent.altKey || keyEvent.ctrlKey || keyEvent.metaKey || keyEvent.shiftKey) return;
switch (keyEvent.keyCode) {
case keys.Enter:
this.execCommand('AppendSiblingNode');
e.preventDefault();
break;
case keys.Backspace:
case keys.Del:
e.preventDefault();
this.execCommand('RemoveNode');
break;
}
} }
}
}
} }
} };
}; });
}); });
\ No newline at end of file
/**
* @fileOverview
*
* 布局模块
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
define(function(require, exports, module) {
var kity = require('../core/kity');
var Command = require('../core/command');
var Module = require('../core/module');
var LayoutCommand = kity.createClass('LayoutCommand', {
base: Command,
execute: function(minder, name) {
var nodes = minder.getSelectedNodes();
nodes.forEach(function(node) {
node.layout(name);
});
},
queryValue: function(minder) {
var node = minder.getSelectedNode();
if (node) {
return node.getData('layout');
}
},
queryState: function(minder) {
return minder.getSelectedNode() ? 0 : -1;
}
});
var ResetLayoutCommand = kity.createClass('ResetLayoutCommand', {
base: Command,
execute: function(minder, name) {
var nodes = minder.getSelectedNodes();
if (!nodes.length) nodes = [minder.getRoot()];
nodes.forEach(function(node) {
node.traverse(function(child) {
child.resetLayoutOffset();
if (!child.isRoot()) {
child.setData('layout', null);
}
});
});
minder.layout(300);
},
enableReadOnly: true
});
Module.register('LayoutModule', {
commands: {
'layout': LayoutCommand,
'resetlayout': ResetLayoutCommand
},
contextmenu: [{
command: 'resetlayout'
}, {
divider: true
}],
commandShortcutKeys: {
'resetlayout': 'Ctrl+Shift+L'
}
});
});
\ No newline at end of file
var AppendChildCommand = kity.createClass('AppendChildCommand', { define(function(require, exports, module) {
base: Command, var kity = require('core/kity');
execute: function(km, text) { var utils = require('core/utils');
var parent = km.getSelectedNode();
if (!parent) { var Minder = require('core/minder');
return null; var MinderNode = require('core/node');
} var Command = require('core/command');
text = text || km.getLang('topic'); var Module = require('core/module');
parent.expand(); var Renderer = require('core/render');
var node = km.createNode(text, parent);
km.select(node, true);
node.render();
km.layout(600);
},
queryState: function(km) {
var selectedNode = km.getSelectedNode();
return selectedNode ? 0 : -1;
}
});
var AppendSiblingCommand = kity.createClass('AppendSiblingCommand', { var AppendChildCommand = kity.createClass('AppendChildCommand', {
base: Command, base: Command,
execute: function(km, text) { execute: function(km, text) {
var sibling = km.getSelectedNode(); var parent = km.getSelectedNode();
var parent = sibling.parent; if (!parent) {
if (!parent) { return null;
return km.execCommand('AppendChildNode', text); }
parent.expand();
var node = km.createNode(text, parent);
km.select(node, true);
node.render();
km.layout(600);
},
queryState: function(km) {
var selectedNode = km.getSelectedNode();
return selectedNode ? 0 : -1;
} }
text = text || km.getLang('topic'); });
var node = km.createNode(text, parent, sibling.getIndex() + 1);
km.select(node, true);
node.render();
km.layout(600);
},
queryState: function(km) {
var selectedNode = km.getSelectedNode();
return selectedNode ? 0 : -1;
}
});
var RemoveNodeCommand = kity.createClass('RemoverNodeCommand', { var AppendSiblingCommand = kity.createClass('AppendSiblingCommand', {
base: Command, base: Command,
execute: function(km, text) { execute: function(km, text) {
var nodes = km.getSelectedNodes(); var sibling = km.getSelectedNode();
var ancestor = MinderNode.getCommonAncestor.apply(null, nodes); var parent = sibling.parent;
if (!parent) {
return km.execCommand('AppendChildNode', text);
}
var node = km.createNode(text, parent, sibling.getIndex() + 1);
km.select(node, true);
node.render();
km.layout(600);
},
queryState: function(km) {
var selectedNode = km.getSelectedNode();
return selectedNode ? 0 : -1;
}
});
nodes.forEach(function(node) { var RemoveNodeCommand = kity.createClass('RemoverNodeCommand', {
if (!node.isRoot()) km.removeNode(node); base: Command,
}); execute: function(km, text) {
var nodes = km.getSelectedNodes();
var ancestor = MinderNode.getCommonAncestor.apply(null, nodes);
km.select(ancestor || km.getRoot(), true); nodes.forEach(function(node) {
km.layout(600); if (!node.isRoot()) km.removeNode(node);
}, });
queryState: function(km) {
var selectedNode = km.getSelectedNode();
return selectedNode ? 0 : -1;
}
});
var EditNodeCommand = kity.createClass('EditNodeCommand', { km.select(ancestor || km.getRoot(), true);
base: Command, km.layout(600);
execute: function(km) { },
var selectedNode = km.getSelectedNode(); queryState: function(km) {
if (!selectedNode) { var selectedNode = km.getSelectedNode();
return null; return selectedNode ? 0 : -1;
} }
km.select(selectedNode, true); });
km.textEditNode(selectedNode);
}, var EditNodeCommand = kity.createClass('EditNodeCommand', {
queryState: function(km) { base: Command,
var selectedNode = km.getSelectedNode(); execute: function(km) {
if (!selectedNode) { var selectedNode = km.getSelectedNode();
return -1; if (!selectedNode) {
} else { return null;
return 0; }
km.select(selectedNode, true);
km.textEditNode(selectedNode);
},
queryState: function(km) {
var selectedNode = km.getSelectedNode();
if (!selectedNode) {
return -1;
} else {
return 0;
}
},
isNeedUndo: function() {
return false;
} }
}, });
isNeedUndo: function() {
return false;
}
});
KityMinder.registerModule('NodeModule', function() { Module.register('NodeModule', function() {
return { return {
commands: { commands: {
'AppendChildNode': AppendChildCommand, 'AppendChildNode': AppendChildCommand,
'AppendSiblingNode': AppendSiblingCommand, 'AppendSiblingNode': AppendSiblingCommand,
'RemoveNode': RemoveNodeCommand, 'RemoveNode': RemoveNodeCommand,
'EditNode': EditNodeCommand 'EditNode': EditNodeCommand
}, },
'contextmenu': [{ 'contextmenu': [{
command: 'appendsiblingnode' command: 'appendsiblingnode'
}, { }, {
command: 'appendchildnode' command: 'appendchildnode'
}, { }, {
command: 'editnode' command: 'editnode'
}, { }, {
command: 'removenode' command: 'removenode'
}, { }, {
divider: 1 divider: 1
}], }],
'commandShortcutKeys': { 'commandShortcutKeys': {
'appendsiblingnode': 'normal::Enter', 'appendsiblingnode': 'normal::Enter',
'appendchildnode': 'normal::Insert|Tab', 'appendchildnode': 'normal::Insert|Tab',
'editnode': 'normal::F2', 'editnode': 'normal::F2',
'removenode': 'normal::Del|Backspace' 'removenode': 'normal::Del|Backspace'
} }
}; };
});
}); });
\ No newline at end of file
...@@ -6,91 +6,102 @@ ...@@ -6,91 +6,102 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
KityMinder.registerModule('NoteModule', function() { define(function(require, exports, module) {
var kity = require('core/kity');
var NOTE_PATH = 'M9,9H3V8h6L9,9L9,9z M9,7H3V6h6V7z M9,5H3V4h6V5z M8.5,11H2V2h8v7.5 M9,12l2-2V1H1v11'; var utils = require('core/utils');
var NoteCommand = kity.createClass('NoteCommand', { var Minder = require('core/minder');
base: Command, var MinderNode = require('core/node');
var Command = require('core/command');
execute: function(minder, note) { var Module = require('core/module');
var node = minder.getSelectedNode(); var Renderer = require('core/render');
node.setData('note', note);
node.render(); Module.register('NoteModule', function() {
node.getMinder().layout(300);
}, var NOTE_PATH = 'M9,9H3V8h6L9,9L9,9z M9,7H3V6h6V7z M9,5H3V4h6V5z M8.5,11H2V2h8v7.5 M9,12l2-2V1H1v11';
queryState: function(minder) { var NoteCommand = kity.createClass('NoteCommand', {
return minder.getSelectedNodes().length === 1 ? 0 : -1; base: Command,
},
execute: function(minder, note) {
queryValue: function(minder) { var node = minder.getSelectedNode();
var node = minder.getSelectedNode(); node.setData('note', note);
return node && node.getData('note'); node.render();
} node.getMinder().layout(300);
},
queryState: function(minder) {
return minder.getSelectedNodes().length === 1 ? 0 : -1;
},
queryValue: function(minder) {
var node = minder.getSelectedNode();
return node && node.getData('note');
}
});
var NoteIcon = kity.createClass('NoteIcon', {
base: kity.Group,
constructor: function() {
this.callBase();
this.width = 16;
this.height = 17;
this.rect = new kity.Rect(16, 17, 0.5, -8.5, 2).fill('transparent');
this.path = new kity.Path().setPathData(NOTE_PATH).setTranslate(2.5, -6.5);
this.addShapes([this.rect, this.path]);
this.on('mouseover', function() {
this.rect.fill('rgba(255, 255, 200, .8)');
}).on('mouseout', function() {
this.rect.fill('transparent');
});
this.setStyle('cursor', 'pointer');
}
});
var NoteIconRenderer = kity.createClass('NoteIconRenderer', {
base: Renderer,
create: function(node) {
var icon = new NoteIcon();
icon.on('mousedown', function(e) {
e.preventDefault();
node.getMinder().fire('editnoterequest');
});
icon.on('mouseover', function() {
node.getMinder().fire('shownoterequest', {node: node, icon: icon});
});
icon.on('mouseout', function() {
node.getMinder().fire('hidenoterequest', {node: node, icon: icon});
});
return icon;
},
shouldRender: function(node) {
return node.getData('note');
},
update: function(icon, node, box) {
var x = box.right + node.getStyle('space-left');
var y = box.cy;
icon.path.fill(node.getStyle('color'));
icon.setTranslate(x, y);
return new kity.Box(x, Math.round(y - icon.height / 2), icon.width, icon.height);
}
});
return {
renderers: {
right: NoteIconRenderer
},
commands: {
'note': NoteCommand
}
};
}); });
var NoteIcon = kity.createClass('NoteIcon', {
base: kity.Group,
constructor: function() {
this.callBase();
this.width = 16;
this.height = 17;
this.rect = new kity.Rect(16, 17, 0.5, -8.5, 2).fill('transparent');
this.path = new kity.Path().setPathData(NOTE_PATH).setTranslate(2.5, -6.5);
this.addShapes([this.rect, this.path]);
this.on('mouseover', function() {
this.rect.fill('rgba(255, 255, 200, .8)');
}).on('mouseout', function() {
this.rect.fill('transparent');
});
this.setStyle('cursor', 'pointer');
}
});
var NoteIconRenderer = kity.createClass('NoteIconRenderer', {
base: KityMinder.Renderer,
create: function(node) {
var icon = new NoteIcon();
icon.on('mousedown', function(e) {
e.preventDefault();
node.getMinder().fire('editnoterequest');
});
icon.on('mouseover', function() {
node.getMinder().fire('shownoterequest', {node: node, icon: icon});
});
icon.on('mouseout', function() {
node.getMinder().fire('hidenoterequest', {node: node, icon: icon});
});
return icon;
},
shouldRender: function(node) {
return node.getData('note');
},
update: function(icon, node, box) {
var x = box.right + node.getStyle('space-left');
var y = box.cy;
icon.path.fill(node.getStyle('color'));
icon.setTranslate(x, y);
return new kity.Box(x, Math.round(y - icon.height / 2), icon.width, icon.height);
}
});
return {
renderers: {
right: NoteIconRenderer
},
commands: {
'note': NoteCommand
}
};
}); });
\ No newline at end of file
/* global Renderer: true */ define(function(require, exports, module) {
var kity = require('core/kity');
var utils = require('core/utils');
var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
var Renderer = require('core/render');
var OutlineRenderer = kity.createClass('OutlineRenderer', { var OutlineRenderer = kity.createClass('OutlineRenderer', {
base: Renderer, base: Renderer,
create: function(node) { create: function(node) {
var outline = new kity.Rect() var outline = new kity.Rect()
.setId(KityMinder.uuid('node_outline')); .setId(utils.uuid('node_outline'));
this.bringToBack = true; this.bringToBack = true;
return outline; return outline;
}, },
update: function(outline, node, box) { update: function(outline, node, box) {
var paddingLeft = node.getStyle('padding-left'), var paddingLeft = node.getStyle('padding-left'),
paddingRight = node.getStyle('padding-right'), paddingRight = node.getStyle('padding-right'),
paddingTop = node.getStyle('padding-top'), paddingTop = node.getStyle('padding-top'),
paddingBottom = node.getStyle('padding-bottom'); paddingBottom = node.getStyle('padding-bottom');
var outlineBox = { var outlineBox = {
x: box.x - paddingLeft, x: box.x - paddingLeft,
y: box.y - paddingTop, y: box.y - paddingTop,
width: box.width + paddingLeft + paddingRight, width: box.width + paddingLeft + paddingRight,
height: box.height + paddingTop + paddingBottom height: box.height + paddingTop + paddingBottom
}; };
var prefix = node.isSelected() ? 'selected-' : ''; var prefix = node.isSelected() ? 'selected-' : '';
outline outline
.setPosition(outlineBox.x, outlineBox.y) .setPosition(outlineBox.x, outlineBox.y)
.setSize(outlineBox.width, outlineBox.height) .setSize(outlineBox.width, outlineBox.height)
.setRadius(node.getStyle('radius')) .setRadius(node.getStyle('radius'))
.fill(node.getData('background') || node.getStyle(prefix + 'background') || node.getStyle('background')) .fill(node.getData('background') || node.getStyle(prefix + 'background') || node.getStyle('background'))
.stroke(node.getStyle(prefix + 'stroke' || node.getStyle('stroke')), .stroke(node.getStyle(prefix + 'stroke' || node.getStyle('stroke')),
node.getStyle(prefix + 'stroke-width')); node.getStyle(prefix + 'stroke-width'));
return new kity.Box(outlineBox); return new kity.Box(outlineBox);
} }
}); });
var ShadowRenderer = kity.createClass('ShadowRenderer', { var ShadowRenderer = kity.createClass('ShadowRenderer', {
base: Renderer, base: Renderer,
create: function(node) { create: function(node) {
this.bringToBack = true; this.bringToBack = true;
return new kity.Rect(); return new kity.Rect();
}, },
shouldRender: function(node) { shouldRender: function(node) {
return node.getStyle('shadow'); return node.getStyle('shadow');
}, },
update: function(shadow, node, box) { update: function(shadow, node, box) {
shadow.setPosition(box.x + 4, box.y + 5) shadow.setPosition(box.x + 4, box.y + 5)
.setSize(box.width, box.height) .setSize(box.width, box.height)
.fill(node.getStyle('shadow')) .fill(node.getStyle('shadow'))
.setRadius(node.getStyle('radius')); .setRadius(node.getStyle('radius'));
}
});
var marker = new kity.Marker();
marker.setWidth(10);
marker.setHeight(12);
marker.setRef(0, 0);
marker.setViewBox(-6, -4, 8, 10);
marker.addShape(new kity.Path().setPathData('M-5-3l5,3,-5,3').stroke('#33ffff'));
var wireframeOption = /wire/.test(window.location.href);
var WireframeRenderer = kity.createClass('WireframeRenderer', {
base: Renderer,
create: function() {
var wireframe = new kity.Group();
var oxy = this.oxy = new kity.Path()
.stroke('#f6f')
.setPathData('M0,-50L0,50M-50,0L50,0');
var box = this.wireframe = new kity.Rect()
.stroke('lightgreen');
var vectorIn = this.vectorIn = new kity.Path()
.stroke('#66ffff');
var vectorOut = this.vectorOut = new kity.Path()
.stroke('#66ffff');
vectorIn.setMarker(marker, 'end');
vectorOut.setMarker(marker, 'end');
return wireframe.addShapes([oxy, box, vectorIn, vectorOut]);
},
shouldRender: function() {
return wireframeOption;
},
update: function(created, node, box) {
this.wireframe
.setPosition(box.x, box.y)
.setSize(box.width, box.height);
var pin = node.getVertexIn();
var pout = node.getVertexOut();
var vin = node.getLayoutVectorIn().normalize(30);
var vout = node.getLayoutVectorOut().normalize(30);
this.vectorIn.setPathData(['M', pin.offset(vin.reverse()), 'L', pin]);
this.vectorOut.setPathData(['M', pout, 'l', vout]);
}
});
KityMinder.registerModule('OutlineModule', function() {
return {
events: (!wireframeOption ? null : {
'ready': function() {
this.getPaper().addResource(marker);
},
'layoutallfinish': function() {
this.getRoot().traverse(function(node) {
node.getRenderer('WireframeRenderer').update(null, node, node.getContentBox());
});
}
}),
renderers: {
outline: OutlineRenderer,
outside: [ShadowRenderer, WireframeRenderer]
} }
}; });
var marker = new kity.Marker();
marker.setWidth(10);
marker.setHeight(12);
marker.setRef(0, 0);
marker.setViewBox(-6, -4, 8, 10);
marker.addShape(new kity.Path().setPathData('M-5-3l5,3,-5,3').stroke('#33ffff'));
var wireframeOption = /wire/.test(window.location.href);
var WireframeRenderer = kity.createClass('WireframeRenderer', {
base: Renderer,
create: function() {
var wireframe = new kity.Group();
var oxy = this.oxy = new kity.Path()
.stroke('#f6f')
.setPathData('M0,-50L0,50M-50,0L50,0');
var box = this.wireframe = new kity.Rect()
.stroke('lightgreen');
var vectorIn = this.vectorIn = new kity.Path()
.stroke('#66ffff');
var vectorOut = this.vectorOut = new kity.Path()
.stroke('#66ffff');
vectorIn.setMarker(marker, 'end');
vectorOut.setMarker(marker, 'end');
return wireframe.addShapes([oxy, box, vectorIn, vectorOut]);
},
shouldRender: function() {
return wireframeOption;
},
update: function(created, node, box) {
this.wireframe
.setPosition(box.x, box.y)
.setSize(box.width, box.height);
var pin = node.getVertexIn();
var pout = node.getVertexOut();
var vin = node.getLayoutVectorIn().normalize(30);
var vout = node.getLayoutVectorOut().normalize(30);
this.vectorIn.setPathData(['M', pin.offset(vin.reverse()), 'L', pin]);
this.vectorOut.setPathData(['M', pout, 'l', vout]);
}
});
Module.register('OutlineModule', function() {
return {
events: (!wireframeOption ? null : {
'ready': function() {
this.getPaper().addResource(marker);
},
'layoutallfinish': function() {
this.getRoot().traverse(function(node) {
node.getRenderer('WireframeRenderer').update(null, node, node.getContentBox());
});
}
}),
renderers: {
outline: OutlineRenderer,
outside: [ShadowRenderer, WireframeRenderer]
}
};
});
}); });
\ No newline at end of file
KityMinder.registerModule( "pasteModule", function () {
var km = this,
_cacheNodes = [],
_selectedNodes = [],
_copystatus= false,
_curstatus = false;
function appendChildNode(parent, child) {
_selectedNodes.push(child);
km.appendNode(child,parent);
child.render();
child.setLayoutOffset(null);
var children = utils.cloneArr(child.children);
for (var i = 0, ci; ci = children[i++]; ) {
appendChildNode(child, ci);
}
}
function getNodes(arr,isCut){
_cacheNodes = [];
for(var i= 0,ni;ni=arr[i++];){
_cacheNodes.push(ni.clone());
if(isCut && !ni.isRoot()){
km.removeNode(ni);
}
}
}
return {
'events': {
'normal.keydown': function (e) {
var keys = KityMinder.keymap;
var keyEvent = e.originEvent;
if (keyEvent.ctrlKey || keyEvent.metaKey) {
switch (keyEvent.keyCode) {
case keys.c:
getNodes(km.getSelectedAncestors(true));
_copystatus = true;
break;
case keys.x:
getNodes(km.getSelectedAncestors(),true);
km.layout(300);
_curstatus = true;
break;
case keys.v:
if(_cacheNodes.length){
var node = km.getSelectedNode();
if(node){
km.fire('saveScene');
for(var i= 0,ni;ni=_cacheNodes[i++];){
appendChildNode(node,ni.clone());
}
km.layout(300);
km.select(_selectedNodes,true);
_selectedNodes = [];
km.fire('saveScene');
}
}
}
}
}
}
};
} );
\ No newline at end of file
KityMinder.registerModule('PriorityModule', function() { define(function(require, exports, module) {
var minder = this; var kity = require('core/kity');
var utils = require('core/utils');
// Designed by Akikonata
// [MASK, BACK] var Minder = require('core/minder');
var PRIORITY_COLORS = [null, var MinderNode = require('core/node');
['#FF1200', '#840023'], // 1 - red var Command = require('core/command');
['#0074FF', '#01467F'], // 2 - blue var Module = require('core/module');
['#00AF00', '#006300'], // 3 - green var Renderer = require('core/render');
['#FF962E', '#B25000'], // 4 - orange
['#A464FF', '#4720C4'], // 5 - purple Module.register('PriorityModule', function() {
['#A3A3A3', '#515151'], // 6,7,8,9 - gray var minder = this;
['#A3A3A3', '#515151'],
['#A3A3A3', '#515151'], // Designed by Akikonata
['#A3A3A3', '#515151'], // [MASK, BACK]
]; // hue from 1 to 5 var PRIORITY_COLORS = [null, ['#FF1200', '#840023'], // 1 - red
['#0074FF', '#01467F'], // 2 - blue
var BACK_PATH = 'M0,13c0,3.866,3.134,7,7,7h6c3.866,0,7-3.134,7-7V7H0V13z'; ['#00AF00', '#006300'], // 3 - green
var MASK_PATH = 'M20,10c0,3.866-3.134,7-7,7H7c-3.866,0-7-3.134-7-7V7c0-3.866,3.134-7,7-7h6c3.866,0,7,3.134,7,7V10z'; ['#FF962E', '#B25000'], // 4 - orange
['#A464FF', '#4720C4'], // 5 - purple
var PRIORITY_DATA = 'priority'; ['#A3A3A3', '#515151'], // 6,7,8,9 - gray
['#A3A3A3', '#515151'],
// 进度图标的图形 ['#A3A3A3', '#515151'],
var PriorityIcon = kity.createClass('PriorityIcon', { ['#A3A3A3', '#515151'],
base: kity.Group, ]; // hue from 1 to 5
constructor: function() { // jscs:disable maximumLineLength
this.callBase(); var BACK_PATH = 'M0,13c0,3.866,3.134,7,7,7h6c3.866,0,7-3.134,7-7V7H0V13z';
this.setSize(20); var MASK_PATH = 'M20,10c0,3.866-3.134,7-7,7H7c-3.866,0-7-3.134-7-7V7c0-3.866,3.134-7,7-7h6c3.866,0,7,3.134,7,7V10z';
this.create();
this.setId(KityMinder.uuid('node_priority')); var PRIORITY_DATA = 'priority';
},
// 进度图标的图形
setSize: function(size) { var PriorityIcon = kity.createClass('PriorityIcon', {
this.width = this.height = size; base: kity.Group,
},
constructor: function() {
create: function() { this.callBase();
var white, back, mask, number; // 4 layer this.setSize(20);
this.create();
white = new kity.Path().setPathData(MASK_PATH).fill('white'); this.setId(utils.uuid('node_priority'));
back = new kity.Path().setPathData(BACK_PATH).setTranslate(0.5, 0.5); },
mask = new kity.Path().setPathData(MASK_PATH).setOpacity(0.8).setTranslate(0.5, 0.5);
setSize: function(size) {
number = new kity.Text() this.width = this.height = size;
.setX(this.width / 2 - 0.5).setY(this.height / 2 - 1.5) },
.setTextAnchor('middle')
.setVerticalAlign('middle') create: function() {
.setFontItalic(true) var white, back, mask, number; // 4 layer
.setFontSize(14)
.fill('white'); white = new kity.Path().setPathData(MASK_PATH).fill('white');
back = new kity.Path().setPathData(BACK_PATH).setTranslate(0.5, 0.5);
this.addShapes([back, mask, number]); mask = new kity.Path().setPathData(MASK_PATH).setOpacity(0.8).setTranslate(0.5, 0.5);
this.mask = mask;
this.back = back; number = new kity.Text()
this.number = number; .setX(this.width / 2 - 0.5).setY(this.height / 2 - 1.5)
}, .setTextAnchor('middle')
.setVerticalAlign('middle')
setValue: function(value) { .setFontItalic(true)
var back = this.back, .setFontSize(14)
mask = this.mask, .fill('white');
number = this.number;
this.addShapes([back, mask, number]);
var color = PRIORITY_COLORS[value]; this.mask = mask;
this.back = back;
if (color) { this.number = number;
back.fill(color[1]); },
mask.fill(color[0]);
} setValue: function(value) {
var back = this.back,
mask = this.mask,
number = this.number;
var color = PRIORITY_COLORS[value];
if (color) {
back.fill(color[1]);
mask.fill(color[0]);
}
number.setContent(value); number.setContent(value);
} }
}); });
// 提供的命令
var PriorityCommand = kity.createClass('SetPriorityCommand', {
base: Command,
execute: function(km, value) {
var nodes = km.getSelectedNodes();
for (var i = 0; i < nodes.length; i++) {
nodes[i].setData(PRIORITY_DATA, value || null).render();
}
km.layout();
},
queryValue: function(km) {
var nodes = km.getSelectedNodes();
var val;
for (var i = 0; i < nodes.length; i++) {
val = nodes[i].getData(PRIORITY_DATA);
if (val) break;
}
return val || null;
},
// 提供的命令 queryState: function(km) {
var PriorityCommand = kity.createClass('SetPriorityCommand', { return km.getSelectedNodes().length ? 0 : -1;
base: Command,
execute: function(km, value) {
var nodes = km.getSelectedNodes();
for (var i = 0; i < nodes.length; i++) {
nodes[i].setData(PRIORITY_DATA, value || null).render();
} }
km.layout(); });
}, return {
queryValue: function(km) { 'commands': {
var nodes = km.getSelectedNodes(); 'priority': PriorityCommand,
var val; },
for (var i = 0; i < nodes.length; i++) { 'renderers': {
val = nodes[i].getData(PRIORITY_DATA); left: kity.createClass('PriorityRenderer', {
if (val) break; base: Renderer,
create: function(node) {
return new PriorityIcon();
},
shouldRender: function(node) {
return node.getData(PRIORITY_DATA);
},
update: function(icon, node, box) {
var data = node.getData(PRIORITY_DATA);
var spaceLeft = node.getStyle('space-left'),
x, y;
icon.setValue(data);
x = box.left - icon.width - spaceLeft;
y = -icon.height / 2;
icon.setTranslate(x, y);
return new kity.Box({
x: x,
y: y,
width: icon.width,
height: icon.height
});
}
})
} }
return val || null; };
},
queryState: function(km) {
return km.getSelectedNodes().length ? 0 : -1;
}
}); });
return {
'commands': {
'priority': PriorityCommand,
},
'renderers': {
left: kity.createClass('PriorityRenderer', {
base: KityMinder.Renderer,
create: function(node) {
return new PriorityIcon();
},
shouldRender: function(node) {
return node.getData(PRIORITY_DATA);
},
update: function(icon, node, box) {
var data = node.getData(PRIORITY_DATA);
var spaceLeft = node.getStyle('space-left'),
x, y;
icon.setValue(data);
x = box.left - icon.width - spaceLeft;
y = -icon.height / 2;
icon.setTranslate(x, y);
return new kity.Box({
x: x,
y: y,
width: icon.width,
height: icon.height
});
}
})
}
};
}); });
\ No newline at end of file
KityMinder.registerModule('ProgressModule', function() { define(function(require, exports, module) {
var minder = this; var kity = require('core/kity');
var utils = require('core/utils');
var PROGRESS_DATA = 'progress';
var Minder = require('core/minder');
// Designed by Akikonata var MinderNode = require('core/node');
var BG_COLOR = '#FFED83'; var Command = require('core/command');
var PIE_COLOR = '#43BC00'; var Module = require('core/module');
var SHADOW_PATH = 'M10,3c4.418,0,8,3.582,8,8h1c0-5.523-3.477-10-9-10S1,5.477,1,11h1C2,6.582,5.582,3,10,3z'; var Renderer = require('core/render');
var SHADOW_COLOR = '#8E8E8E';
var FRAME_PATH = 'M10,0C4.477,0,0,4.477,0,10c0,5.523,4.477,10,10,10s10-4.477,10-10C20,4.477,15.523,0,10,0zM10,18c-4.418,0-8-3.582-8-8s3.582-8,8-8s8,3.582,8,8S14.418,18,10,18z'; Module.register('ProgressModule', function() {
var FRAME_GRAD = new kity.LinearGradientBrush().pipe(function(g) { var minder = this;
g.setStartPosition(0, 0);
g.setEndPosition(0, 1); var PROGRESS_DATA = 'progress';
g.addStop(0, '#fff');
g.addStop(1, '#ccc'); // Designed by Akikonata
}); var BG_COLOR = '#FFED83';
var CHECK_PATH = 'M15.812,7.896l-6.75,6.75l-4.5-4.5L6.25,8.459l2.812,2.803l5.062-5.053L15.812,7.896z'; var PIE_COLOR = '#43BC00';
var CHECK_COLOR = '#EEE'; var SHADOW_PATH = 'M10,3c4.418,0,8,3.582,8,8h1c0-5.523-3.477-10-9-10S1,5.477,1,11h1C2,6.582,5.582,3,10,3z';
var SHADOW_COLOR = '#8E8E8E';
minder.getPaper().addResource(FRAME_GRAD);
// jscs:disable maximumLineLength
// 进度图标的图形 var FRAME_PATH = 'M10,0C4.477,0,0,4.477,0,10c0,5.523,4.477,10,10,10s10-4.477,10-10C20,4.477,15.523,0,10,0zM10,18c-4.418,0-8-3.582-8-8s3.582-8,8-8s8,3.582,8,8S14.418,18,10,18z';
var ProgressIcon = kity.createClass('ProgressIcon', {
base: kity.Group, var FRAME_GRAD = new kity.LinearGradientBrush().pipe(function(g) {
g.setStartPosition(0, 0);
constructor: function(value) { g.setEndPosition(0, 1);
this.callBase(); g.addStop(0, '#fff');
this.setSize(20); g.addStop(1, '#ccc');
this.create(); });
this.setValue(value); var CHECK_PATH = 'M15.812,7.896l-6.75,6.75l-4.5-4.5L6.25,8.459l2.812,2.803l5.062-5.053L15.812,7.896z';
this.setId(KityMinder.uuid('node_progress')); var CHECK_COLOR = '#EEE';
this.translate(0.5, 0.5);
}, minder.getPaper().addResource(FRAME_GRAD);
setSize: function(size) { // 进度图标的图形
this.width = this.height = size; var ProgressIcon = kity.createClass('ProgressIcon', {
}, base: kity.Group,
create: function() { constructor: function(value) {
this.callBase();
var bg, pie, shadow, frame, check; this.setSize(20);
this.create();
bg = new kity.Circle(9) this.setValue(value);
.fill(BG_COLOR); this.setId(utils.uuid('node_progress'));
this.translate(0.5, 0.5);
pie = new kity.Pie(9, 0) },
.fill(PIE_COLOR);
setSize: function(size) {
shadow = new kity.Path() this.width = this.height = size;
.setPathData(SHADOW_PATH) },
.setTranslate(-10, -10)
.fill(SHADOW_COLOR); create: function() {
frame = new kity.Path() var bg, pie, shadow, frame, check;
.setTranslate(-10, -10)
.setPathData(FRAME_PATH) bg = new kity.Circle(9)
.fill(FRAME_GRAD); .fill(BG_COLOR);
check = new kity.Path() pie = new kity.Pie(9, 0)
.setTranslate(-10, -10) .fill(PIE_COLOR);
.setPathData(CHECK_PATH)
.fill(CHECK_COLOR); shadow = new kity.Path()
.setPathData(SHADOW_PATH)
this.addShapes([bg, pie, shadow, check, frame]); .setTranslate(-10, -10)
this.pie = pie; .fill(SHADOW_COLOR);
this.check = check;
}, frame = new kity.Path()
.setTranslate(-10, -10)
setValue: function(value) { .setPathData(FRAME_PATH)
this.pie.setAngle(-360 * (value - 1) / 8); .fill(FRAME_GRAD);
this.check.setVisible(value == 9);
} check = new kity.Path()
}); .setTranslate(-10, -10)
.setPathData(CHECK_PATH)
.fill(CHECK_COLOR);
this.addShapes([bg, pie, shadow, check, frame]);
this.pie = pie;
this.check = check;
},
setValue: function(value) {
this.pie.setAngle(-360 * (value - 1) / 8);
this.check.setVisible(value == 9);
}
});
var ProgressCommand = kity.createClass('ProgressCommand', {
base: Command,
execute: function(km, value) {
var nodes = km.getSelectedNodes();
for (var i = 0; i < nodes.length; i++) {
nodes[i].setData(PROGRESS_DATA, value || null).render();
}
km.layout();
},
queryValue: function(km) {
var nodes = km.getSelectedNodes();
var val;
for (var i = 0; i < nodes.length; i++) {
val = nodes[i].getData(PROGRESS_DATA);
if (val) break;
}
return val || null;
},
var ProgressCommand = kity.createClass('ProgressCommand', { queryState: function(km) {
base: Command, return km.getSelectedNodes().length ? 0 : -1;
execute: function(km, value) {
var nodes = km.getSelectedNodes();
for (var i = 0; i < nodes.length; i++) {
nodes[i].setData(PROGRESS_DATA, value || null).render();
} }
km.layout(); });
},
queryValue: function(km) { return {
var nodes = km.getSelectedNodes(); 'commands': {
var val; 'progress': ProgressCommand
for (var i = 0; i < nodes.length; i++) { },
val = nodes[i].getData(PROGRESS_DATA); 'renderers': {
if (val) break; left: kity.createClass('ProgressRenderer', {
base: Renderer,
create: function(node) {
return new ProgressIcon();
},
shouldRender: function(node) {
return node.getData(PROGRESS_DATA);
},
update: function(icon, node, box) {
var data = node.getData(PROGRESS_DATA);
var spaceLeft = node.getStyle('space-left');
var x, y;
icon.setValue(data);
x = box.left - icon.width - spaceLeft;
y = -icon.height / 2;
icon.setTranslate(x + icon.width / 2, y + icon.height / 2);
return new kity.Box(x, y, icon.width, icon.height);
}
})
} }
return val|| null; };
},
queryState: function(km) {
return km.getSelectedNodes().length ? 0 : -1;
}
}); });
return {
'commands': {
'progress': ProgressCommand
},
'renderers': {
left: kity.createClass('ProgressRenderer', {
base: KityMinder.Renderer,
create: function(node) {
return new ProgressIcon();
},
shouldRender: function(node) {
return node.getData(PROGRESS_DATA);
},
update: function(icon, node, box) {
var data = node.getData(PROGRESS_DATA);
var spaceLeft = node.getStyle('space-left');
var x, y;
icon.setValue(data);
x = box.left - icon.width - spaceLeft;
y = -icon.height / 2;
icon.setTranslate(x + icon.width / 2, y + icon.height / 2);
return new kity.Box(x, y, icon.width, icon.height);
}
})
}
};
}); });
\ No newline at end of file
KityMinder.registerModule('Resource', function() { define(function(require, exports, module) {
var kity = require('core/kity');
var utils = require('core/utils');
/** var Minder = require('core/minder');
* 自动使用的颜色序列 var MinderNode = require('core/node');
*/ var Command = require('core/command');
var RESOURCE_COLOR_SERIES = [51, 303, 75, 200, 157, 0, 26, 254].map(function(h) { var Module = require('core/module');
return kity.Color.createHSL(h, 100, 85); var Renderer = require('core/render');
});
var RESOURCE_COLOR_OVERFLOW = kity.Color.createHSL(0, 0, 95);
/** Module.register('Resource', function() {
* 在 KityMinder 上拓展一些关于资源的支持接口
*/
kity.extendClass(KityMinder, {
/** /**
* 获取脑图中某个资源对应的颜色 * 自动使用的颜色序列
*
* 如果存在同名资源,则返回已经分配给该资源的颜色,否则分配给该资源一个颜色,并且返回
*
* 如果资源数超过颜色序列数量,返回白色
*
* @param {String} resource 资源名称
* @return {Color}
*/ */
getResourceColor: function(resource) { var RESOURCE_COLOR_SERIES = [51, 303, 75, 200, 157, 0, 26, 254].map(function(h) {
var colorMapping = this._getResourceColorIndexMapping(); return kity.Color.createHSL(h, 100, 85);
var nextIndex; });
if (!colorMapping.hasOwnProperty(resource)) {
// 找不到找下个可用索引
nextIndex = this._getNextResourceColorIndex();
colorMapping[resource] = nextIndex;
}
// 资源过多,找不到可用索引颜色,统一返回白色 var RESOURCE_COLOR_OVERFLOW = kity.Color.createHSL(0, 0, 95);
return RESOURCE_COLOR_SERIES[colorMapping[resource]] || RESOURCE_COLOR_OVERFLOW;
},
/** /**
* 获得已使用的资源的列表 * 在 Minder 上拓展一些关于资源的支持接口
*
* @return {Array}
*/ */
getUsedResource: function() { kity.extendClass(Minder, {
var mapping = this._getResourceColorIndexMapping();
var used = [], /**
resource; * 获取脑图中某个资源对应的颜色
*
for (resource in mapping) { * 如果存在同名资源,则返回已经分配给该资源的颜色,否则分配给该资源一个颜色,并且返回
if (mapping.hasOwnProperty(resource)) { *
used.push(resource); * 如果资源数超过颜色序列数量,返回白色
*
* @param {String} resource 资源名称
* @return {Color}
*/
getResourceColor: function(resource) {
var colorMapping = this._getResourceColorIndexMapping();
var nextIndex;
if (!colorMapping.hasOwnProperty(resource)) {
// 找不到找下个可用索引
nextIndex = this._getNextResourceColorIndex();
colorMapping[resource] = nextIndex;
} }
}
return used; // 资源过多,找不到可用索引颜色,统一返回白色
}, return RESOURCE_COLOR_SERIES[colorMapping[resource]] || RESOURCE_COLOR_OVERFLOW;
},
/**
* 获得已使用的资源的列表
*
* @return {Array}
*/
getUsedResource: function() {
var mapping = this._getResourceColorIndexMapping();
var used = [],
resource;
for (resource in mapping) {
if (mapping.hasOwnProperty(resource)) {
used.push(resource);
}
}
/** return used;
* 获取脑图下一个可用的资源颜色索引 },
*
* @return {int} /**
*/ * 获取脑图下一个可用的资源颜色索引
_getNextResourceColorIndex: function() { *
// 获取现有颜色映射 * @return {int}
// resource => color_index */
var colorMapping = this._getResourceColorIndexMapping(); _getNextResourceColorIndex: function() {
// 获取现有颜色映射
// resource => color_index
var colorMapping = this._getResourceColorIndexMapping();
var resource, used, i; var resource, used, i;
used = []; used = [];
// 抽取已经使用的值到 used 数组 // 抽取已经使用的值到 used 数组
for (resource in colorMapping) { for (resource in colorMapping) {
if (colorMapping.hasOwnProperty(resource)) { if (colorMapping.hasOwnProperty(resource)) {
used.push(colorMapping[resource]); used.push(colorMapping[resource]);
}
} }
}
// 枚举所有的可用值,如果还没被使用,返回 // 枚举所有的可用值,如果还没被使用,返回
for (i = 0; i < RESOURCE_COLOR_SERIES.length; i++) { for (i = 0; i < RESOURCE_COLOR_SERIES.length; i++) {
if (!~used.indexOf(i)) return i; if (!~used.indexOf(i)) return i;
} }
// 没有可用的颜色了 // 没有可用的颜色了
return -1; return -1;
}, },
// 获取现有颜色映射 // 获取现有颜色映射
// resource => color_index // resource => color_index
_getResourceColorIndexMapping: function() { _getResourceColorIndexMapping: function() {
return this._resourceColorMapping || (this._resourceColorMapping = {}); return this._resourceColorMapping || (this._resourceColorMapping = {});
} }
}); });
/** /**
* @class 设置资源的命令 * @class 设置资源的命令
* *
* @example * @example
* *
* // 设置选中节点资源为 "张三" * // 设置选中节点资源为 "张三"
* minder.execCommand('resource', ['张三']); * minder.execCommand('resource', ['张三']);
* *
* // 添加资源 "李四" 到选中节点 * // 添加资源 "李四" 到选中节点
* var resource = minder.queryCommandValue(); * var resource = minder.queryCommandValue();
* resource.push('李四'); * resource.push('李四');
* minder.execCommand('resource', resource); * minder.execCommand('resource', resource);
* *
* // 清除选中节点的资源 * // 清除选中节点的资源
* minder.execCommand('resource', null); * minder.execCommand('resource', null);
*/ */
var ResourceCommand = kity.createClass('ResourceCommand', { var ResourceCommand = kity.createClass('ResourceCommand', {
base: Command,
execute: function(minder, resource) {
var nodes = minder.getSelectedNodes();
if (typeof(resource) == 'string') {
resource = [resource];
}
nodes.forEach(function(node) { base: Command,
node.setData('resource', resource).render();
});
minder.layout(200); execute: function(minder, resource) {
}, var nodes = minder.getSelectedNodes();
queryValue: function(minder) { if (typeof(resource) == 'string') {
var nodes = minder.getSelectedNodes(); resource = [resource];
var resource = []; }
nodes.forEach(function(node) { nodes.forEach(function(node) {
var nodeResource = node.getData('resource'); node.setData('resource', resource).render();
});
if (!nodeResource) return; minder.layout(200);
},
nodeResource.forEach(function(name) { queryValue: function(minder) {
if (!~resource.indexOf(name)) { var nodes = minder.getSelectedNodes();
resource.push(name); var resource = [];
}
});
});
return resource; nodes.forEach(function(node) {
}, var nodeResource = node.getData('resource');
queryState: function(km) { if (!nodeResource) return;
return km.getSelectedNode() ? 0 : -1;
}
});
/** nodeResource.forEach(function(name) {
* @class 资源的覆盖图形 if (!~resource.indexOf(name)) {
* resource.push(name);
* 该类为一个资源以指定的颜色渲染一个动态的覆盖图形 }
*/ });
var ResourceOverlay = kity.createClass('ResourceOverlay', { });
base: kity.Group,
constructor: function() { return resource;
this.callBase(); },
var text, rect; queryState: function(km) {
return km.getSelectedNode() ? 0 : -1;
}
});
rect = this.rect = new kity.Rect().setRadius(4); /**
* @class 资源的覆盖图形
*
* 该类为一个资源以指定的颜色渲染一个动态的覆盖图形
*/
var ResourceOverlay = kity.createClass('ResourceOverlay', {
base: kity.Group,
text = this.text = new kity.Text() constructor: function() {
.setFontSize(12) this.callBase();
.setVerticalAlign('middle');
this.addShapes([rect, text]); var text, rect;
},
setValue: function(resourceName, color) { rect = this.rect = new kity.Rect().setRadius(4);
var paddingX = 8,
paddingY = 4,
borderRadius = 4;
var text, box, rect;
text = this.text; text = this.text = new kity.Text()
.setFontSize(12)
.setVerticalAlign('middle');
if (resourceName == this.lastResourceName) { this.addShapes([rect, text]);
},
box = this.lastBox; setValue: function(resourceName, color) {
var paddingX = 8,
paddingY = 4,
borderRadius = 4;
var text, box, rect;
} else { text = this.text;
text.setContent(resourceName); if (resourceName == this.lastResourceName) {
box = text.getBoundaryBox(); box = this.lastBox;
this.lastResourceName = resourceName;
this.lastBox = box;
} } else {
text.setX(paddingX).fill(color.dec('l', 70)); text.setContent(resourceName);
rect = this.rect; box = text.getBoundaryBox();
rect.setPosition(0, box.y - paddingY); this.lastResourceName = resourceName;
this.width = Math.round(box.width + paddingX * 2); this.lastBox = box;
this.height = Math.round(box.height + paddingY * 2);
rect.setSize(this.width, this.height);
rect.fill(color);
}
});
/**
* @class 资源渲染器
*/
var ResourceRenderer = kity.createClass('ResourceRenderer', {
base: KityMinder.Renderer,
create: function(node) {
this.overlays = [];
return new kity.Group();
},
shouldRender: function(node) {
return node.getData('resource') && node.getData('resource').length;
},
update: function(container, node, box) {
var spaceRight = node.getStyle('space-right');
var overlays = this.overlays;
var resource = node.getData('resource');
var minder = node.getMinder();
var i, overlay, x;
x = 0;
for (i = 0; i < resource.length; i++) {
x += spaceRight;
overlay = overlays[i];
if (!overlay) {
overlay = new ResourceOverlay();
overlays.push(overlay);
container.addShape(overlay);
} }
overlay.setVisible(true);
overlay.setValue(resource[i], minder.getResourceColor(resource[i]));
overlay.setTranslate(x, -1);
x += overlay.width; text.setX(paddingX).fill(color.dec('l', 70));
rect = this.rect;
rect.setPosition(0, box.y - paddingY);
this.width = Math.round(box.width + paddingX * 2);
this.height = Math.round(box.height + paddingY * 2);
rect.setSize(this.width, this.height);
rect.fill(color);
} }
});
while ((overlay = overlays[i++])) overlay.setVisible(false); /**
* @class 资源渲染器
*/
var ResourceRenderer = kity.createClass('ResourceRenderer', {
base: Renderer,
create: function(node) {
this.overlays = [];
return new kity.Group();
},
shouldRender: function(node) {
return node.getData('resource') && node.getData('resource').length;
},
update: function(container, node, box) {
var spaceRight = node.getStyle('space-right');
var overlays = this.overlays;
var resource = node.getData('resource');
var minder = node.getMinder();
var i, overlay, x;
x = 0;
for (i = 0; i < resource.length; i++) {
x += spaceRight;
overlay = overlays[i];
if (!overlay) {
overlay = new ResourceOverlay();
overlays.push(overlay);
container.addShape(overlay);
}
overlay.setVisible(true);
overlay.setValue(resource[i], minder.getResourceColor(resource[i]));
overlay.setTranslate(x, -1);
container.setTranslate(box.right, 0); x += overlay.width;
}
return new kity.Box({ while ((overlay = overlays[i++])) overlay.setVisible(false);
x: box.right,
y: Math.round(-overlays[0].height / 2),
width: x,
height: overlays[0].height
});
}
});
return { container.setTranslate(box.right, 0);
commands: {
'resource': ResourceCommand
},
renderers: { return new kity.Box({
right: ResourceRenderer x: box.right,
} y: Math.round(-overlays[0].height / 2),
}; width: x,
height: overlays[0].height
});
}
});
return {
commands: {
'resource': ResourceCommand
},
renderers: {
right: ResourceRenderer
}
};
});
}); });
\ No newline at end of file
KityMinder.registerModule('Select', function() { define(function(require, exports, module) {
var minder = this; var kity = require('core/kity');
var rc = minder.getRenderContainer(); var utils = require('core/utils');
var g = KityMinder.Geometry;
var Minder = require('core/minder');
// 在实例上渲染框选矩形、计算框选范围的对象 var MinderNode = require('core/node');
var marqueeActivator = (function() { var Command = require('core/command');
var Module = require('core/module');
// 记录选区的开始位置(mousedown的位置) var Renderer = require('core/render');
var startPosition = null;
Module.register('Select', function() {
// 选区的图形 var minder = this;
var marqueeShape = new kity.Path(); var rc = minder.getRenderContainer();
// 标记是否已经启动框选状态 // 在实例上渲染框选矩形、计算框选范围的对象
// 并不是 mousedown 发生之后就启动框选状态,而是检测到移动了一定的距离(MARQUEE_MODE_THRESHOLD)之后 var marqueeActivator = (function() {
var marqueeMode = false;
var MARQUEE_MODE_THRESHOLD = 10; // 记录选区的开始位置(mousedown的位置)
var startPosition = null;
// 选区的图形
var marqueeShape = new kity.Path();
// 标记是否已经启动框选状态
// 并不是 mousedown 发生之后就启动框选状态,而是检测到移动了一定的距离(MARQUEE_MODE_THRESHOLD)之后
var marqueeMode = false;
var MARQUEE_MODE_THRESHOLD = 10;
return {
selectStart: function(e) {
// 只接受左键
if (e.originEvent.button || e.originEvent.altKey) return;
// 清理不正确状态
if (startPosition) {
return this.selectEnd();
}
return { startPosition = e.getPosition(rc).round();
selectStart: function(e) { },
// 只接受左键 selectMove: function(e) {
if (e.originEvent.button || e.originEvent.altKey) return; if (minder.getStatus() == 'textedit') {
return;
}
if (!startPosition) return;
var p1 = startPosition,
p2 = e.getPosition(rc);
// 检测是否要进入选区模式
if (!marqueeMode) {
// 距离没达到阈值,退出
if (kity.Vector.fromPoints(p1, p2).length() < MARQUEE_MODE_THRESHOLD) {
return;
}
// 已经达到阈值,记录下来并且重置选区形状
marqueeMode = true;
rc.addShape(marqueeShape);
marqueeShape
.fill(minder.getStyle('marquee-background'))
.stroke(minder.getStyle('marquee-stroke')).setOpacity(0.8).getDrawer().clear();
}
// 清理不正确状态 var marquee = new kity.Box(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y),
if (startPosition) { selectedNodes = [];
return this.selectEnd();
} // 使其犀利
marquee.left = Math.round(marquee.left);
marquee.top = Math.round(marquee.top);
marquee.right = Math.round(marquee.right);
marquee.bottom = Math.round(marquee.bottom);
// 选区形状更新
marqueeShape.getDrawer().pipe(function() {
this.clear();
this.moveTo(marquee.left, marquee.top);
this.lineTo(marquee.right, marquee.top);
this.lineTo(marquee.right, marquee.bottom);
this.lineTo(marquee.left, marquee.bottom);
this.close();
});
startPosition = e.getPosition(rc).round(); // 计算选中范围
}, minder.getRoot().traverse(function(node) {
selectMove: function(e) { var renderBox = node.getLayoutBox();
if (minder.getStatus() == 'textedit') { if (!renderBox.intersect(marquee).isEmpty()) {
return; selectedNodes.push(node);
} }
if (!startPosition) return; });
var p1 = startPosition, // 应用选中范围
p2 = e.getPosition(rc); minder.select(selectedNodes, true);
// 检测是否要进入选区模式 // 清除多余的东西
if (!marqueeMode) { window.getSelection().removeAllRanges();
// 距离没达到阈值,退出 },
if (kity.Vector.fromPoints(p1, p2).length() < MARQUEE_MODE_THRESHOLD) { selectEnd: function(e) {
return; if (startPosition) {
startPosition = null;
}
if (marqueeMode) {
marqueeShape.fadeOut(200, 'ease', 0, function() {
if (marqueeShape.remove) marqueeShape.remove();
});
marqueeMode = false;
} }
// 已经达到阈值,记录下来并且重置选区形状
marqueeMode = true;
rc.addShape(marqueeShape);
marqueeShape
.fill(minder.getStyle('marquee-background'))
.stroke(minder.getStyle('marquee-stroke')).setOpacity(0.8).getDrawer().clear();
} }
};
})();
var marquee = new kity.Box(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y), var lastDownNode = null,
selectedNodes = []; lastDownPosition = null;
return {
// 使其犀利 'init': function() {
marquee.left = Math.round(marquee.left); window.addEventListener('mouseup', function() {
marquee.top = Math.round(marquee.top); marqueeActivator.selectEnd();
marquee.right = Math.round(marquee.right);
marquee.bottom = Math.round(marquee.bottom);
// 选区形状更新
marqueeShape.getDrawer().pipe(function() {
this.clear();
this.moveTo(marquee.left, marquee.top);
this.lineTo(marquee.right, marquee.top);
this.lineTo(marquee.right, marquee.bottom);
this.lineTo(marquee.left, marquee.bottom);
this.close();
}); });
},
'events': {
'mousedown': function(e) {
// 计算选中范围 var downNode = e.getTargetNode();
minder.getRoot().traverse(function(node) {
var renderBox = node.getLayoutBox();
if (!renderBox.intersect(marquee).isEmpty()) {
selectedNodes.push(node);
}
});
// 应用选中范围 // 没有点中节点:
minder.select(selectedNodes, true); // 清除选中状态,并且标记选区开始位置
if (!downNode) {
this.removeAllSelectedNodes();
marqueeActivator.selectStart(e);
// 清除多余的东西 this.setStatus('normal');
window.getSelection().removeAllRanges(); }
},
selectEnd: function(e) {
if (startPosition) {
startPosition = null;
}
if (marqueeMode) {
marqueeShape.fadeOut(200, 'ease', 0, function() {
if (marqueeShape.remove) marqueeShape.remove();
});
marqueeMode = false;
}
}
};
})();
var lastDownNode = null, lastDownPosition = null;
return {
'init': function() {
window.addEventListener('mouseup', function() {
marqueeActivator.selectEnd();
});
},
'events': {
'mousedown': function(e) {
var downNode = e.getTargetNode();
// 没有点中节点:
// 清除选中状态,并且标记选区开始位置
if (!downNode) {
this.removeAllSelectedNodes();
marqueeActivator.selectStart(e);
this.setStatus('normal');
}
// 点中了节点,并且按了 shift 键: // 点中了节点,并且按了 shift 键:
// 被点中的节点切换选中状态 // 被点中的节点切换选中状态
else if (e.originEvent.shiftKey) { else if (e.originEvent.shiftKey) {
this.toggleSelect(downNode); this.toggleSelect(downNode);
} }
// 点中的节点没有被选择: // 点中的节点没有被选择:
// 单选点中的节点 // 单选点中的节点
else if (!downNode.isSelected()) { else if (!downNode.isSelected()) {
this.select(downNode, true); this.select(downNode, true);
} }
// 点中的节点被选中了,并且不是单选: // 点中的节点被选中了,并且不是单选:
// 完成整个点击之后需要使其变为单选。 // 完成整个点击之后需要使其变为单选。
// 不能马上变为单选,因为可能是需要拖动选中的多个节点 // 不能马上变为单选,因为可能是需要拖动选中的多个节点
else if (!this.isSingleSelect()) { else if (!this.isSingleSelect()) {
lastDownNode = downNode; lastDownNode = downNode;
lastDownPosition = e.getPosition(this.getRenderContainer()); lastDownPosition = e.getPosition(this.getRenderContainer());
} }
}, },
'mousemove': marqueeActivator.selectMove, 'mousemove': marqueeActivator.selectMove,
'mouseup': function(e) { 'mouseup': function(e) {
var upNode = e.getTargetNode(); var upNode = e.getTargetNode();
// 如果 mouseup 发生在 lastDownNode 外,是无需理会的 // 如果 mouseup 发生在 lastDownNode 外,是无需理会的
if (upNode && upNode == lastDownNode) { if (upNode && upNode == lastDownNode) {
var upPosition = e.getPosition(this.getRenderContainer()); var upPosition = e.getPosition(this.getRenderContainer());
var movement = kity.Vector.fromPoints(lastDownPosition, upPosition); var movement = kity.Vector.fromPoints(lastDownPosition, upPosition);
if (movement.length() < 1) this.select(lastDownNode, true); if (movement.length() < 1) this.select(lastDownNode, true);
lastDownNode = null; lastDownNode = null;
} }
// 清理一下选择状态 // 清理一下选择状态
marqueeActivator.selectEnd(e); marqueeActivator.selectEnd(e);
}, },
//全选操作 //全选操作
'normal.keydown inputready.keydown':function(e){ 'normal.keydown inputready.keydown': function(e) {
if ( e.isShortcutKey('ctrl+a') ){ if (e.isShortcutKey('ctrl+a')) {
var selectedNodes = []; var selectedNodes = [];
this.getRoot().traverse(function(node){ this.getRoot().traverse(function(node) {
selectedNodes.push(node); selectedNodes.push(node);
}); });
this.select(selectedNodes,true); this.select(selectedNodes, true);
e.preventDefault(); e.preventDefault();
}
} }
} }
} };
}; });
}); });
\ No newline at end of file
KityMinder.registerModule('StyleModule', function() { define(function(require, exports, module) {
var styleNames = ['font-size', 'font-family', 'font-weight', 'font-style', 'background', 'color']; var kity = require('core/kity');
var styleClipBoard = null; var utils = require('core/utils');
function hasStyle(node) { var Minder = require('core/minder');
var data = node.getData(); var MinderNode = require('core/node');
for(var i = 0; i < styleNames.length; i++) { var Command = require('core/command');
if (styleNames[i] in data) return true; var Module = require('core/module');
var Renderer = require('core/render');
Module.register('StyleModule', function() {
var styleNames = ['font-size', 'font-family', 'font-weight', 'font-style', 'background', 'color'];
var styleClipBoard = null;
function hasStyle(node) {
var data = node.getData();
for (var i = 0; i < styleNames.length; i++) {
if (styleNames[i] in data) return true;
}
} }
}
return { return {
"commands": { 'commands': {
"copystyle": kity.createClass("CopyStyleCommand", { 'copystyle': kity.createClass('CopyStyleCommand', {
base: Command, base: Command,
execute: function(minder) { execute: function(minder) {
var node = minder.getSelectedNode(); var node = minder.getSelectedNode();
var nodeData = node.getData(); var nodeData = node.getData();
styleClipBoard = {}; styleClipBoard = {};
styleNames.forEach(function(name) { styleNames.forEach(function(name) {
if (name in nodeData) styleClipBoard[name] = nodeData[name]; if (name in nodeData) styleClipBoard[name] = nodeData[name];
else { else {
styleClipBoard[name] = null; styleClipBoard[name] = null;
delete styleClipBoard[name]; delete styleClipBoard[name];
} }
}); });
return styleClipBoard; return styleClipBoard;
}, },
queryState: function(minder) { queryState: function(minder) {
var nodes = minder.getSelectedNodes(); var nodes = minder.getSelectedNodes();
if (nodes.length !== 1) return -1; if (nodes.length !== 1) return -1;
return hasStyle(nodes[0]) ? 0 : -1; return hasStyle(nodes[0]) ? 0 : -1;
} }
}), }),
"pastestyle": kity.createClass("PastStyleCommand", { 'pastestyle': kity.createClass('PastStyleCommand', {
base: Command, base: Command,
execute: function(minder) { execute: function(minder) {
minder.getSelectedNodes().forEach(function(node) { minder.getSelectedNodes().forEach(function(node) {
for (var name in styleClipBoard) { for (var name in styleClipBoard) {
if (styleClipBoard.hasOwnProperty(name)) if (styleClipBoard.hasOwnProperty(name))
node.setData(name, styleClipBoard[name]); node.setData(name, styleClipBoard[name]);
} }
}); });
minder.renderNodeBatch(minder.getSelectedNodes()); minder.renderNodeBatch(minder.getSelectedNodes());
minder.layout(300); minder.layout(300);
return styleClipBoard; return styleClipBoard;
}, },
queryState: function(minder) { queryState: function(minder) {
return (styleClipBoard && minder.getSelectedNodes().length) ? 0 : -1; return (styleClipBoard && minder.getSelectedNodes().length) ? 0 : -1;
} }
}), }),
"clearstyle": kity.createClass("ClearStyleCommand", { 'clearstyle': kity.createClass('ClearStyleCommand', {
base: Command, base: Command,
execute: function(minder) { execute: function(minder) {
minder.getSelectedNodes().forEach(function(node) { minder.getSelectedNodes().forEach(function(node) {
styleNames.forEach(function(name) { styleNames.forEach(function(name) {
node.setData(name); node.setData(name);
});
}); });
}); minder.renderNodeBatch(minder.getSelectedNodes());
minder.renderNodeBatch(minder.getSelectedNodes()); minder.layout(300);
minder.layout(300); return styleClipBoard;
return styleClipBoard; },
},
queryState: function(minder) { queryState: function(minder) {
var nodes = minder.getSelectedNodes(); var nodes = minder.getSelectedNodes();
if (!nodes.length) return -1; if (!nodes.length) return -1;
for(var i = 0; i < nodes.length; i++) { for (var i = 0; i < nodes.length; i++) {
if (hasStyle(nodes[i])) return 0; if (hasStyle(nodes[i])) return 0;
}
return -1;
} }
return -1; })
} }
}) };
} });
};
}); });
\ No newline at end of file
/* global Renderer: true */ define(function(require, exports, module) {
var kity = require('core/kity');
var utils = require('core/utils');
var Minder = require('core/minder');
var MinderNode = require('core/node');
var Command = require('core/command');
var Module = require('core/module');
var Renderer = require('core/render');
var FONT_ADJUST = {
'微软雅黑,Microsoft YaHei': -0.15,
'arial black,avant garde': -0.17,
'default': -0.15
};
var TextRenderer = kity.createClass('TextRenderer', {
base: Renderer,
create: function() {
return new kity.Group().setId(utils.uuid('node_text'));
},
update: function(textGroup, node) {
function s(name) {
return node.getData(name) || node.getStyle(name);
}
var FONT_ADJUST = { var nodeText = node.getText() || '';
'微软雅黑,Microsoft YaHei': -0.15, var textArr = nodeText.split('\n');
'arial black,avant garde': -0.17,
'default': -0.15
};
var TextRenderer = KityMinder.TextRenderer = kity.createClass('TextRenderer', { var lineHeight = node.getStyle('line-height');
base: Renderer,
create: function() { var fontSize = s('font-size');
return new kity.Group().setId(KityMinder.uuid('node_text')); var fontFamily = s('font-family') || 'default';
},
update: function(textGroup, node) { var height = (lineHeight * fontSize) * textArr.length - (lineHeight - 1) * fontSize;
var yStart = -height / 2;
function s(name) { var adjust = FONT_ADJUST[fontFamily] || 0;
return node.getData(name) || node.getStyle(name);
}
var textArr = node.getText(true); textGroup.setTranslate(0, adjust * fontSize);
var lineHeight = node.getStyle('line-height'); var rBox = new kity.Box(),
r = Math.round;
var fontSize = s('font-size'); this.setTextStyle(node, textGroup);
var fontFamily = s('font-family') || 'default';
var height = (lineHeight * fontSize) * textArr.length - (lineHeight - 1) * fontSize; var textLength = textArr.length;
var yStart = -height / 2;
var adjust = FONT_ADJUST[fontFamily] || 0; var textGroupLength = textGroup.getItems().length;
textGroup.setTranslate(0, adjust * fontSize); var i, ci, textShape, text;
var rBox = new kity.Box(), if (textLength < textGroupLength) {
r = Math.round; for (i = textLength, ci; ci = textGroup.getItem(i);) {
textGroup.removeItem(i);
}
} else if (textLength > textGroupLength) {
var length = textLength - textGroupLength;
for (i = 0; i < length; i++) {
textShape = new kity.Text()
.setAttr('text-rendering', 'inherit');
if (kity.Browser.ie) {
textShape.setVerticalAlign('top');
} else {
textShape.setAttr('dominant-baseline', 'text-before-edge');
}
textGroup.addItem(textShape);
}
}
this.setTextStyle(node, textGroup);
var textLength = textArr.length; for (i = 0, text, textShape;
(text = textArr[i], textShape = textGroup.getItem(i)); i++) {
textShape.setContent(text);
}
var textGroupLength = textGroup.getItems().length; this.setTextStyle(node, textGroup);
if(textLength < textGroupLength){ var textHash = node.getText() +
for( var i = textLength,ci;ci = textGroup.getItem(i);){ [s('font-size'), s('font-name'), s('font-weight'), s('font-style')].join('/');
textGroup.removeItem(i);
}
}else if(textLength > textGroupLength){
var length = textLength - textGroupLength;
for(var i = 0;i < length;i++){
var textShape = new kity.Text()
.setAttr('text-rendering', 'inherit');
if (kity.Browser.ie) {
textShape.setVerticalAlign('top');
} else {
textShape.setAttr('dominant-baseline', 'text-before-edge');
}
textGroup.addItem(textShape);
}
}
if (node._currentTextHash == textHash && node._currentTextGroupBox) return node._currentTextGroupBox;
for (var i = 0, text, textShape; node._currentTextHash = textHash;
(text = textArr[i], textShape = textGroup.getItem(i)); i++) {
textShape.setContent(text);
}
this.setTextStyle(node, textGroup); return function() {
textGroup.eachItem(function(i, textShape) {
var y = yStart + i * fontSize * lineHeight;
var textHash = node.getText() + [s('font-size'), s('font-name'), s('font-weight'), s('font-style')].join('/'); textShape.setY(y);
if (node._currentTextHash == textHash && node._currentTextGroupBox) return node._currentTextGroupBox; rBox = rBox.merge(new kity.Box(0, y, textShape.getBoundaryBox().width || 1, fontSize));
});
node._currentTextHash = textHash; var nBox = new kity.Box(r(rBox.x), r(rBox.y), r(rBox.width), r(rBox.height));
return function() { node._currentTextGroupBox = nBox;
textGroup.eachItem(function(i, textShape) { return nBox;
var y = yStart + i * fontSize * lineHeight; };
textShape.setY(y); },
rBox = rBox.merge(new kity.Box(0, y, textShape.getBoundaryBox().width || 1, fontSize)); setTextStyle: function(node, text) {
var hooks = TextRenderer._styleHooks;
hooks.forEach(function(hook) {
hook(node, text);
}); });
}
});
utils.extend(TextRenderer, {
_styleHooks: [],
registerStyleHook: function(fn) {
TextRenderer._styleHooks.push(fn);
}
});
kity.extendClass(MinderNode, {
getTextGroup: function() {
return this.getRenderer('TextRenderer').getRenderShape();
}
});
Module.register('text', {
'renderers': {
center: TextRenderer
}
});
var nBox = new kity.Box(r(rBox.x), r(rBox.y), r(rBox.width), r(rBox.height)); module.exports = TextRenderer;
node._currentTextGroupBox = nBox;
return nBox;
};
},
setTextStyle: function(node, text) {
var hooks = TextRenderer._styleHooks;
hooks.forEach(function(hook) {
hook(node, text);
});
}
});
utils.extend(TextRenderer, {
_styleHooks: [],
registerStyleHook: function(fn) {
TextRenderer._styleHooks.push(fn);
}
});
kity.extendClass(MinderNode, {
getTextGroup: function() {
return this.getRenderer('TextRenderer').getRenderShape();
}
});
KityMinder.registerModule('text', {
'renderers': {
center: TextRenderer
}
}); });
\ No newline at end of file
var ViewDragger = kity.createClass("ViewDragger", { define(function(require, exports, module) {
constructor: function(minder) { var kity = require('core/kity');
this._minder = minder; var utils = require('core/utils');
this._enabled = false;
this._bind(); var Minder = require('core/minder');
var me = this; var MinderNode = require('core/node');
this._minder.getViewDragger = function() { var Command = require('core/command');
return me; var Module = require('core/module');
}; var Renderer = require('core/render');
},
var ViewDragger = kity.createClass('ViewDragger', {
constructor: function(minder) {
this._minder = minder;
this._enabled = false;
this._bind();
var me = this;
this._minder.getViewDragger = function() {
return me;
};
},
isEnabled: function() { isEnabled: function() {
return this._enabled; return this._enabled;
}, },
setEnabled: function(value) { setEnabled: function(value) {
var paper = this._minder.getPaper(); var paper = this._minder.getPaper();
paper.setStyle('cursor', value ? 'pointer' : 'default'); paper.setStyle('cursor', value ? 'pointer' : 'default');
paper.setStyle('cursor', value ? '-webkit-grab' : 'default'); paper.setStyle('cursor', value ? '-webkit-grab' : 'default');
this._enabled = value; this._enabled = value;
}, },
move: function(offset, duration) { move: function(offset, duration) {
var minder = this._minder; var minder = this._minder;
var targetPosition = this.getMovement().offset(offset); var targetPosition = this.getMovement().offset(offset);
this.moveTo(targetPosition, duration); this.moveTo(targetPosition, duration);
}, },
moveTo: function(position, duration) { moveTo: function(position, duration) {
if (duration) { if (duration) {
var dragger = this; var dragger = this;
if (this._moveTimeline) this._moveTimeline.stop(); if (this._moveTimeline) this._moveTimeline.stop();
this._moveTimeline = this._minder.getRenderContainer().animate(new kity.Animator( this._moveTimeline = this._minder.getRenderContainer().animate(new kity.Animator(
this.getMovement(), this.getMovement(),
position, position,
function(target, value) { function(target, value) {
dragger.moveTo(value); dragger.moveTo(value);
} }
), duration, 'easeOutCubic'); ), duration, 'easeOutCubic');
this._moveTimeline.on('finish', function() { this._moveTimeline.on('finish', function() {
dragger._moveTimeline = null; dragger._moveTimeline = null;
}); });
return this; return this;
} }
this._minder.getRenderContainer().setTranslate(position.round()); this._minder.getRenderContainer().setTranslate(position.round());
this._minder.fire('viewchange'); this._minder.fire('viewchange');
}, },
getMovement: function() { getMovement: function() {
var translate = this._minder.getRenderContainer().transform.translate; var translate = this._minder.getRenderContainer().transform.translate;
return translate ? translate[0] : new kity.Point(); return translate ? translate[0] : new kity.Point();
}, },
getView: function() { getView: function() {
var minder = this._minder; var minder = this._minder;
var c = { var c = {
width: minder.getRenderTarget().clientWidth, width: minder.getRenderTarget().clientWidth,
height: minder.getRenderTarget().clientHeight height: minder.getRenderTarget().clientHeight
}; };
var m = this.getMovement(); var m = this.getMovement();
var box = new kity.Box(0, 0, c.width, c.height); var box = new kity.Box(0, 0, c.width, c.height);
var viewMatrix = minder.getPaper().getViewPortMatrix(); var viewMatrix = minder.getPaper().getViewPortMatrix();
return viewMatrix.inverse().translate(-m.x, -m.y).transformBox(box); return viewMatrix.inverse().translate(-m.x, -m.y).transformBox(box);
}, },
_bind: function() {
var dragger = this,
isTempDrag = false,
lastPosition = null,
currentPosition = null;
function dragEnd(e) {
if (!lastPosition) return;
lastPosition = null;
e.stopPropagation();
// 临时拖动需要还原状态
if (isTempDrag) {
dragger.setEnabled(false);
isTempDrag = false;
if (dragger._minder.getStatus() == 'hand')
dragger._minder.rollbackStatus();
}
var paper = dragger._minder.getPaper();
paper.setStyle('cursor', dragger._minder.getStatus() == 'hand' ? '-webkit-grab' : 'default');
}
this._minder.on('normal.mousedown normal.touchstart ' + _bind: function() {
'inputready.mousedown inputready.touchstart ' + var dragger = this,
'readonly.mousedown readonly.touchstart', function(e) { isTempDrag = false,
if (e.originEvent.button == 2) { lastPosition = null,
e.originEvent.preventDefault(); // 阻止中键拉动 currentPosition = null;
}
// 点击未选中的根节点临时开启
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
lastPosition = e.getPosition();
isTempDrag = true;
}
})
.on('normal.mousemove normal.touchmove ' + function dragEnd(e) {
'readonly.mousemove readonly.touchmove ' + if (!lastPosition) return;
'inputready.mousemove inputready.touchmove', function(e) {
if (e.type == 'touchmove') { lastPosition = null;
e.preventDefault(); // 阻止浏览器的后退事件
e.stopPropagation();
// 临时拖动需要还原状态
if (isTempDrag) {
dragger.setEnabled(false);
isTempDrag = false;
if (dragger._minder.getStatus() == 'hand')
dragger._minder.rollbackStatus();
} }
if (!isTempDrag) return; var paper = dragger._minder.getPaper();
var offset = kity.Vector.fromPoints(lastPosition, e.getPosition()); paper.setStyle('cursor', dragger._minder.getStatus() == 'hand' ? '-webkit-grab' : 'default');
if (offset.length() > 10) { }
this.setStatus('hand', true);
this._minder.on('normal.mousedown normal.touchstart ' +
'inputready.mousedown inputready.touchstart ' +
'readonly.mousedown readonly.touchstart',
function(e) {
if (e.originEvent.button == 2) {
e.originEvent.preventDefault(); // 阻止中键拉动
}
// 点击未选中的根节点临时开启
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
lastPosition = e.getPosition();
isTempDrag = true;
}
})
.on('normal.mousemove normal.touchmove ' +
'readonly.mousemove readonly.touchmove ' +
'inputready.mousemove inputready.touchmove',
function(e) {
if (e.type == 'touchmove') {
e.preventDefault(); // 阻止浏览器的后退事件
}
if (!isTempDrag) return;
var offset = kity.Vector.fromPoints(lastPosition, e.getPosition());
if (offset.length() > 10) {
this.setStatus('hand', true);
var paper = dragger._minder.getPaper();
paper.setStyle('cursor', '-webkit-grabbing');
}
})
.on('hand.beforemousedown hand.beforetouchstart', function(e) {
// 已经被用户打开拖放模式
if (dragger.isEnabled()) {
lastPosition = e.getPosition();
e.stopPropagation();
var paper = dragger._minder.getPaper(); var paper = dragger._minder.getPaper();
paper.setStyle('cursor', '-webkit-grabbing'); paper.setStyle('cursor', '-webkit-grabbing');
} }
}) })
.on('hand.beforemousedown hand.beforetouchstart', function(e) { .on('hand.beforemousemove hand.beforetouchmove', function(e) {
// 已经被用户打开拖放模式 if (lastPosition) {
if (dragger.isEnabled()) { currentPosition = e.getPosition();
lastPosition = e.getPosition();
e.stopPropagation(); // 当前偏移加上历史偏移
var paper = dragger._minder.getPaper(); var offset = kity.Vector.fromPoints(lastPosition, currentPosition);
paper.setStyle('cursor', '-webkit-grabbing'); dragger.move(offset);
} e.stopPropagation();
}) e.preventDefault();
e.originEvent.preventDefault();
lastPosition = currentPosition;
}
})
.on('hand.beforemousemove hand.beforetouchmove', function(e) { .on('mouseup touchend', dragEnd);
if (lastPosition) {
currentPosition = e.getPosition();
// 当前偏移加上历史偏移 window.addEventListener('mouseup', dragEnd);
var offset = kity.Vector.fromPoints(lastPosition, currentPosition); this._minder.on('contextmenu', function(e) {
dragger.move(offset);
e.stopPropagation();
e.preventDefault(); e.preventDefault();
e.originEvent.preventDefault(); });
lastPosition = currentPosition; }
}
})
.on('mouseup touchend', dragEnd);
window.addEventListener('mouseup', dragEnd);
this._minder.on('contextmenu', function(e) {
e.preventDefault();
});
}
});
KityMinder.registerModule('View', function() {
var km = this;
var ToggleHandCommand = kity.createClass('ToggleHandCommand', {
base: Command,
execute: function(minder) {
if (minder.getStatus() != 'hand') {
minder.setStatus('hand', true);
} else {
minder.rollbackStatus();
}
this.setContentChanged(false);
},
queryState: function(minder) {
return minder.getStatus() == 'hand' ? 1 : 0;
},
enableReadOnly: true
}); });
var CameraCommand = kity.createClass('CameraCommand', { Module.register('View', function() {
base: Command,
execute: function(km, focusNode, duration) {
focusNode = focusNode || km.getRoot(); var km = this;
var viewport = km.getPaper().getViewPort();
var offset = focusNode.getRenderContainer().getRenderBox('view');
var dx = viewport.center.x - offset.x - offset.width / 2,
dy = viewport.center.y - offset.y;
var dragger = km._viewDragger;
dragger.move(new kity.Point(dx, dy), duration);
this.setContentChanged(false);
},
enableReadOnly: true
});
var MoveCommand = kity.createClass('MoveCommand', { var ToggleHandCommand = kity.createClass('ToggleHandCommand', {
base: Command, base: Command,
execute: function(minder) {
execute: function(km, dir, duration) {
var dragger = km._viewDragger;
var size = km._lastClientSize;
switch (dir) {
case 'up':
dragger.move(new kity.Point(0, size.height / 2), duration);
break;
case 'down':
dragger.move(new kity.Point(0, -size.height / 2), duration);
break;
case 'left':
dragger.move(new kity.Point(size.width / 2, 0), duration);
break;
case 'right':
dragger.move(new kity.Point(-size.width / 2, 0), duration);
break;
}
},
enableReadOnly: true if (minder.getStatus() != 'hand') {
}); minder.setStatus('hand', true);
} else {
minder.rollbackStatus();
}
this.setContentChanged(false);
return {
init: function() {
this._viewDragger = new ViewDragger(this);
},
commands: {
'hand': ToggleHandCommand,
'camera': CameraCommand,
'move': MoveCommand
},
events: {
statuschange: function(e) {
this._viewDragger.setEnabled(e.currentStatus == 'hand');
}, },
mousewheel: function(e) { queryState: function(minder) {
var dx, dy; return minder.getStatus() == 'hand' ? 1 : 0;
e = e.originEvent; },
if (e.ctrlKey || e.shiftKey) return; enableReadOnly: true
if ('wheelDeltaX' in e) { });
dx = e.wheelDeltaX || 0; var CameraCommand = kity.createClass('CameraCommand', {
dy = e.wheelDeltaY || 0; base: Command,
execute: function(km, focusNode, duration) {
} else { focusNode = focusNode || km.getRoot();
var viewport = km.getPaper().getViewPort();
var offset = focusNode.getRenderContainer().getRenderBox('view');
var dx = viewport.center.x - offset.x - offset.width / 2,
dy = viewport.center.y - offset.y;
var dragger = km._viewDragger;
dx = 0; dragger.move(new kity.Point(dx, dy), duration);
dy = e.wheelDelta; this.setContentChanged(false);
},
enableReadOnly: true
});
var MoveCommand = kity.createClass('MoveCommand', {
base: Command,
execute: function(km, dir, duration) {
var dragger = km._viewDragger;
var size = km._lastClientSize;
switch (dir) {
case 'up':
dragger.move(new kity.Point(0, size.height / 2), duration);
break;
case 'down':
dragger.move(new kity.Point(0, -size.height / 2), duration);
break;
case 'left':
dragger.move(new kity.Point(size.width / 2, 0), duration);
break;
case 'right':
dragger.move(new kity.Point(-size.width / 2, 0), duration);
break;
} }
},
this._viewDragger.move({ enableReadOnly: true
x: dx / 2.5, });
y: dy / 2.5
});
e.preventDefault(); return {
init: function() {
this._viewDragger = new ViewDragger(this);
}, },
'normal.dblclick readonly.dblclick': function(e) { commands: {
if (e.kityEvent.targetShape instanceof kity.Paper) { 'hand': ToggleHandCommand,
this.execCommand('camera', this.getRoot(), 800); 'camera': CameraCommand,
} 'move': MoveCommand
}, },
ready: function() { events: {
this.execCommand('camera', null, 0); statuschange: function(e) {
this._lastClientSize = { this._viewDragger.setEnabled(e.currentStatus == 'hand');
width: this.getRenderTarget().clientWidth, },
height: this.getRenderTarget().clientHeight mousewheel: function(e) {
}; var dx, dy;
}, e = e.originEvent;
resize: function(e) { if (e.ctrlKey || e.shiftKey) return;
var a = { if ('wheelDeltaX' in e) {
dx = e.wheelDeltaX || 0;
dy = e.wheelDeltaY || 0;
} else {
dx = 0;
dy = e.wheelDelta;
}
this._viewDragger.move({
x: dx / 2.5,
y: dy / 2.5
});
e.preventDefault();
},
'normal.dblclick readonly.dblclick': function(e) {
if (e.kityEvent.targetShape instanceof kity.Paper) {
this.execCommand('camera', this.getRoot(), 800);
}
},
ready: function() {
this.execCommand('camera', null, 0);
this._lastClientSize = {
width: this.getRenderTarget().clientWidth, width: this.getRenderTarget().clientWidth,
height: this.getRenderTarget().clientHeight height: this.getRenderTarget().clientHeight
}, };
b = this._lastClientSize; },
this._viewDragger.move( resize: function(e) {
new kity.Point((a.width - b.width) / 2 | 0, (a.height - b.height) / 2 | 0)); var a = {
this._lastClientSize = a; width: this.getRenderTarget().clientWidth,
}, height: this.getRenderTarget().clientHeight
'selectionchange layoutallfinish': function(e) { },
var selected = this.getSelectedNode(); b = this._lastClientSize;
this._viewDragger.move(
if (!selected) return; new kity.Point((a.width - b.width) / 2 | 0, (a.height - b.height) / 2 | 0));
this._lastClientSize = a;
var dragger = this._viewDragger; },
var view = dragger.getView(); 'selectionchange layoutallfinish': function(e) {
var focus = selected.getLayoutBox(); var selected = this.getSelectedNode();
var space = 50;
var dx = 0, dy = 0; if (!selected) return;
if (focus.right > view.right) { var dragger = this._viewDragger;
dx += view.right - focus.right - space; var view = dragger.getView();
} var focus = selected.getLayoutBox();
else if (focus.left < view.left) { var space = 50;
dx += view.left - focus.left + space; var dx = 0,
} dy = 0;
if (focus.bottom > view.bottom) { if (focus.right > view.right) {
dy += view.bottom - focus.bottom - space; dx += view.right - focus.right - space;
} } else if (focus.left < view.left) {
if (focus.top < view.top) { dx += view.left - focus.left + space;
dy += view.top - focus.top + space; }
if (focus.bottom > view.bottom) {
dy += view.bottom - focus.bottom - space;
}
if (focus.top < view.top) {
dy += view.top - focus.top + space;
}
if (dx || dy) {
dragger.move(new kity.Point(dx, dy), 100);
}
} }
if (dx || dy) dragger.move(new kity.Point(dx, dy), 100);
} }
} };
}; });
}); });
\ No newline at end of file
KityMinder.registerModule('Zoom', function() { define(function(require, exports, module) {
var me = this; var kity = require('core/kity');
var utils = require('core/utils');
var timeline;
function setTextRendering() {
var value = me._zoomValue >= 100 ? 'optimize-speed' : 'geometricPrecision';
me.getRenderContainer().setAttr('text-rendering', value);
}
function fixPaperCTM(paper) {
var node = paper.shapeNode;
var ctm = node.getCTM();
var matrix = new kity.Matrix(ctm.a, ctm.b, ctm.c, ctm.d, (ctm.e | 0) + 0.5, (ctm.f | 0) + 0.5);
node.setAttribute('transform', 'matrix(' + matrix.toString() + ')');
}
kity.extendClass(KityMinder, {
zoom: function(value) {
var paper = this.getPaper();
var viewport = paper.getViewPort();
viewport.zoom = value / 100;
viewport.center = {
x: viewport.center.x,
y: viewport.center.y
};
paper.setViewPort(viewport);
if (value == 100) fixPaperCTM(paper);
},
getZoomValue: function() {
return this._zoomValue;
}
});
function zoomMinder(minder, value) { var Minder = require('core/minder');
var paper = minder.getPaper(); var MinderNode = require('core/node');
var viewport = paper.getViewPort(); var Command = require('core/command');
var Module = require('core/module');
var Renderer = require('core/render');
if (!value) return; Module.register('Zoom', function() {
var me = this;
setTextRendering(); var timeline;
if (minder.getRoot().getComplex() > 200) { function setTextRendering() {
minder._zoomValue = value; var value = me._zoomValue >= 100 ? 'optimize-speed' : 'geometricPrecision';
minder.zoom(value); me.getRenderContainer().setAttr('text-rendering', value);
minder.fire('viewchange');
} else {
var animator = new kity.Animator({
beginValue: minder._zoomValue,
finishValue: value,
setter: function(target, value) {
target.zoom(value);
}
});
minder._zoomValue = value;
if (timeline) {
timeline.pause();
}
timeline = animator.start(minder, 300, 'easeInOutSine');
timeline.on('finish', function() {
minder.fire('viewchange');
});
} }
minder.fire('zoom', { zoom: value });
} function fixPaperCTM(paper) {
var node = paper.shapeNode;
var ZoomCommand = kity.createClass('Zoom', { var ctm = node.getCTM();
base: Command, var matrix = new kity.Matrix(ctm.a, ctm.b, ctm.c, ctm.d, (ctm.e | 0) + 0.5, (ctm.f | 0) + 0.5);
execute: zoomMinder, node.setAttribute('transform', 'matrix(' + matrix.toString() + ')');
queryValue: function(minder) {
return minder._zoomValue;
} }
});
var ZoomInCommand = kity.createClass('ZoomInCommand', { kity.extendClass(Minder, {
base: Command, zoom: function(value) {
execute: function(minder) { var paper = this.getPaper();
zoomMinder(minder, this.nextValue(minder)); var viewport = paper.getViewPort();
}, viewport.zoom = value / 100;
queryState: function(minder) { viewport.center = {
return +!this.nextValue(minder); x: viewport.center.x,
}, y: viewport.center.y
nextValue: function(minder) { };
var stack = minder.getOptions('zoom'), paper.setViewPort(viewport);
i; if (value == 100) fixPaperCTM(paper);
for (i = 0; i < stack.length; i++) { },
if (stack[i] > minder._zoomValue) return stack[i]; getZoomValue: function() {
return this._zoomValue;
} }
return 0; });
},
enableReadOnly: true
});
var ZoomOutCommand = kity.createClass('ZoomOutCommand', { function zoomMinder(minder, value) {
base: Command, var paper = minder.getPaper();
execute: function(minder) { var viewport = paper.getViewPort();
zoomMinder(minder, this.nextValue(minder));
}, if (!value) return;
queryState: function(minder) {
return +!this.nextValue(minder);
},
nextValue: function(minder) {
var stack = minder.getOptions('zoom'),
i;
for (i = stack.length - 1; i >= 0; i--) {
if (stack[i] < minder._zoomValue) return stack[i];
}
return 0;
},
enableReadOnly: true
});
return {
init: function() {
this._zoomValue = 100;
setTextRendering(); setTextRendering();
},
commands: { if (minder.getRoot().getComplex() > 200) {
'zoom-in': ZoomInCommand, minder._zoomValue = value;
'zoom-out': ZoomOutCommand, minder.zoom(value);
'zoom': ZoomCommand minder.fire('viewchange');
}, } else {
events: { var animator = new kity.Animator({
'normal.mousewheel readonly.mousewheel': function(e) { beginValue: minder._zoomValue,
if (!e.originEvent.ctrlKey && !e.originEvent.metaKey) return; finishValue: value,
setter: function(target, value) {
var delta = e.originEvent.wheelDelta; target.zoom(value);
var me = this; }
});
if (!kity.Browser.mac) { minder._zoomValue = value;
delta = -delta; if (timeline) {
timeline.pause();
} }
timeline = animator.start(minder, 300, 'easeInOutSine');
timeline.on('finish', function() {
minder.fire('viewchange');
});
}
minder.fire('zoom', {
zoom: value
});
}
// 稀释 var ZoomCommand = kity.createClass('Zoom', {
if (Math.abs(delta) > 100) { base: Command,
clearTimeout(this._wheelZoomTimeout); execute: zoomMinder,
} else { queryValue: function(minder) {
return; return minder._zoomValue;
}
});
var ZoomInCommand = kity.createClass('ZoomInCommand', {
base: Command,
execute: function(minder) {
zoomMinder(minder, this.nextValue(minder));
},
queryState: function(minder) {
return +!this.nextValue(minder);
},
nextValue: function(minder) {
var stack = minder.getOption('zoom'),
i;
for (i = 0; i < stack.length; i++) {
if (stack[i] > minder._zoomValue) return stack[i];
} }
return 0;
},
enableReadOnly: true
});
var ZoomOutCommand = kity.createClass('ZoomOutCommand', {
base: Command,
execute: function(minder) {
zoomMinder(minder, this.nextValue(minder));
},
queryState: function(minder) {
return +!this.nextValue(minder);
},
nextValue: function(minder) {
var stack = minder.getOption('zoom'),
i;
for (i = stack.length - 1; i >= 0; i--) {
if (stack[i] < minder._zoomValue) return stack[i];
}
return 0;
},
enableReadOnly: true
});
return {
init: function() {
this._zoomValue = 100;
setTextRendering();
},
commands: {
'zoom-in': ZoomInCommand,
'zoom-out': ZoomOutCommand,
'zoom': ZoomCommand
},
events: {
'normal.mousewheel readonly.mousewheel': function(e) {
if (!e.originEvent.ctrlKey && !e.originEvent.metaKey) return;
var delta = e.originEvent.wheelDelta;
var me = this;
if (!kity.Browser.mac) {
delta = -delta;
}
this._wheelZoomTimeout = setTimeout(function() { // 稀释
var value; if (Math.abs(delta) > 100) {
var lastValue = me.getPaper()._zoom || 1; clearTimeout(this._wheelZoomTimeout);
if (delta < 0) { } else {
me.execCommand('zoom-in'); return;
} else if (delta > 0) {
me.execCommand('zoom-out');
} }
}, 100);
e.originEvent.preventDefault(); this._wheelZoomTimeout = setTimeout(function() {
} var value;
}, var lastValue = me.getPaper()._zoom || 1;
if (delta < 0) {
me.execCommand('zoom-in');
} else if (delta > 0) {
me.execCommand('zoom-out');
}
}, 100);
e.originEvent.preventDefault();
}
},
commandShortcutKeys: { commandShortcutKeys: {
'zoom-in': 'ctrl+=', 'zoom-in': 'ctrl+=',
'zoom-out': 'ctrl+-' 'zoom-out': 'ctrl+-'
} }
}; };
});
}); });
\ No newline at end of file
...@@ -6,30 +6,33 @@ ...@@ -6,30 +6,33 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
define(function(require, exports, module) {
var template = require('core/template');
KityMinder.registerTemplate('default', { template.register('default', {
getLayout: function(node) { getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout'); if (node.getData('layout')) return node.getData('layout');
var level = node.getLevel(); var level = node.getLevel();
// 根节点 // 根节点
if (level === 0) { if (level === 0) {
return 'mind'; return 'mind';
} }
// 一级节点 // 一级节点
if (level === 1) { if (level === 1) {
return node.getLayoutPointPreview().x > 0 ? 'right': 'left'; return node.getLayoutPointPreview().x > 0 ? 'right': 'left';
} }
return node.parent.getLayout(); return node.parent.getLayout();
}, },
getConnect: function(node) { getConnect: function(node) {
if (node.getLevel() == 1) return 'arc'; if (node.getLevel() == 1) return 'arc';
return 'under'; return 'under';
} }
});
}); });
\ No newline at end of file
...@@ -6,20 +6,23 @@ ...@@ -6,20 +6,23 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
define(function(require, exports, module) {
var template = require('core/template');
KityMinder.registerTemplate('filetree', { template.register('filetree', {
getLayout: function(node) { getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout'); if (node.getData('layout')) return node.getData('layout');
if (node.isRoot()) return 'bottom'; if (node.isRoot()) return 'bottom';
return 'filetree-down'; return 'filetree-down';
}, },
getConnect: function(node) { getConnect: function(node) {
if (node.getLevel() == 1) { if (node.getLevel() == 1) {
return 'poly'; return 'poly';
}
return 'l';
} }
return 'l'; });
}
}); });
\ No newline at end of file
...@@ -6,33 +6,36 @@ ...@@ -6,33 +6,36 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
define(function(require, exports, module) {
var template = require('core/template');
KityMinder.registerTemplate('fish-bone', { template.register('fish-bone', {
getLayout: function(node) { getLayout: function(node) {
if (node.getData('layout')) return node.getData('layout'); if (node.getData('layout')) return node.getData('layout');
var level = node.getLevel(); var level = node.getLevel();
// 根节点 // 根节点
if (level === 0) { if (level === 0) {
return 'fish-bone-master'; return 'fish-bone-master';
} }
// 一级节点 // 一级节点
if (level === 1) { if (level === 1) {
return 'fish-bone-slave'; return 'fish-bone-slave';
} }
return node.getLayoutPointPreview().y > 0 ? 'filetree-up': 'filetree-down'; return node.getLayoutPointPreview().y > 0 ? 'filetree-up': 'filetree-down';
}, },
getConnect: function(node) { getConnect: function(node) {
switch (node.getLevel()) { switch (node.getLevel()) {
case 1: return 'fish-bone-master'; case 1: return 'fish-bone-master';
case 2: return 'line'; case 2: return 'line';
default: return 'l'; default: return 'l';
}
} }
} });
}); });
\ No newline at end of file
...@@ -6,15 +6,18 @@ ...@@ -6,15 +6,18 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
define(function(require, exports, module) {
var template = require('core/template');
KityMinder.registerTemplate('right', { template.register('right', {
getLayout: function(node) { getLayout: function(node) {
return node.getData('layout') || 'right'; return node.getData('layout') || 'right';
}, },
getConnect: function(node) { getConnect: function(node) {
if (node.getLevel() == 1) return 'arc'; if (node.getLevel() == 1) return 'arc';
return 'bezier'; return 'bezier';
} }
});
}); });
\ No newline at end of file
...@@ -6,14 +6,17 @@ ...@@ -6,14 +6,17 @@
* @author: techird * @author: techird
* @copyright: Baidu FEX, 2014 * @copyright: Baidu FEX, 2014
*/ */
define(function(require, exports, module) {
var template = require('core/template');
KityMinder.registerTemplate('structure', { template.register('structure', {
getLayout: function(node) { getLayout: function(node) {
return node.getData('layout') || 'bottom'; return node.getData('layout') || 'bottom';
}, },
getConnect: function(node) { getConnect: function(node) {
return 'poly'; return 'poly';
} }
});
}); });
\ No newline at end of file
['classic', 'classic-compact'].forEach(function(name) { define(function(require, exports, module) {
var compact = name == 'classic-compact'; var theme = require('core/theme');
KityMinder.registerTheme(name, { ['classic', 'classic-compact'].forEach(function(name) {
'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat', var compact = name == 'classic-compact';
'root-color': '#430', /* jscs:disable maximumLineLength */
'root-background': '#e9df98', theme.register(name, {
'root-stroke': '#e9df98', 'background': '#3A4144 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=") repeat',
'root-font-size': 24,
'root-padding': compact ? [10, 25] : [15, 25], 'root-color': '#430',
'root-margin': compact ? [15, 25] : [30, 100], 'root-background': '#e9df98',
'root-radius': 30, 'root-stroke': '#e9df98',
'root-space': 10, 'root-font-size': 24,
'root-shadow': 'rgba(0, 0, 0, .25)', 'root-padding': compact ? [10, 25] : [15, 25],
'root-margin': compact ? [15, 25] : [30, 100],
'main-color': '#333', 'root-radius': 30,
'main-background': '#a4c5c0', 'root-space': 10,
'main-stroke': '#a4c5c0', 'root-shadow': 'rgba(0, 0, 0, .25)',
'main-font-size': 16,
'main-padding': compact ? [5, 15] : [6, 20], 'main-color': '#333',
'main-margin': compact ? [5, 10] : 20, 'main-background': '#a4c5c0',
'main-radius': 10, 'main-stroke': '#a4c5c0',
'main-space': 5, 'main-font-size': 16,
'main-shadow': 'rgba(0, 0, 0, .25)', 'main-padding': compact ? [5, 15] : [6, 20],
'main-margin': compact ? [5, 10] : 20,
'sub-color': 'white', 'main-radius': 10,
'sub-background': 'transparent', 'main-space': 5,
'sub-stroke': 'none', 'main-shadow': 'rgba(0, 0, 0, .25)',
'sub-font-size': 12,
'sub-padding': [5, 10], 'sub-color': 'white',
'sub-margin': compact ? [5, 10] : [15, 20], 'sub-background': 'transparent',
'sub-tree-margin': 30, 'sub-stroke': 'none',
'sub-radius': 5, 'sub-font-size': 12,
'sub-space': 5, 'sub-padding': [5, 10],
'sub-margin': compact ? [5, 10] : [15, 20],
'connect-color': 'white', 'sub-tree-margin': 30,
'connect-width': 2, 'sub-radius': 5,
'main-connect-width': 3, 'sub-space': 5,
'connect-radius': 5,
'connect-color': 'white',
'selected-background': 'rgb(254, 219, 0)', 'connect-width': 2,
'selected-stroke': 'rgb(254, 219, 0)', 'main-connect-width': 3,
'selected-color': 'black', 'connect-radius': 5,
'marquee-background': 'rgba(255,255,255,.3)', 'selected-background': 'rgb(254, 219, 0)',
'marquee-stroke': 'white', 'selected-stroke': 'rgb(254, 219, 0)',
'selected-color': 'black',
'drop-hint-color': 'yellow',
'sub-drop-hint-width': 2, 'marquee-background': 'rgba(255,255,255,.3)',
'main-drop-hint-width': 4, 'marquee-stroke': 'white',
'root-drop-hint-width': 4,
'drop-hint-color': 'yellow',
'order-hint-area-color': 'rgba(0, 255, 0, .5)', 'sub-drop-hint-width': 2,
'order-hint-path-color': '#0f0', 'main-drop-hint-width': 4,
'order-hint-path-width': 1, 'root-drop-hint-width': 4,
'text-selection-color': 'rgb(27,171,255)', 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
'line-height':1.5 'order-hint-path-color': '#0f0',
'order-hint-path-width': 1,
'text-selection-color': 'rgb(27,171,255)',
'line-height':1.5
});
}); });
}); });
\ No newline at end of file
KityMinder.registerTheme('fish', { define(function(require, exports, module) {
'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat', var theme = require('core/theme');
'root-color': '#430', theme.register('fish', {
'root-background': '#e9df98', 'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat',
'root-stroke': '#e9df98',
'root-font-size': 24, 'root-color': '#430',
'root-padding': [35, 35], 'root-background': '#e9df98',
'root-margin': 30, 'root-stroke': '#e9df98',
'root-radius': 100, 'root-font-size': 24,
'root-space': 10, 'root-padding': [35, 35],
'root-shadow': 'rgba(0, 0, 0, .25)', 'root-margin': 30,
'root-radius': 100,
'main-color': '#333', 'root-space': 10,
'main-background': '#a4c5c0', 'root-shadow': 'rgba(0, 0, 0, .25)',
'main-stroke': '#a4c5c0',
'main-font-size': 16, 'main-color': '#333',
'main-padding': [6, 20], 'main-background': '#a4c5c0',
'main-margin': [20, 20], 'main-stroke': '#a4c5c0',
'main-radius': 5, 'main-font-size': 16,
'main-space': 5, 'main-padding': [6, 20],
'main-shadow': 'rgba(0, 0, 0, .25)', 'main-margin': [20, 20],
'main-radius': 5,
'sub-color': 'black', 'main-space': 5,
'sub-background': 'white', 'main-shadow': 'rgba(0, 0, 0, .25)',
'sub-stroke': 'white',
'sub-font-size': 12, 'sub-color': 'black',
'sub-padding': [5, 10], 'sub-background': 'white',
'sub-margin': [10], 'sub-stroke': 'white',
'sub-radius': 5, 'sub-font-size': 12,
'sub-space': 5, 'sub-padding': [5, 10],
'sub-margin': [10],
'connect-color': 'white', 'sub-radius': 5,
'connect-width': 3, 'sub-space': 5,
'main-connect-width': 3,
'connect-radius': 5, 'connect-color': 'white',
'connect-width': 3,
'selected-background': 'rgb(254, 219, 0)', 'main-connect-width': 3,
'selected-stroke': 'rgb(254, 219, 0)', 'connect-radius': 5,
'marquee-background': 'rgba(255,255,255,.3)', 'selected-background': 'rgb(254, 219, 0)',
'marquee-stroke': 'white', 'selected-stroke': 'rgb(254, 219, 0)',
'drop-hint-color': 'yellow', 'marquee-background': 'rgba(255,255,255,.3)',
'drop-hint-width': 4, 'marquee-stroke': 'white',
'order-hint-area-color': 'rgba(0, 255, 0, .5)', 'drop-hint-color': 'yellow',
'order-hint-path-color': '#0f0', 'drop-hint-width': 4,
'order-hint-path-width': 1,
'order-hint-area-color': 'rgba(0, 255, 0, .5)',
'text-selection-color': 'rgb(27,171,255)', 'order-hint-path-color': '#0f0',
'line-height':1.5 'order-hint-path-width': 1,
'text-selection-color': 'rgb(27,171,255)',
'line-height':1.5
});
}); });
\ No newline at end of file
(function() { define(function(require, exports, module) {
var kity = require('core/kity');
var theme = require('core/theme');
function hsl(h, s, l) { function hsl(h, s, l) {
return kity.Color.createHSL(h, s, l); return kity.Color.createHSL(h, s, l);
} }
...@@ -67,8 +70,8 @@ ...@@ -67,8 +70,8 @@
}; };
var name; var name;
for (name in plans) { for (name in plans) {
KityMinder.registerTheme('fresh-' + name, generate(plans[name])); theme.register('fresh-' + name, generate(plans[name]));
KityMinder.registerTheme('fresh-' + name + '-compat', generate(plans[name], true)); theme.register('fresh-' + name + '-compat', generate(plans[name], true));
} }
})(); });
\ No newline at end of file \ No newline at end of file
define(function(require, exports, module) {
var theme = require('core/theme');
['snow', 'snow-compact'].forEach(function(name) {
var compact = name == 'snow-compact'; ['snow', 'snow-compact'].forEach(function(name) {
var compact = name == 'snow-compact';
KityMinder.registerTheme(name, {
'background': '#3A4144 url(ui/theme/default/images/grid.png) repeat', /* jscs:disable maximumLineLength */
theme.register(name, {
'root-color': '#430', 'background': '#3A4144 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=") repeat',
'root-background': '#e9df98',
'root-stroke': '#e9df98', 'root-color': '#430',
'root-font-size': 24, 'root-background': '#e9df98',
'root-padding': compact ? [5, 10] : [15, 25], 'root-stroke': '#e9df98',
'root-margin': compact ? 15 : 30, 'root-font-size': 24,
'root-radius': 5, 'root-padding': compact ? [5, 10] : [15, 25],
'root-space': 10, 'root-margin': compact ? 15 : 30,
'root-shadow': 'rgba(0, 0, 0, .25)', 'root-radius': 5,
'root-space': 10,
'main-color': '#333', 'root-shadow': 'rgba(0, 0, 0, .25)',
'main-background': '#a4c5c0',
'main-stroke': '#a4c5c0', 'main-color': '#333',
'main-font-size': 16, 'main-background': '#a4c5c0',
'main-padding': compact ? [4, 10] : [6, 20], 'main-stroke': '#a4c5c0',
'main-margin': compact ? [5, 10] : [20, 40], 'main-font-size': 16,
'main-radius': 5, 'main-padding': compact ? [4, 10] : [6, 20],
'main-space': 5, 'main-margin': compact ? [5, 10] : [20, 40],
'main-shadow': 'rgba(0, 0, 0, .25)', 'main-radius': 5,
'main-space': 5,
'sub-color': 'black', 'main-shadow': 'rgba(0, 0, 0, .25)',
'sub-background': 'white',
'sub-stroke': 'white', 'sub-color': 'black',
'sub-font-size': 12, 'sub-background': 'white',
'sub-padding': [5, 10], 'sub-stroke': 'white',
'sub-margin': compact ? [5, 10] : [10, 20], 'sub-font-size': 12,
'sub-radius': 5, 'sub-padding': [5, 10],
'sub-space': 5, 'sub-margin': compact ? [5, 10] : [10, 20],
'sub-radius': 5,
'connect-color': 'white', 'sub-space': 5,
'connect-width': 2,
'main-connect-width': 3, 'connect-color': 'white',
'connect-radius': 5, 'connect-width': 2,
'main-connect-width': 3,
'selected-background': 'rgb(254, 219, 0)', 'connect-radius': 5,
'selected-stroke': 'rgb(254, 219, 0)',
'selected-background': 'rgb(254, 219, 0)',
'marquee-background': 'rgba(255,255,255,.3)', 'selected-stroke': 'rgb(254, 219, 0)',
'marquee-stroke': 'white',
'marquee-background': 'rgba(255,255,255,.3)',
'drop-hint-color': 'yellow', 'marquee-stroke': 'white',
'drop-hint-width': 4,
'drop-hint-color': 'yellow',
'order-hint-area-color': 'rgba(0, 255, 0, .5)', 'drop-hint-width': 4,
'order-hint-path-color': '#0f0',
'order-hint-path-width': 1, 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
'order-hint-path-color': '#0f0',
'text-selection-color': 'rgb(27,171,255)', 'order-hint-path-width': 1,
'line-height':1.5
'text-selection-color': 'rgb(27,171,255)',
'line-height':1.5
});
}); });
}); });
\ No newline at end of file
KityMinder.registerTheme('wire', { define(function(require, exports, module) {
'background': 'black', var theme = require('core/theme');
'color': '#999', theme.register('wire', {
'stroke': 'none', 'background': 'black',
'padding': 10,
'margin': 20,
'font-size': 14,
'connect-color': '#999', 'color': '#999',
'connect-width': 1, 'stroke': 'none',
'padding': 10,
'margin': 20,
'font-size': 14,
'selected-background': '#999', 'connect-color': '#999',
'selected-color': 'black', 'connect-width': 1,
'marquee-background': 'rgba(255,255,255,.3)', 'selected-background': '#999',
'marquee-stroke': 'white', 'selected-color': 'black',
'drop-hint-color': 'yellow', 'marquee-background': 'rgba(255,255,255,.3)',
'sub-drop-hint-width': 2, 'marquee-stroke': 'white',
'main-drop-hint-width': 4,
'root-drop-hint-width': 4,
'order-hint-area-color': 'rgba(0, 255, 0, .5)', 'drop-hint-color': 'yellow',
'order-hint-path-color': '#0f0', 'sub-drop-hint-width': 2,
'order-hint-path-width': 1, 'main-drop-hint-width': 4,
'root-drop-hint-width': 4,
'text-selection-color': 'rgb(27,171,255)', 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
'line-height':1.5 'order-hint-path-color': '#0f0',
'order-hint-path-width': 1,
'text-selection-color': 'rgb(27,171,255)',
'line-height':1.5
});
}); });
\ No newline at end of file
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