This commit is contained in:
Xes
2025-08-14 22:39:38 +02:00
parent 3641e93527
commit 5403f346e3
3370 changed files with 327179 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Process the saving of the mindmap updates (when clicking the logo to get out).
*/
if (isset($_GET['id'])) {
if (isset($_POST['datamap'])) {
require_once __DIR__.'/../../../main/inc/global.inc.php';
if (api_is_anonymous()) {
echo "KO";
exit;
}
$idMM = -1;
if (isset($_GET['id'])) {
$idMM = (int) $_GET['id'];
}
$dataMap = '';
if (isset($_POST['datamap'])) {
$dataMap = $_POST['datamap'];
}
if ($dataMap != '') {
$user = api_get_user_info();
$table = 'plugin_mindmap';
$params = [
'mindmap_data' => $dataMap,
];
$whereConditions = [
'id = ?' => $idMM,
'AND (user_id = ?' => $user['id'],
'OR is_shared = 1)',
];
$isAdmin = api_is_platform_admin();
if ($user['status'] == SESSIONADMIN || $user['status'] == PLATFORM_ADMIN || $isAdmin) {
$whereConditions = [
'id = ?' => $idMM,
];
}
Database::update($table, $params, $whereConditions);
echo 'OK';
} else {
echo 'KO';
}
} else {
echo 'KO';
}
} else {
echo 'KO';
}

View File

@@ -0,0 +1,13 @@
mindMap
=======
mindMap is a mind mapping application written entirely in JavaScript. I'm trying to use the latest HTML5 and CSS3 technologies in it.
mindMap is hosted [here][1] and a simple document is [here][2].
[1]: http://kampfer.github.com/mindMap/client/index.html
[2]: http://kampfer.github.com/mindMap/client/help/introduce.html
###Supported browsers
Just chrome and firefox

View File

@@ -0,0 +1,88 @@
setTimeout(function () {
var mapData = {
'document': [{
'id': '937205e4-c2b0-ead3-2db4-66719b3612e2',
'parent': null,
'children': null,
'content': 'Chamilo',
'offset': {'x': 360, 'y': 394}
}], 'lastModified': 1592229869766
}
if (dataMMLoad != '') {
mapData = dataMMLoad
}
var view = document.getElementById('map-container')
view = kampfer.mindMap.window
var command = new kampfer.mindMap.command.CreateNewMap(mapData, view)
command.execute()
var ht = '<li id="mindmapmenu" style="width:128px;height:128px;" >'
ht += '<img alt="Save" style="width:128px;height:128px;cursor:pointer;" onClick="saveMapProcess(true);" src="img/mindmap128.png" /></li>'
$('#main-menu').html(ht)
}, 100)
var onlyOneUpdate = true
setTimeout(function () {
saveMapProcess(false)
}, 6000)
function saveMapProcess (redir) {
if (onlyOneUpdate == false) {return false}
if (redir) {
var ht = '<img alt="Save" style="width:128px;height:128px;cursor:pointer;" src="img/mindmap128gray.png" />'
$('#mindmapmenu').html(ht)
}
var map = kampfer.mindMap.mapManager.getMapData()
var mapString = JSON.stringify(map)
var formData = {datamap: mapString}
$.ajax({
url: '../ajax/mindmap.ajax.php?id=' + idMM,
type: 'POST', data: formData,
success: function (data, textStatus, jqXHR) {
onlyOneUpdate = true
if (data.indexOf('KO') == -1) {
if (redir) {
window.location.href = '../list.php?cid=' + MMGetParamValue('cid') + '&sid=' + MMGetParamValue('sid')
}
} else {
alert('Error !')
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error : ' + textStatus)
onlyOneUpdate = true
}
})
}
function MMGetParamValue (param) {
var u = document.location.href
var reg = new RegExp('(\\?|&|^)' + param + '=(.*?)(&|$)')
matches = u.match(reg)
if (matches == null) {return ''}
var vari = matches[2] != undefined ? decodeURIComponent(matches[2]).replace(/\+/g, ' ') : ''
for (var i = 100; i > -1; i--) {
vari = vari.replace('#page' + i, '')
}
return vari
}

View File

@@ -0,0 +1,8 @@
{
"name" : "kampfer",
"jsDir" : "client/js/",
"combine" : {
"source" : "",
"export" : ""
}
}

View File

@@ -0,0 +1,75 @@
var path = require('path'),
fs = require('fs');
var //项目名
prefix,
//依赖关系
dep,
//项目路径
jsDir;
var sort = function(src) {
if(!dep) {
console.log('Please call combine.init method first!');
return;
}
var scripts = [],
visited = {},
visit = function(node) {
if(node in visited) {
return;
}
visited[node] = true;
var requires = dep.getRequiresByPath(node);
for(var require in requires) {
visit( dep.getPathByName(require) );
}
scripts.push(node);
};
visit(src);
return scripts;
};
var deleteRequire = function(code) {
var reg = prefix + '\\.require\\([\'\"]([-_\\.a-zA-Z0-9]+)[\'\"]\\);[\n\r]*';
reg = new RegExp(reg, 'g');
return code.replace(reg, '');
};
exports.init = function(dependency, config) {
dep = dependency;
jsDir = config.getJsDir();
prefix = config.getProjectName();
};
exports.combineCode = function(src) {
if(!src) {
console.log('Please input a file');
return;
}
src = path.relative(jsDir, src).replace(/\\/g, '/');
var scripts = sort(src), code = [];
for(var i = 0, l = scripts.length; i < l; i++) {
src = path.join(jsDir, scripts[i]);
var content = fs.readFileSync(src).toString();
code.push( deleteRequire(content) );
}
return code.join('\n\n');
};
exports.combineFile = function(src, output) {
var content = exports.combineCode(src);
fs.writeFileSync(output, content);
console.log('success! -> Combined File : ' + src);
};
exports.combine = function() {};

View File

@@ -0,0 +1,19 @@
var fs = require('fs'),
path = require('path'),
config = {};
exports.getProjectName = function() {
return config.name;
};
//js文件夹必须和tools在同一级目录
exports.getJsDir = function() {
if(config.jsDir) {
return path.resolve(__dirname, '../../', config.jsDir);
}
};
exports.parse = function(uri) {
uri = path.normalize(uri);
config = JSON.parse( fs.readFileSync(uri) );
};

View File

@@ -0,0 +1,136 @@
var fs = require('fs'),
path = require('path');
var //项目名
prefix,
//项目路径
jsDir,
//依赖文件路径
depsPath,
//依赖关系缓存
dependencies = {
pathToNames: {}, // 1 to many
nameToPath: {}, // 1 to 1
requires: {} // 1 to many
};
function addDepsToFile(src, provides, requires) {
var insertText, fd;
requires = '[' + requires.join(',') + ']';
provides = '[' + provides.join(',') + ']';
insertText = [
prefix,
'.addDependency(\'',
src,
'\', ',
provides,
', ',
requires,
');\n'
].join('');
try{
fd = fs.openSync(depsPath, 'a');
fs.writeSync(fd, insertText, 0, 'utf8');
}catch(e){
return false;
}
return true;
}
function addDepsToObj(src, provides, requires) {
var provide, require, deps = dependencies;
for( var i = 0; (provide = provides[i]); i++) {
deps.nameToPath[provide] = src;
if (!(src in deps.pathToNames)) {
deps.pathToNames[src] = {};
}
deps.pathToNames[src][provide] = true;
}
for( var j = 0; (require = requires[j]); j++) {
if (!(src in deps.requires)) {
deps.requires[src] = {};
}
deps.requires[src][require] = true;
}
}
function scanFile(uri) {
if( path.basename(uri) === 'deps.js') {
return;
}
var reg = prefix + '\\.(require|provide)\\([\'\"]([-_\\.a-zA-Z0-9]+)[\'\"]\\);[\n\r]*',
provides = [],
requires = [],
content = fs.readFileSync(uri),
match;
reg = new RegExp(reg, 'g');
uri = path.relative(jsDir, uri).replace(/\\/g, '/');
do {
match = reg.exec(content);
if(match) {
if( match[1] === 'require' ) {
requires.push('\'' + match[2] + '\'');
}
if( match[1] === 'provide' ) {
//prefix不应该被包含在provide name中
var provide = match[2].split('.');
if(provide[0] === prefix) {
provide = provide.slice(1).join('.');
} else {
provide = match[2];
}
provides.push('\'' + provide + '\'');
}
}
} while(match);
addDepsToFile( uri, provides, requires );
addDepsToObj( uri, provides, requires );
console.log('success! -> create one dependency record : ' + uri);
}
exports.scan = function(uri) {
var stat = fs.statSync(uri);
if( stat.isDirectory() ) {
fs.readdirSync(uri).forEach(function(part) {
exports.scan( path.join(uri, part) );
});
} else if( stat.isFile() ) {
scanFile(uri);
}
};
exports.init = function(config) {
prefix = config.getProjectName();
jsDir = config.getJsDir();
depsPath = path.join(jsDir, 'deps.js');
fs.writeFile(depsPath, '');
console.log('success! -> create a new deps.js');
exports.scan(jsDir);
};
exports.getRequiresByPath = function(src) {
return dependencies.requires[src];
};
exports.getPathByName = function(name) {
return dependencies.nameToPath[name];
};
exports.getDepsPath = function() {
return depsPath;
};

View File

@@ -0,0 +1,16 @@
var combine = require('./lib/combine'),
dep = require('./lib/dependency'),
fs = require('fs'),
path = require('path'),
config = require('./lib/config'),
UglifyJS = require("uglify-js");
config.parse( path.join(__dirname, 'config.json') );
dep.init(config);
combine.init(dep, config);
var testUri = path.resolve(__dirname, '../', 'client/js/mindmap.js'),
testOutput = path.resolve(__dirname, '../', 'client/js/mindmap.min.js');
combine.combineFile(testUri, testOutput);
fs.writeFileSync(testOutput, UglifyJS.minify(testOutput).code);

View File

@@ -0,0 +1,7 @@
var dep = require('./lib/dependency'),
fs = require('fs'),
path = require('path'),
config = require('./lib/config');
config.parse( path.join(__dirname, 'config.json') );
dep.init(config);

View File

@@ -0,0 +1,31 @@
# Code Structure Of Mindmap #
## Model ##
mapmanager.js
-------------
## View ##
window.js
toolbar.js
menu.js
map.js
node.js
caption.js
branch.js
-----------
## Controller ##
command.js
app.js

View File

@@ -0,0 +1,31 @@
关于架构设计
============
设计一个领域实体,必须明确这个领域实体必须知道其他哪些领域实体(帮助其完成业务),之后对于其他领域实体可以完全无视。
程序的启动程序的主要工作是初始化view、model和controller。model比较封闭初始化时一般不需要外部帮助view初始化一般需要model数据等信息controller需要view和model的引用保证view和model信息的同步。
数据的流动方向和路径?
启动文件负责配置好所有组件,并在命名空间中保存引用.
所有view组件注册在mindMap.view下, 所有modal注册在mindMap.modal下, controller类似.
组件需要调用其它组件时, 可以将mindMap作为参数直接传递.
已经使用的设计模式
==================
1. Observer
2. Composition
3. Command
4. Template Method
**Composition模式**
类有两部分的功能: 管理子节点和递归操作
**Decorator模式**
https://gist.github.com/kampfer/5012413
**Abstract Factory/Factory Method**
抽象工厂模式依赖工厂方法模式 他们也经常和模板方法模式一起使用

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,134 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>MindMap</title>
<link rel="stylesheet" type="text/css" href="vendor/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="vendor/css/bootstrap-responsive.min.css">
<link rel="stylesheet" type="text/css" href="vendor/css/app.css">
<script type="text/javascript" src="vendor/js/base.js"></script>
<script type="text/javascript">
var dataMMLoad = ''
var titleMM = ''
<?php
$globalInclude = __DIR__.'/../../main/inc/global.inc.php';
if (file_exists($globalInclude)) {
require_once $globalInclude;
} else {
$globalInclude = __DIR__.'/../../../main/inc/global.inc.php';
if (file_exists($globalInclude)) {
require_once $globalInclude;
}
}
if (isset($_GET['id'])) {
$idMM = (int) $_GET['id'];
echo 'var idMM = '.$idMM.';';
$sql = "SELECT title, mindmap_data FROM plugin_mindmap ";
$sql .= " WHERE id = $idMM;";
$resultParts = Database::query($sql);
while ($part = Database::fetch_array($resultParts)) {
$titleMM = $part['title'];
$dataMMLoad = $part['mindmap_data'];
if ($dataMMLoad != '') {
echo 'dataMMLoad = '.$dataMMLoad.';';
}
echo 'titleMM = "'.$titleMM.'";';
}
}
?>
</script>
</head>
<body>
<div class="app-tool-bar" id="app-tool-bar">
<ul id="main-menu" class="dropdown-menu">
<li>
<a href="javascript:void(0);" title="File" onClick="saveMapProcess();" tabindex="-1"><i
class="icon-save"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a tabindex="-1" href="javascript:void(0);" command="SaveMapInStorage"><span class="short-cut">Ctrl+S</span>Save
Map In Storage</a></li>
</ul>
</li>
<li class="dropdown-submenu" role="menu-trigger">
<a href="javascript:void(0);" title="Edit" tabindex="-1"><i class="icon-edit"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a>
</li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span
class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a>
</li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Undo"><span class="short-cut">Ctrl+Z</span>Undo</a>
</li>
<li><a tabindex="-1" href="javascript:void(0);" command="Redo"><span class="short-cut">Ctrl+Y</span>Redo</a>
</li>
</ul>
</li>
<li class="divider"></li>
<li id="help"><a href="help/introduce.html" title="Help" tabindex="-1"><i class="icon-question-sign"></i></a>
</li>
</ul>
</div>
<div class="app-container" id="map-container">
<ul class="dropdown-menu" id="context-menu">
<li><a tabindex="-1" href="javascript:void(0);" command="CreateNewRootNode">Create New Root Node</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a>
</li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a>
</li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Undo"><span class="short-cut">Ctrl+Z</span>Undo</a>
</li>
<li><a tabindex="-1" href="javascript:void(0);" command="Redo"><span class="short-cut">Ctrl+Y</span>Redo</a>
</li>
</ul>
<ul class="dropdown-menu" id="node-context-menu">
<li><a tabindex="-1" href="javascript:void(0);" command="AppendChildNode">Append Child Node</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="EditNodeContent">Edit Node</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="DeleteNode">Delete</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a>
</li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a>
</li>
</ul>
</div>
<div class="app-footer">
<div class="container">
<p style="color:white;">MindMap</p>
</div>
</div>
<div style="display:none;">
<input type="file" name="mapJson" id="mapJson"/>
</div>
<script type="text/javascript" src="vendor/js/mindmap.js"></script>
<script type="text/javascript">
kampfer.mindMap.init()
</script>
<script type="text/javascript" src="vendor/js/jquery.js"></script>
<script type="text/javascript" src="app-base.js"></script>
</body>
</html>

View File

@@ -0,0 +1,11 @@
var connect = require('connect');
var path = require('path');
connect.static.mime.define({
'text/cache-manifest' : ['mf', 'manifest']
});
var app = connect()
.use( connect.logger('dev') )
.use( connect.static('client/') )
.listen(8000);

View File

@@ -0,0 +1,52 @@
{
"tree" : {
"id" : "map",
"children" : [
{
"id" : "child1",
"content" : "child1",
"offset" : {"x" : 100, "y" : 200},
"parent" : "map",
"children" : [
{
"id" : "child1-1",
"content" : "child1-1",
"offset" : {"x" : 100, "y" : 200},
"parent" : "child1",
"children" : [
{
"id" : "child1-1-1",
"content" : "child1-1-1",
"offset" : {"x" : 200, "y" : 200},
"parent" : "child1-1",
"children" : null
}
]
},
{
"id" : "child1-2",
"content" : "child1-2",
"offset" : {"x" : 200, "y" : 200},
"parent" : "child1",
"children" : null
}
]
},
{
"id" : "child2",
"content" : "child2",
"offset" : {"x" : 100, "y" : 100},
"parent" : "map",
"children" : null
},
{
"id" : "child3",
"content" : "child3",
"offset" : {"x" : 200, "y" : 100},
"parent" : "map",
"children" : null
}
]
},
"name" : "untitled"
}

View File

@@ -0,0 +1,216 @@
/*Styles used for the various demonstration divs that need to be vendor prefixed*/
.TransformDemoPerspective200 {
-ms-perspective: 200px;
}
.TransformDemoPerspectiveOrigin3050 {
-ms-perspective-origin: 30% 50%;
}
.TransformDemoPerspectiveOrigin8050 {
-ms-perspective-origin: 80% 50%;
}
.TransformDemoDivRotate45 {
}
.TransformDemoDivRotate45:hover {
-ms-transform: rotate(45deg);
}
.TransformDemoDivSkewX45:hover {
-ms-transform: skewX(45deg);
}
.Transform3DDemoDivRotateX:hover {
-ms-transform: rotateX(45deg);
}
.Transform3DDemoDivRotateY:hover {
-ms-transform: rotateY(45deg);
}
.Transform3DDemoDivTranslateZ:hover {
-ms-transform: translateZ(-50px);
}
.Transform3DDemoDivRotateYTranslateZ:hover {
-ms-transform: rotateY(45deg) translateZ(-50px);
}
.Transform3DDemoDivTranslateZRotateY:hover {
-ms-transform: translateZ(-50px) rotateY(45deg);
}
@-ms-keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@-ms-keyframes fadeOutInOut {
0% {
opacity: 1;
}
25% {
opacity: 0;
}
75% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@-ms-keyframes fadeOutInOutSwirl {
0% {
opacity: 1;
}
25% {
opacity: 0.5;
-ms-transform: rotateZ(0deg);
}
75% {
opacity: 0.5;
-ms-transform: rotateZ(180deg);
}
100% {
opacity: 1.0;
-ms-transform: rotateZ(360deg);
}
}
@-ms-keyframes fullPageInOut {
50% {
opacity: 0.5;
-ms-transform: scale(0.1) rotateZ(360deg);
}
}
.TransformDemoDivFadeOut:hover {
-ms-animation-duration: 2s;
-ms-animation-name: fadeOut;
}
.TransformDemoDivFadeOutInOut:hover {
-ms-animation-duration: 2s;
-ms-animation-name: fadeOutInOut;
}
.TransformDemoDivFadeOutInOutSwirl:hover {
-ms-animation-duration: 2s;
-ms-animation-name: fadeOutInOutSwirl;
}
.TransformTranslateX400px {
-ms-transform: translateX(400px);
}
.TransformTranslateY300px {
-ms-transform: translateY(300px);
}
.TransformRotate45 {
-ms-transform: rotate(45deg);
}
.TransformRotateMinus35 {
-ms-transform: rotate(-35deg);
}
.TransformSkewX25 {
-ms-transform: skewX(25deg);
}
.TransformSkewY25 {
-ms-transform: skewY(25deg);
}
.TransformScale075 {
-ms-transform: scale(0.75);
}
.TransformScaleX075 {
-ms-transform: scaleX(0.75);
}
.TransformScaleY075 {
-ms-transform: scaleY(0.75);
}
.TransformScaleX125 {
-ms-transform: scaleX(1.25);
}
.TransformScaleY125 {
-ms-transform: scaleY(1.25);
}
.TransformRotate45TranslateX200px {
-ms-transform: rotate(45deg) translateX(200px);
}
.TransformTranslateX200pxRotate45 {
-ms-transform: translateX(200px) rotate(45deg);
}
.TransformOrigin0050 {
-ms-transform-origin: 0% 50%;
}
.TransformOrigin0000 {
-ms-transform-origin: 0% 0%;
}
.TransformOrigin00100 {
-ms-transform-origin: 0% 100%;
}
.TransformOrigin100100 {
-ms-transform-origin: 100% 100%;
}
.TransformOrigin2525 {
-ms-transform-origin: 25% 25%;
}
.TransformOrigin5000 {
-ms-transform-origin: 50% 0%;
}
.TransformOrigin50100 {
-ms-transform-origin: 50% 100%;
}
.TransformOrigin6666 {
-ms-transform-origin: 66% 66%;
}
.AnimationTimingEase {
-ms-animation-timing-function: ease;
}
.AnimationTimingEaseIn {
-ms-animation-timing-function: ease-in;
}
.AnimationTimingEaseOut {
-ms-animation-timing-function: ease-out;
}
.AnimationTimingEaseInOut {
-ms-animation-timing-function: ease-in-out;
}
.AnimationTimingLinear {
-ms-animation-timing-function: linear;
}
.Animation3Iterations {
-ms-animation-iteration-count: 3;
}

View File

@@ -0,0 +1,223 @@
/* Copyright © Microsoft Corporation. All Rights Reserved. */
/* Demo Author: Charilaos "Harris" Papadopoulos, Microsoft Corporation */
/*
Predefined full-page animations for the CSS Animation/Transform IE Test Drive Demo
Please check FullPageAnimations.js for more information
*/
@-ms-keyframes rotateInLeft {
from {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateY(180deg);
}
to {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateY(0deg);
}
}
@-ms-keyframes rotateOutLeft {
from {
-ms-transform-origin: 0% 0%;
}
to {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateY(180deg);
}
}
@-ms-keyframes rotateInRight {
from {
-ms-transform-origin: 100% 0%;
-ms-transform: rotateY(-180deg);
}
to {
-ms-transform-origin: 100% 0%;
}
}
@-ms-keyframes rotateInRightWithoutToKeyframe {
from {
-ms-transform-origin: 100% 0%;
-ms-transform: rotateY(-180deg);
}
}
@-ms-keyframes rotateOutRight {
from {
-ms-transform-origin: 100% 0%;
}
to {
-ms-transform-origin: 100% 0%;
-ms-transform: rotateY(-180deg);
}
}
@-ms-keyframes fadeIn {
from {
opacity: 0;
}
}
@-ms-keyframes fadeOut {
to {
opacity: 0;
}
}
@-ms-keyframes whirlIn {
from {
-ms-transform-origin: 50% 50%;
-ms-transform: scale(0) rotateZ(1260deg);
}
to {
-ms-transform-origin: 50% 50%;
}
}
@-ms-keyframes whirlOut {
from {
-ms-transform-origin: 50% 50%;
}
to {
-ms-transform-origin: 50% 50%;
-ms-transform: scale(0) rotateZ(1260deg);
}
}
@-ms-keyframes fallFromTop {
from {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateX(-180deg);
animation-timing-function: ease;
}
50% {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateX(30deg);
animation-timing-function: ease;
}
85% {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateX(-10deg);
animation-timing-function: ease;
}
to {
-ms-transform-origin: 0% 0%;
-ms-transform: rotateX(0deg);
animation-timing-function: ease;
}
}
@-ms-keyframes dropToBottom {
from {
-ms-transform-origin: 0% 100%;
}
to {
-ms-transform-origin: 0% 100%;
-ms-transform: rotateX(180deg);
}
}
@-ms-keyframes slideInSkew {
from {
-ms-transform-origin: 0% 100%;
-ms-transform: translateX(-200%) skewX(-45deg);
}
50% {
-ms-transform-origin: 0% 100%;
-ms-transform: translateX(0%) skewX(-45deg);
}
90% {
-ms-transform-origin: 0% 100%;
-ms-transform: translateX(0%) skewX(10deg);
}
to {
-ms-transform-origin: 0% 100%;
-ms-transform:translateX(0%) skewX(0deg);
}
}
@-ms-keyframes slideOutSkew {
from {
-ms-transform-origin: 0% 100%;
-ms-transform: translateX(0%);
}
to {
-ms-transform-origin: 0% 100%;
-ms-transform: skewX(-45deg) translateX(200%) ;
}
}
@-ms-keyframes tumbleIn {
from {
-ms-transform-origin: 0% 100%;
-ms-transform: rotateZ(-180deg);
}
to {
-ms-transform-origin: 0% 100%;
}
}
@-ms-keyframes tumbleOut {
from {
-ms-transform-origin: 100% 100%;
}
to {
-ms-transform-origin: 100% 100%;
-ms-transform: rotateZ(180deg);
}
}
@-ms-keyframes expandIn {
from {
-ms-transform: scale(0);
}
50% {
-ms-transform: scale(1);
}
75% {
-ms-transform: scale(1.2);
}
to {
-ms-transform: scale(1);
}
}
@-ms-keyframes collapseOut {
to {
-ms-transform: scale(0);
}
}

View File

@@ -0,0 +1,174 @@
/* app css start */
html, body, .map-container{
width:100%;
height:100%;
}
.dropdown-menu .short-cut{
float: right;
font-size: 12px;
}
.app-tool-bar{
position: fixed;
top: 10px;
left: 10px;
z-index: 9999;
}
.app-tool-bar .dropdown-menu{
min-width: 250px;
}
.app-tool-bar > .dropdown-menu{
display: block;
min-width: 40px;
}
.app-tool-bar .dropdown-menu > li > a{
padding: 5px 10px;
}
.app-tool-bar .dropdown-submenu > a:after{
margin-right: -5px;
margin-top: 3px;
}
.app-container {
position: relative;
width:100%;
height:100%;
overflow: hidden;
}
.map{
width: 2000px;
height: 2000px;
background:url('../img/bg.gif') repeat;
}
.app-footer {
position: fixed;
left: 0px;
bottom: 0px;
width: 100%;
height: 40px;
line-height: 40px;
background-color: #000;
text-align: center;
z-index: 9999;
}
.app-footer:after{
clear: both;
}
.app-footer a{
color: #333;
}
.app-footer a:hover{
text-decoration: none;
color: #fff;
}
.app-footer .brand{
color: #000000;
font-weight: bold;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.1), 0 0 30px rgba(255, 255, 255, 0.125);
-webkit-transition: all .2s linear;
-moz-transition: all .2s linear;
transition: all .2s linear;
font-size: 20px;
position: absolute;
right: 90px;
top: 0px;
}
div.node{
position: absolute;
cursor: default;
}
div.node-caption{
min-width: 100px;
max-width: 300px;
padding:10px;
z-index: 99;
border: 1px solid rgba(0, 0, 0, 0.4);
border-radius : 6px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
background-color: black;
color: white;
position: absolute;
}
div.node-caption textarea{
margin: 0;
}
div.node-caption.black{
border-color: #222 #222 black;
background-color: #363636;
background-image: -webkit-linear-gradient(top, #444, #222);
background-repeat: repeat-x;
}
div.node-caption.red{
border-color: #BD362F #BD362F #802420;
background-color: #DA4F49;
background-image: -webkit-linear-gradient(top, #EE5F5B, #BD362F);
background-repeat: repeat-x;
}
div.node-caption.orange{
border-color: #F89406 #F89406 #AD6704;
background-color: #FAA732;
background-image: -webkit-linear-gradient(top, #FBB450, #F89406);
background-repeat: repeat-x;
}
div.node-caption.green{
border-color: #51A351 #51A351 #387038;
background-color: #5BB75B;
background-image: -webkit-linear-gradient(top, #62C462, #51A351);
background-repeat: repeat-x;
}
div.node-caption.blue{
border-color: #2F96B4 #2F96B4 #1F6377;
background-color: #2F96B4;
background-image: -webkit-linear-gradient(top, #5BC0DE, #2F96B4);
background-image: -moz-linear-gradient(top, #5BC0DE, #2F96B4);
background-repeat: repeat-x;
}
div.node-caption.dark-blue{
border-color: #04C #04C #002A80;
background-color: #04C;
background-image: -webkit-linear-gradient(top, #08C, #04C);
background-repeat: repeat-x;
}
div.node-caption:hover{
background-position: 0 -15px;
transition: background-position 0.1s linear 0s;
}
div.node-caption.blue:hover{
background-color: #2F96B4;
}
div.node canvas{
position:absolute;
}
.modal .app-file-list{
max-height: 200px;
overflow: auto;
}
.modal .app-file-name{
padding-top: 20px;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
html,body{margin:0;padding:0;}
html{background-color: rgb(0,135,255);height:100%;}
body{background-color: white;min-height:100%;}
.contentWrapper{width:940px;margin:0 auto;overflow: hidden;}
.nav{padding:30px 0;}
.next-page{float:right;}

View File

@@ -0,0 +1,236 @@
/**
* QUnit v1.7.0pre - A JavaScript Unit Testing Framework
*
* http://docs.jquery.com/QUnit
*
* Copyright (c) 2012 John Resig, Jörn Zaefferer
* Dual licensed under the MIT (MIT-LICENSE.txt)
* or GPL (GPL-LICENSE.txt) licenses.
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 15px 15px 0 0;
-moz-border-radius: 15px 15px 0 0;
-webkit-border-top-right-radius: 15px;
-webkit-border-top-left-radius: 15px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-header label {
display: inline-block;
padding-left: 0.5em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests ol {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 15px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
box-shadow: inset 0px 2px 13px #999;
-moz-box-shadow: inset 0px 2px 13px #999;
-webkit-box-shadow: inset 0px 2px 13px #999;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
margin: 0.5em;
padding: 0.4em 0.5em 0.4em 0.5em;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #5E740B;
background-color: #fff;
border-left: 26px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 26px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 15px 15px;
-moz-border-radius: 0 0 15px 15px;
-webkit-border-bottom-right-radius: 15px;
-webkit-border-bottom-left-radius: 15px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

View File

@@ -0,0 +1,68 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>MindMap帮助文档</title>
<link rel="stylesheet" type="text/css" href="../css/help.css">
</head>
<body>
<script type="text/javascript" src="../js/help.js"></script>
<script type="text/javascript">
SetupBodyBringToViewAnimation("whirlIn");
</script>
<div class="contentWrapper">
<h1>MindMap帮助文档</h1>
<h2>简介</h2>
<p>
MindMap是一款web版的思维导图应用整个项目使用html+css+javascript开发。MindMap利用了许多html5特性:<a href="http://www.html5rocks.com/en/features/storage">Storage</a><a href="http://www.html5rocks.com/en/features/file_access">File Access</a><a href="http://www.html5rocks.com/en/features/graphics">Graphics</a><a href="http://www.html5rocks.com/en/features/presentation">Presentation</a>
</p>
<h2>技术实现</h2>
<p>
MindMap以<a href="http://twitter.github.com/bootstrap/">bootstrap</a>为基础开发css+html。
</p>
<p>
MindMap采用OOP的开发方式使用类似<a href="http://backbonejs.org/">backbone</a><a href="https://github.com/documentcloud/backbone/blob/master/backbone.js#LC1454">extend</a>方法实现继承。许多设计模式被应用到MindMap中使用Command模式实现操作的Undo和Redo功能使用Compositon模式组织map和node对象等等。
</p>
<p>
MindMap的js组织方式变量命名方式受到<a href="https://developers.google.com/closure/library/">google closure</a>的影响。 MindMap实现了一个类似closure的js加载器配合一个nodejs脚本用于生成js文件依赖记录来管理组件之间的依赖关系。
</p>
<h2>兼容性</h2>
<p>
目前mindMap支持Firefox19、Chrome25。我没有条件测试Safari而Opera最近宣布将加入webkit的大家庭所以我也没有再花时间测试MindMap不支持IE。
</p>
<h2>功能特性</h2>
<ol>
<li>
可以将map保存为本地的文本文件也能打开本地文本格式的map
</li>
<li>
可以将map保存在浏览器的storage中也能打开在storage中的map
</li>
<li>
创建新的map为map添加节点为节点添加子节点删除节点。
</li>
<li>
改变节点的内容、位置
</li>
<li>
保存操作实现了简单的redo和undo功能
</li>
<li>
节点的copy、cut、paste功能
</li>
</ol>
<div class="nav">
<a href="javascript:void(0);" class="next-page" onclick="TriggerBodyRemoveFromViewAnimation('whirlOut','map.html');">下一节map操作</a>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,46 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>templates</title>
<style>
html{background-color: rgb(0,135,255);}
body{background-color: white;padding:0;margin:0;}
.contentWrapper{width:940px;margin:0 auto;}
</style>
<link rel="stylesheet" type="text/css" href="css/FullPageAnimationsPrefixed.css">
</head>
<body>
<script type="text/javascript" src="js/help.js"></script>
<script type="text/javascript">
SetupBodyBringToViewAnimation("fadeIn");
</script>
<div class="contentWrapper">
<div><h1>mindMap帮助文档</h1></div>
<div>
<h2>简介</h2>
<p>MindMap是一款web版的思维导图应用整个项目使用html+css+javascript开发。MindMap利用了许多html5特性:<a href="http://www.html5rocks.com/en/features/storage">Storage</a><a href="http://www.html5rocks.com/en/features/file_access">File Access</a><a href="http://www.html5rocks.com/en/features/graphics">Graphics</a><a href="http://www.html5rocks.com/en/features/presentation">Presentation</a>。目前mindMap支持的浏览器有Firefox19、Chrome25我没有条件测试Safari而Opera最近宣布将加入webkit的大家庭所以我也没有再花时间测试mindMap不支持IE。</p>
<p>建立MindMap的目的是将自己在学习工作中积累的新知识和技巧应用到实践中。</p>
<p>MindMap以<a href="http://twitter.github.com/bootstrap/">bootstrap</a>为基础开发css+html。
js结构命名方式类似于<a href="https://developers.google.com/closure/library/">google closure</a>mindMap实现了一个类似closure的js加载器并且使用一个nodejs脚本管理js文件的依赖关系。</p>
<h2>功能特性</h2>
<ol>
<li>可以将map保存为本地的文本文件也能本地文本格式的map</li>
<li>可以将map保存在浏览器的storage中也能打开在storage中的map</li>
<li>创建新的map为map添加节点为节点添加子节点删除节点。</li>
<li>改变节点的内容、位置</li>
<li>保存操作实现了简单的redo和undo功能</li>
<li>节点的copy、cut、paste功能</li>
</ol>
</div>
<div></div>
</div>
</body>
</html>

View File

@@ -0,0 +1,103 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>MindMap帮助文档</title>
<link rel="stylesheet" type="text/css" href="../css/help.css">
</head>
<body>
<script type="text/javascript" src="../js/help.js"></script>
<script type="text/javascript">
SetupBodyBringToViewAnimation("rotateInLeft");
</script>
<div class="contentWrapper">
<h1>MindMap帮助文档</h1>
<h2>map操作</h2>
<ol>
<li>
<p>
创建新mapfile-〉Create New Map 或者使用快捷键[ctrl+m]
</p>
<p><img src="../img/help/create_new_map.png" alt="create new map" title="" />
</p>
</li>
<li>
<p>
打开硬盘中的mapfile-〉Open Map In Disk
</p>
<p><img src="../img/help/open_map_in_disk.png" alt="open map in disk" title="" />
</p>
</li>
<li>
<p>
打开storage中的mapfile-〉Open Map In Storage
</p>
<p><img src="../img/help/open_map_in_storage.png" alt="open map in storage" title="" />
</p>
</li>
<li>
<p>
将map保存到硬盘中file-〉Save Map In Disk 或者使用快捷键[ctrl+shift+s]
</p>
<p><img src="../img/help/save_map_in_disk.png" alt="open map in storage" title="" />
</p>
</li>
<li>
<p>
将map保存到storage中file-〉Save Map In Storage 或者使用快捷键[ctrl+s]
</p>
<p><img src="../img/help/save_map_in_storage.png" alt="open map in storage" title="" />
</p>
</li>
<li>
<p>
contextMenu: 右键点击map空白处
</p>
</li>
<li>
<p>
取消上一步操作file-〉Undo 或者 contextMenu-〉Undo 或者使用快捷键[ctrl+z]
</p>
<p><img src="../img/help/undo1.png" alt="undo" title="" />
</p>
<p><img src="../img/help/undo2.png" alt="undo" title="" />
</p>
</li>
<li>
<p>
还原上一步操作file-〉Redo 或者 contextMenu-〉Redo 或者使用快捷键[ctrl+y]
</p>
<p><img src="../img/help/redo1.png" alt="redo" title="" />
</p>
<p><img src="../img/help/redo2.png" alt="redo" title="" />
</p>
</li>
<li>
<p>
查看help文档
</p>
<p><img src="../img/help/help.png" alt="redo" title="" />
</p>
</li>
</ol>
<div class="nav">
<a href="javascript:void(0);" class="prev-page" onclick="TriggerBodyRemoveFromViewAnimation('rotateOutRight','introduce.html');">上一节MindMap简介</a>
<a href="javascript:void(0);" class="next-page" onclick="TriggerBodyRemoveFromViewAnimation('rotateOutRight','node.html');">下一节node操作</a>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>MindMap帮助文档</title>
<link rel="stylesheet" type="text/css" href="../css/help.css">
</head>
<body>
<script type="text/javascript" src="../js/help.js"></script>
<script type="text/javascript">
SetupBodyBringToViewAnimation("rotateInLeft");
</script>
<div class="contentWrapper">
<h1>MindMap帮助文档</h1>
<h2>node操作</h2>
<ol>
<li>
<p>
选中节点:左键单击节点
</p>
</li>
<li>
<p>
nodeContextMenu右键单击节点
</p>
</li>
<li>
<p>
修改节点位置:左键点击节点不松,拖动鼠标
</p>
</li>
<li>
<p>
修改节点内容nodeContextMenu-〉edit
</p>
<p><img src="../img/help/edit_node.png" alt="edit node" title="" />
</p>
</li>
<li>
<p>
创建根节点contextMenu-〉Creat New Root Node
</p>
<p><img src="../img/help/create_root_node.png" alt="cteate root node" title="" />
</p>
</li>
<li>
<p>
添加子节点nodeContextmenu-> Append Child Node
</p>
<p><img src="../img/help/append_child_node.png" alt="append child node" title="" />
</p>
</li>
<li>
<p>
删除节点nodeContextMenu-〉Delete
</p>
<p><img src="../img/help/delete.png" alt="delete node" title="" />
</p>
</li>
<li>
<p>
复制节点:选中节点-〉(点击右键-〉Copy或者file-〉Copy 或者使用快捷键[ctrl+c]
</p>
<p><img src="../img/help/copy_node.png" alt="copy node" title="" />
</p>
</li>
<li>
<p>
剪切节点:选中节点-〉(点击右键-〉cut或者file-〉cut 或者使用快捷键[ctrl+x]
</p>
<p><img src="../img/help/cut_node.png" alt="cut node" title="" />
</p>
</li>
<li>
<p>
粘贴节点:选中节点-〉(点击右键-〉Paste或者file-〉Paste 或者使用快捷键[ctrl+v]
</p>
<p><img src="../img/help/paste_node.png" alt="paste" title="" />
</p>
</li>
</ol>
<div class="nav">
<a href="javascript:void(0);" class="prev-page" onclick="TriggerBodyRemoveFromViewAnimation('rotateOutRight','map.html');">上一节map操作</a>
<a href="javascript:void(0);" class="next-page" onclick="TriggerBodyRemoveFromViewAnimation('fadeOut','../index.html');">Go to MindMap</a>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>kampfer's mindMap</title>
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../css/bootstrap-responsive.min.css">
<link rel="stylesheet" type="text/css" href="../css/app.css">
<script type="text/javascript" src="../js/base.js"></script>
<script type="text/javascript">
kampfer.require('mindMap.Menu');
</script>
</head>
<body>
<!-- MapContainer
================================================== -->
<div class="map-container">
<div class="node" style="left:600px;top:100px;">
<div class="node-caption black">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="left:600px;top:200px;">
<div class="node-caption red">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="left:600px;top:300px;">
<div class="node-caption orange">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="left:900px;top:100px;">
<div class="node-caption green">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="left:900px;top:200px;">
<div class="node-caption blue">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="left:900px;top:300px;">
<div class="node-caption dark-blue">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
</div>
<!-- menu
================================================== -->
<ul class="dropdown-menu" id="menu">
<li><a tabindex="-1" href="javascript:void(0);" command="fuck">Action</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Another action</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="cry">Something else here</a></li>
<li class="divider"></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="javascript:void(0);">More options</a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="javascript:void(0);">Second level link</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Second level link</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Second level link</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Second level link</a></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="javascript:void(0);">Second level link</a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="javascript:void(0);">Third level link</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Third level link</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);">Third level link</a></li>
</ul>
</li>
</ul>
</li>
<li><a tabindex="-1" href="javascript:void(0);">Another action</a></li>
<li><a tabindex="-1" href="javascript:void(0);">Second level link</a></li>
</ul>
<!-- script
================================================== -->
<script type="text/javascript">
var menu = new kampfer.mindMap.Menu('menu');
kampfer.events.addListener(menu, 'beforeshow', function(event) {
console.log(event.type);
});
kampfer.events.addListener(menu, 'beforehide', function(event) {
console.log(event.type);
});
kampfer.events.addListener(menu, 'cry', function(event) {
console.log(event.type);
});
kampfer.events.addListener(document, 'contextmenu', function(event) {
menu.setPosition(event.pageX, event.pageY);
menu.show();
return false;
});
kampfer.events.addListener(document, 'click', function(event) {
if(event.which === 1) {
menu.hide();
return false;
}
});
menu.disable(0);
</script>
</body>
</html>

View File

@@ -0,0 +1,225 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>kampfer's mindMap</title>
<link rel="stylesheet" type="text/css" href="../css/app.css">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../css/bootstrap-responsive.min.css">
</head>
<body>
<!-- Navbar
================================================== -->
<div class="app-vertical-nav">
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#"><i class="icon-file"></i></a></li>
<li><a tabindex="-1" href="#"><i class="icon-eject"></i></a></li>
<li><a tabindex="-1" href="#"><i class="icon-plus"></i></a></li>
<li class="divider"></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="#"><i class="icon-file"></i></a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#"><i class="icon-exclamation-sign"></i> open new file</a></li>
<li><a tabindex="-1" href="#"><i class="icon-leaf"></i> open new file</a></li>
<li><a tabindex="-1" href="#"><i class="icon-folder-close"></i> open new file</a></li>
</ul>
</li>
</ul>
</div>
<!-- MapContainer
================================================== -->
<div class="app-container">
<div class="node" style="right:10px;top:50px;">
<div class="node-caption black">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="right:10px;top:140px;">
<div class="node-caption red">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="right:240px;top:50px;">
<div class="node-caption orange">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="right:240px;top:140px;">
<div class="node-caption green">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="right:470px;top:50px;">
<div class="node-caption blue">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
<div class="node" style="right:470px;top:140px;">
<div class="node-caption dark-blue">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
</div>
<!-- footer
================================================== -->
<div class="app-footer">
<div class="container">
<!--
© 2011-2012 l.w.kampfer@gmail.com
-->
<p>© 2011-2012 <a href="#">kampfer</a></p>
<a href="#" class="brand">Kampfer's MindMap</a>
</div>
</div>
<!-- save as
================================================== -->
<div style="left:350px;top:50px;" class="modal">
<div class="modal-header">
<button class="close" type="button">×</button>
<h3>Save As :</h3>
</div>
<div class="modal-body">
<p class="text-info">There are 13 maps in your localstorage.</p>
<div class="app-file-list">
<table class="table table-condensed table-hover table-striped">
<thead>
<tr>
<th>#</th>
<th>map name</th>
<th>lastModified</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><i class="icon-file"></i> kampfer's mindmap1</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>2</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr class="info">
<td>3</td>
<td><i class="icon-file"></i> kampfer's mindmap3</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>4</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>5</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>6</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>7</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>8</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>9</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>10</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>11</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>12</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>13</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>14</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>15</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
<tr>
<td>16</td>
<td><i class="icon-file"></i> kampfer's mindmap2</td>
<td>2012-12-12</td>
</tr>
</tbody>
</table>
</div>
<div class="app-file-name">
<div class="input-prepend">
<span class="add-on">File name :</span>
<input class="span4" id="prependedInput" type="text" placeholder="Please write file name">
</div>
</div>
</div>
<div class="modal-footer">
<a class="btn" href="#">Close</a>
<a class="btn btn-primary" href="#">Save changes</a>
</div>
</div>
<!-- drop menu
================================================== -->
<div class="dropdown clearfix" style="left:675px;top:250px;">
<ul class="dropdown-menu" role="menu" style="3">
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="#">More options</a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#">Second level link</a></li>
<li class="disabled"><a tabindex="-1" href="#">Second level link</a></li>
<li><a tabindex="-1" href="#">Second level link</a></li>
<li><a tabindex="-1" href="#">Second level link</a></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="#">Second level link</a>
<ul class="dropdown-menu">
<li><a tabindex="-1" href="#">Third level link</a></li>
<li><a tabindex="-1" href="#">Third level link</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Third level link</a></li>
</ul>
</li>
</ul>
</li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li class="disabled"><a tabindex="-1" href="#">Second level link</a></li>
</ul>
</div>
<!-- tip bar
================================================== -->
<div class="alert fade in alert-error">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Holy guacamole!</strong> Best check yo self, you're not looking too good.
</div>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>templates</title>
</head>
<body></body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,112 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Kampfer's MindMap</title>
<link rel="stylesheet" type="text/css" href="./css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="./css/bootstrap-responsive.min.css">
<link rel="stylesheet" type="text/css" href="./css/app.css">
<script type="text/javascript" src="./js/base.js"></script>
</head>
<body>
<!-- toolbar
================================================== -->
<div class="app-tool-bar" id="app-tool-bar">
<ul class="dropdown-menu">
<li class="dropdown-submenu" role="menu-trigger">
<a href="javascript:void(0);" title="File" tabindex="-1"><i class="icon-file"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a tabindex="-1" href="javascript:void(0);" command="CreateNewMap"><span class="short-cut">Ctrl+M</span>Create New Map</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="OpenMapInStorage">Open Map In Storage</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="OpenMapInDisk">Open Map In Disk</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="SaveMapInStorage"><span class="short-cut">Ctrl+S</span>Save Map In Storage</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="SaveMapInDisk"><span class="short-cut">Ctrl+Shift+S</span>Save Map In Disk</a></li>
</ul>
</li>
<li class="dropdown-submenu" role="menu-trigger">
<a href="javascript:void(0);" title="Edit" tabindex="-1"><i class="icon-edit"></i></a>
<ul class="dropdown-menu" role="menu">
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Undo"><span class="short-cut">Ctrl+Z</span>Undo</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Redo"><span class="short-cut">Ctrl+Y</span>Redo</a></li>
</ul>
</li>
<li class="divider"></li>
<li id="help"><a href="help/introduce.html" title="Help" tabindex="-1"><i class="icon-question-sign"></i></a></li>
</ul>
</div>
<!-- MapContainer
================================================== -->
<div class="app-container" id="map-container">
<!-- map document
==================================================
<div class="map">
<div class="node" style="right:10px;top:50px;" role="node">
<div class="node-caption blue">As a thank you, we ask you to include an optional link back to Glyphicons whenever practical.</div>
<canvas></canvas>
</div>
</div>
-->
<!-- drop menu for map
================================================== -->
<ul class="dropdown-menu" id="context-menu">
<li><a tabindex="-1" href="javascript:void(0);" command="CreateNewRootNode">Create New Root Node</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Undo"><span class="short-cut">Ctrl+Z</span>Undo</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Redo"><span class="short-cut">Ctrl+Y</span>Redo</a></li>
<!--
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="SelectAll"><span class="short-cut">Ctrl+A</span>Select All</a></li>
-->
</ul>
<!-- drop menu for node
================================================== -->
<ul class="dropdown-menu" id="node-context-menu">
<li><a tabindex="-1" href="javascript:void(0);" command="AppendChildNode">Append Child Node</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="EditNodeContent">Edit Node</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="DeleteNode">Delete</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Copy"><span class="short-cut">Ctrl+C</span>Copy</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Cut"><span class="short-cut">Ctrl+X</span>Cut</a></li>
<li><a tabindex="-1" href="javascript:void(0);" command="Paste"><span class="short-cut">Ctrl+V</span>Paste</a></li>
</ul>
</div>
<!-- footer
================================================== -->
<div class="app-footer">
<div class="container">
<p>© 2012-2013 <a href="javascript:void(0);">kampfer</a></p>
<a href="javascript:void(0);" class="brand">Kampfer's MindMap</a>
</div>
</div>
<!-- others
================================================== -->
<div style="display:none;">
<input type="file" name="mapJson" id="mapJson" />
</div>
<!--
<script type="text/javascript">
kampfer.require('mindMap');
</script>
-->
<script type="text/javascript" src="js/mindmap.js"></script>
<script type="text/javascript">
kampfer.mindMap.init();
</script>
</body>
</html>

View File

@@ -0,0 +1,255 @@
/*global kampfer*/
kampfer.require('Class');
kampfer.provide('mindMap.MapManager');
/*
* MapManager类为mindmap提供数据支持。
* 注意:1.MapManager依赖的第三方组件store.js依赖JSON当浏览器不原生支持JSON时
* 需要额外引入JSON.js实现兼容。
* 2.MapManager提供的查询方法返回的都是对数据的引用因此它们都是只读的绝对不要直接
* 对它们进行写操作。
*/
kampfer.mindMap.MapManager = kampfer.Class.extend({
/**
* 实例化一个MapManager对象。
* 当传递给构建函数的参数是一个对象那么这个对象被用作mindmap数据来源
* @param name{string|object|null}
*/
initializer : function(data) {
this._oriData = data;
data = data || {};
this._nodeTree = data.document || [];
this._mapName = data.name;
this._lastModified = data.lastModified || +new Date();
//map用于快速查找
this._nodeMap = this.parseTree(this._nodeTree);
this._isModified = false;
},
_isModified : null,
//重命名map的时候先改变_mapName.保存时会检查_mapName和_mapData.name的一致性,
//两者如果不一致那么会删除localstore中名字叫_mapData.name的数据.并将_mapName
//和_mapData.name同步. 这个过程需要同时保存新名字和旧名字,_mapName保存新名字
//_mapData.name是旧名字。
_mapName : null,
//解析原始数据, 通过tree生成map
parseTree : function(data) {
var map = {};
for(var i = 0, root; (root = data[i]); i++) {
this.traverseNode(root, function(node) {
map[node.id] = node;
});
}
return map;
},
isModified : function() {
return this._isModified;
},
getMapName : function() {
return this._mapName;
},
getNode : function(id) {
return this._nodeMap[id];
},
getChildren : function(id) {
if(id) {
var node = this.getNode(id);
return node.children;
}
},
getNodeTree : function() {
return this._nodeTree;
},
//如果有同id的node那么新的node不会被添加
addNode : function(node) {
if( kampfer.type(node) === 'object' && !this.getNode(node.id) ) {
var parent = this.getNode(node.parent);
//add node to nodeTree
if(parent) {
if(!parent.children) {
parent.children = [];
}
parent.children.push(node);
} else {
this._nodeTree.push(node);
}
//保存node和它的子节点的引用
this.traverseNode(node, function(node) {
if( !(node.id in this._nodeMap) ) {
this._nodeMap[node.id] = node;
}
});
this._isModified = true;
}
},
createNode : function(data) {
var node = {
id : this.generateUniqueId(),
parent : null,
children : null,
content : 'node',
offset : {
x : 100,
y : 100
}
},
type = kampfer.type(data);
if( type === 'object' ) {
for(var attr in node) {
if(attr in data) {
if(attr === 'offset') {
node[attr].x = data[attr].x;
node[attr].y = data[attr].y;
} else {
node[attr] = data[attr];
}
}
}
} else if( type === 'string' ) {
node.parent = data;
}
return node;
},
//此方法会立即改变children数组的长度
deleteNode : function(id) {
var node = this.getNode(id), parent, nodeList;
if(!node) {
return;
}
parent = this.getNode(node.parent);
if(!parent) {
nodeList = this._nodeTree;
} else if(parent.children) {
nodeList = parent.children;
}
if(nodeList) {
//delete node from tree
for(var i = 0, c; (c = nodeList[i]); i++) {
if(c.id === id) {
nodeList.splice(i, 1);
break;
}
}
}
//delete node from map
this.traverseNode(node, function(node) {
delete this._nodeMap[node.id];
});
this._isModified = true;
return node;
},
setNodeContent : function(id, text) {
var node = this.getNode(id);
node.content = text;
this._isModified = true;
},
getNodeContent : function(id) {
var node = this.getNode(id);
return node.content;
},
setNodePosition : function(id, x, y) {
if(kampfer.type(id) === 'object') {
id = id.id;
}
var node = this.getNode(id);
node.offset.x = x;
node.offset.y = y;
this._isModified = true;
},
//传值
getNodePosition : function(id) {
var node = this.getNode(id);
return {
left : node.offset.x,
top : node.offset.y
};
},
setMapName : function(name) {
this._mapName = name;
this._isModified = true;
},
getMapData : function() {
return {
document : this._nodeTree,
name : this._mapName,
lastModified : this._lastModified
};
},
traverseNode : function(node, callback, forward) {
if(forward) {
callback.call(this, node);
}
if(node.children) {
for(var i = 0, child; (child = node.children[i]); i++) {
this.traverseNode(child, callback, forward);
}
}
if(!forward) {
callback.call(this, node);
}
},
traverse : function(callback) {
for(var i = 0, node; (node = this._nodeTree[i]); i++) {
this.traverseNode(node, callback, true);
}
},
/*
* 生成唯一id
* 直接使用时间戳不可行
* 以下方法摘自http://www.cnblogs.com/NoRoad/archive/2010/03/12/1684759.html
*/
generateUniqueId : function() {
var guid = "";
for(var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
if((i == 8) || (i == 12) || (i == 16) || (i == 20)) {
guid += "-";
}
}
return guid;
},
dispose : function() {
delete this._oriData;
delete this._nodeTree;
delete this._mapName;
delete this._lastModified;
delete this._nodeMap;
delete this._isModified;
}
});

View File

@@ -0,0 +1,125 @@
/*global kampfer*/
kampfer.require('Class');
kampfer.require('store');
kampfer.provide('mindMap.MapsManager');
/*
* 负责维护localStorage
* MapsManager提供的查询方法返回的都是对数据的引用因此它们都是只读的。
* 绝对不要直接对它们进行写操作。
* localStorage目前维护两部分内容:
* 1. map的信息
* 2. clipboard的信息
*/
kampfer.mindMap.MapsManager = kampfer.Class.extend({
initializer : function(appName) {
if(appName) {
this._appName = appName;
}
},
_appName : 'mindMap',
getAppName : function() {
return this._appName;
},
//从localStorage中读取mindMap保存的数据。
//如果没有任何数据,那么就创建一个新的空的数据对象,并将它写入 localStorage。
getMapStorage : function() {
var mapStore = kampfer.store.get(this._appName);
if(!mapStore) {
mapStore = {};
mapStore.maps = {};
mapStore.maps._count = 0;
kampfer.store.set(this._appName, mapStore);
}
return mapStore;
},
getMapData : function(name) {
var mapStore = this.getMapStorage();
if(name) {
return mapStore.maps[name];
}
},
//只接受object作为参数
saveMapToLocalStorage : function(data) {
if( kampfer.type(data) === 'object' ) {
var mapStorage = this.getMapStorage(),
name = data.name;
if( !(name in mapStorage.maps) ) {
mapStorage.maps._count++;
}
mapStorage.maps[name] = data;
kampfer.store.set(this._appName, mapStorage);
}
},
getMapCount : function() {
var mapStorage = this.getMapStorage();
return mapStorage.maps._count;
},
//返回包含所有map名字的数组
getMapList : function() {
var mapStorage = this.getMapStorage();
if(mapStorage.maps._count > 0) {
var ret = [];
for(var map in mapStorage.maps) {
if( map !== '_count') {
ret.push(mapStorage.maps[map]);
}
}
return ret;
}
},
hasMap : function(mapName) {
var mapStore = kampfer.store.get(this._appName);
if(mapStore) {
if(mapName in mapStore.maps) {
return true;
}
}
return false;
},
removeMap : function(mapName) {
if( this.hasMap(mapName) ) {
var mapStore = kampfer.store.get(this._appName);
delete mapStore.maps[mapName];
kampfer.store.set(this._appName, mapStore);
}
},
setClipboard : function(data) {
var mapStore = kampfer.store.get(this._appName);
if(mapStore) {
mapStore.clipboard = data;
kampfer.store.set(this._appName, mapStore);
}
},
getClipboard : function() {
var mapStore = kampfer.store.get(this._appName);
if(mapStore && mapStore.clipboard) {
return mapStore.clipboard;
}
},
removeClipboard : function() {
var mapStore = kampfer.store.get(this._appName);
if(mapStore && mapStore.clipboard) {
delete mapStore.clipboard;
kampfer.store.set(this._appName, mapStore);
}
}
});

View File

@@ -0,0 +1,369 @@
/*
* @Author : l.w.kampfer@gmail.com
*/
(function(global) {
var COMPILED = false;
var kampfer = {};
kampfer.global = global;
kampfer.basePath = '';
kampfer.implicitNamespaces = {};
kampfer.isProvided = function(name) {
return !kampfer.implicitNamespaces[name] && !!kampfer.getPropertyByName(name);
};
kampfer.getPropertyByName = function( name, obj ) {
var namespace = name.split('.'),
cur = obj || kampfer;
for( var part; (part = namespace.shift()); ) {
if( kampfer.isDefAndNotNull( cur[part] ) ) {
cur = cur[part];
} else {
return null;
}
}
return cur;
};
kampfer.exportPath = function(name, value, objectToExportTo) {
var cur = objectToExportTo || kampfer.global,
namespace = name.split('.');
for( var part; (part = namespace.shift()); ) {
if( !namespace.length && kampfer.isDefAndNotNull(value) ) {
cur[part] = value;
} else if( cur[part] ) {
cur = cur[part];
} else {
cur = cur[part] = {};
}
}
};
kampfer.provide = function(name) {
//if(!COMPILED) {
if( kampfer.isProvided(name) ) {
throw Error('Namespace "' + name + '" already declared.');
}
delete kampfer.implicitNamespaces[name];
var namespace = name;
while( (namespace = namespace.substring( 0, namespace.lastIndexOf('.') )) ) {
if( kampfer.getPropertyByName(namespace) ) {
break;
} else {
kampfer.implicitNamespaces[namespace] = true;
}
}
//}
kampfer.exportPath(name, null, kampfer);
};
kampfer.require = function(name) {
if( !COMPILED ) {
if ( !name || kampfer.isProvided(name) ) {
return;
}
var path = kampfer._getPathFromDeps(name);
if (path) {
kampfer._included[path] = true;
kampfer._writeScripts();
}
}
};
kampfer.addDependency = function( path, provides, requires ) {
if( !COMPILED ) {
var provide, require, deps;
path = path.replace(/\\/g, '/');
deps = kampfer._dependencies;
for( var i = 0; (provide = provides[i]); i++) {
deps.nameToPath[provide] = path;
if (!(path in deps.pathToNames)) {
deps.pathToNames[path] = {};
}
deps.pathToNames[path][provide] = true;
}
for( var j = 0; (require = requires[j]); j++) {
if (!(path in deps.requires)) {
deps.requires[path] = {};
}
deps.requires[path][require] = true;
}
}
};
if(!COMPILED) {
kampfer._inHtmlDocument = function() {
var doc = kampfer.global.document;
return typeof doc != 'undefined' && 'write' in doc;
// XULDocument misses write.
};
kampfer._getPathFromDeps = function(name) {
if( name in kampfer._dependencies.nameToPath ) {
return kampfer._dependencies.nameToPath[name];
} else {
return null;
}
};
kampfer._importScript = function(src) {
var _importScript = kampfer._writeScriptTag;
if(!kampfer._dependencies.written[src] && _importScript(src)) {
kampfer._dependencies.written[src] = true;
}
};
kampfer._writeScripts = function() {
var scripts = [],
seenScript = {},
deps = kampfer._dependencies;
function visitNode(path) {
if( path in deps.written ) {
return;
}
if( path in deps.visited ) {
if( !(path in seenScript) ) {
seenScript[path] = true;
scripts.push(path);
}
return;
}
deps.visited[path] = true;
if (path in deps.requires) {
for (var requireName in deps.requires[path]) {
if (!kampfer.isProvided(requireName)) {
if (requireName in deps.nameToPath) {
visitNode(deps.nameToPath[requireName]);
} else {
throw Error('Undefined nameToPath for ' + requireName + ' in ' + path);
}
}
}
}
if (!(path in seenScript)) {
seenScript[path] = true;
scripts.push(path);
}
}
for( var path in kampfer._included ) {
if( !deps.written[path] ) {
visitNode(path);
}
}
for( var i = 0; i < scripts.length; i++ ) {
if ( scripts[i] ) {
kampfer._importScript( kampfer.basePath + scripts[i] );
} else {
throw Error('Undefined script input');
}
}
};
kampfer._writeScriptTag = function(src) {
if( kampfer._inHtmlDocument() ) {
var doc = kampfer.global.document;
doc.write('<script type="text/javascript" src="' + src + '"></' + 'script>');
return true;
} else {
return false;
}
};
kampfer._findBasePath = function() {
if( !kampfer._inHtmlDocument() ) {
return;
}
var doc = kampfer.global.document,
scripts = doc.getElementsByTagName('script');
for(var i = scripts.length - 1; i >= 0; --i) {
var src = scripts[i].src,
qmark = src.lastIndexOf('?'),
l = (qmark === -1 ? src.length : qmark);
if (src.substr(l - 7, 7) == 'base.js') {
kampfer.basePath = src.substr(0, l - 7);
return;
}
}
};
kampfer._dependencies = {
pathToNames: {}, // 1 to many
nameToPath: {}, // 1 to 1
requires: {}, // 1 to many
visited: {}, // 避免在拓扑排序时循环访问同一个节点。访问过的节点将保存在这里
written: {} // 记录已经被加载到页面的js文件名
};
kampfer._included = {};
//寻找js默认路径即base.js的路径
kampfer._findBasePath();
//加载依赖关系记录
kampfer._importScript( kampfer.basePath + 'deps.js' );
}
kampfer.isDef = function(val) {
return val !== undefined;
};
kampfer.isDefAndNotNull = function(val) {
return val != null;
};
var _toString = Object.prototype.toString;
kampfer.type = function(value) {
return value == null ?
String(value) :
_class2type[ _toString.call(value) ] || 'object';
};
kampfer.isArray = function(val) {
return kampfer.type(val) === 'array';
};
kampfer.isObject = function(val) {
return kampfer.type(val) === 'object';
};
kampfer.isEmptyObject = function(val) {
if( kampfer.type(val) !== 'object' ) {
return;
}
for( var name in val ) {
return false;
}
return true;
};
kampfer.isWindow = function(obj) {
return !!obj && obj == obj.window;
};
kampfer.each = function( array, fn, thisObj ) {
for( var i = 0, len = (array && array.length) || 0; i < len; ++i ) {
if( i in array ) {
fn.call( thisObj || kampfer.global, i, array[i], array );
}
}
};
kampfer.extend = function() {
var src, target, name, len, i, deep, copyFrom, copyTo, clone;
i = 1;
len = arguments.length;
deep = false;
target = arguments[0] || {};
if( typeof target === 'boolean' ) {
deep = target;
i = 2;
target = arguments[1] || {};
}
if( i === len ) {
target = this;
--i;
}
for( ; i < len; i++ ) {
src = arguments[i];
if( src !== null ) {
for( name in src ) {
copyFrom = src[name];
copyTo = target[name];
if( copyTo === copyFrom ) {
continue;
}
if( deep && copyFrom && ( kampfer.isArray(copyFrom) ||
kampfer.isObject(copyFrom) ) ) {
if( kampfer.isArray(copyFrom) ) {
clone = copyTo && kampfer.isArray(copyTo) ? copyTo : [];
} else if( kampfer.isObject(copyFrom) ) {
clone = copyTo && kampfer.isObject(copyTo) ? copyTo : {};
}
target[name] = kampfer.extend( deep, clone, copyFrom );
} else if( copyFrom !== undefined ) {
target[name] = copyFrom;
}
}
}
}
return target;
};
kampfer.emptyFn = function() {};
kampfer.now = function() {
return +new Date();
};
kampfer.expando = 'kampfer' + kampfer.now();
var _class2type = {};
kampfer.each( "Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
_class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
if( kampfer.type( kampfer.global.kampfer ) != 'undefined' ) {
kampfer._kampfer = kampfer.global.kampfer;
}
if( kampfer.type( kampfer.global.k ) != 'undefined' ) {
kampfer._k = kampfer.global.k;
}
kampfer.global.kampfer = kampfer.global.k = kampfer;
})( (typeof exports !== 'undefined') ? exports : this );

View File

@@ -0,0 +1,184 @@
/*global kampfer console*/
kampfer.require('Component');
kampfer.require('dom');
kampfer.require('events');
kampfer.provide('mindMap.Branch');
kampfer.mindMap.Branch = kampfer.Component.extend({
initializer : function(data) {
kampfer.mindMap.Branch.superClass.initializer.apply(this, arguments);
this._id = this.prefix + data.id;
this.createDom();
},
createDom : function() {
this._element = kampfer.global.document.createElement('canvas');
},
decorate : function() {
kampfer.mindMap.Branch.superClass.decorate.apply(this, arguments);
var size = this.calculateSize(),
position = this.calculatePosition();
kampfer.dom.setStyle(this._element, {
left : position.left + 'px',
top : position.top + 'px'
});
this._element.width = size.width;
this._element.height = size.height;
this._element.id = this.prefix + this.getParent().getId();
this._element.setAttribute('role', 'branch');
this.drawLine();
},
getQuadrant : function() {
var position = this._parent.getPosition(),
x = position.left,
y = position.top;
if(x > 0 && y < 0) {
return 1;
}
if(x === 0 && y < 0) {
return 'topY';
}
if(x < 0 && y < 0) {
return 2;
}
if(x < 0 && y === 0) {
return 'leftX';
}
if(x < 0 && y > 0) {
return 3;
}
if(x === 0 && y > 0) {
return 'bottomY';
}
if(x > 0 && y > 0) {
return 4;
}
if(x > 0 && y === 0) {
return 'rightX';
}
},
calculateSize : function() {
var offset = this.getParent().getPosition(),
x = Math.abs(offset.left),
y = Math.abs(offset.top);
x = x <= 0 ? 10 : x;
y = y <= 0 ? 10 : y;
return {
width : x,
height : y
};
},
calculatePosition : function() {
var quadrant = this.getQuadrant(),
offset = this.getParent().getPosition();
switch(quadrant) {
case 1 :
return {
left : -offset.left,
top : 0
};
case 'topY' :
return {
left : -5,
top : 0
};
case 2 :
return {
left : 0,
top : 0
};
case 'leftX' :
return {
left : 0,
top : -5
};
case 3 :
return {
left : 0,
top : -offset.top
};
case 'bottomY' :
return {
left : -5,
top : -offset.top
};
case 4 :
return {
left : -offset.left,
top : -offset.top
};
case 'rightX' :
return {
left : -offset.left,
top : -5
};
default :
throw ('invalid quadrant!');
}
},
drawLine : function() {
var quadrant = this.getQuadrant(),
ctx = this._element.getContext('2d');
ctx.beginPath();
if(quadrant === 1) {
ctx.moveTo(0, ctx.canvas.height - 6);
ctx.lineTo(6, ctx.canvas.height);
ctx.lineTo(ctx.canvas.width, 0);
}
if(quadrant === 'topY') {
ctx.moveTo(0, ctx.canvas.height);
ctx.lineTo(ctx.canvas.width, ctx.canvas.height);
ctx.lineTo(ctx.canvas.width / 2, 0);
}
if(quadrant === 2) {
ctx.moveTo(ctx.canvas.width, ctx.canvas.height - 6);
ctx.lineTo(ctx.canvas.width - 6, ctx.canvas.height);
ctx.lineTo(0, 0);
}
if(quadrant === 'leftX') {
ctx.moveTo(ctx.canvas.width, 0);
ctx.lineTo(ctx.canvas.width, ctx.canvas.height);
ctx.lineTo(0, ctx.canvas.height / 2);
}
if(quadrant === 3) {
ctx.moveTo(ctx.canvas.width - 6, 0);
ctx.lineTo(ctx.canvas.width, 6);
ctx.lineTo(0, ctx.canvas.height);
}
if(quadrant === 'bottomY') {
ctx.moveTo(0, 0);
ctx.lineTo(ctx.canvas.width, 0);
ctx.lineTo(ctx.canvas.width / 2, ctx.canvas.height);
}
if(quadrant === 4) {
ctx.moveTo(6, 0);
ctx.lineTo(0, 6);
ctx.lineTo(ctx.canvas.width, ctx.canvas.height);
}
if(quadrant === 'rightX') {
ctx.moveTo(0, 0);
ctx.lineTo(0, ctx.canvas.height);
ctx.lineTo(ctx.canvas.width, ctx.canvas.height / 2);
}
ctx.fill();
},
prefix : 'branch-',
dispose : function() {}
});

View File

@@ -0,0 +1,96 @@
/*global kampfer console*/
kampfer.require('Component');
kampfer.require('dom');
kampfer.require('events');
kampfer.provide('mindMap.Caption');
kampfer.mindMap.Caption = kampfer.Component.extend({
initializer : function(data) {
kampfer.mindMap.Caption.superClass.initializer.apply(this, arguments);
this._id = this.prefix + data.id;
this.createDom();
this._contentHolder = document.createElement('div');
this._contentHolder.setAttribute('role', 'content');
this._element.appendChild(this._contentHolder);
this.setContent(data.content);
this.isEditing = false;
},
decorate : function() {
kampfer.mindMap.Caption.superClass.decorate.apply(this, arguments);
this._element.className = 'node-caption blue';
this._element.id = this._id;
this._element.setAttribute('role', 'caption');
this.fixPosition();
},
setContent : function(text) {
this.hideTextarea();
this.showContentHolder();
this._contentHolder.innerHTML = text;
this.isEditing = false;
},
getContent : function() {
return this._contentHolder.innerHTML;
},
fixPosition : function() {
var size = this.getSize();
this.setPosition( -(size.width / 2), -(size.height / 2) );
},
insertTextarea : function() {
var value = this.getContent();
if(!this._textarea) {
this._textarea = this._doc.createElement('textarea');
this._textarea.value = value;
this._textarea.id = 'node-editor';
this._textarea.setAttribute('node-type', 'editor');
this._textarea.className = 'node-editor';
this._element.appendChild(this._textarea);
this.isEditing = true;
} else {
this.showTextarea();
}
this.hideContentHolder();
},
showTextarea : function() {
if(this._textarea) {
this.isEditing = true;
this._textarea.style.display = '';
}
},
hideTextarea : function() {
if(this._textarea) {
this._textarea.style.display = 'none';
}
},
showContentHolder : function() {
this._contentHolder.style.display = '';
},
hideContentHolder : function() {
this._contentHolder.style.display = 'none';
},
getTextareaValue : function() {
if(this._textarea) {
return this._textarea.value;
}
},
prefix : 'caption-'
});

View File

@@ -0,0 +1,431 @@
/*global window kampfer console localStorage*/
kampfer.require('Class');
kampfer.require('JSON');
kampfer.require('BlobBuilder');
kampfer.require('saveAs');
kampfer.require('mindMap.Node');
kampfer.require('mindMap.Map');
kampfer.require('mindMap.MapManager');
kampfer.require('mindMap.MapsManager');
kampfer.require('mindMap.OpenMapDialog');
kampfer.require('mindMap.RenameMapDialog');
kampfer.provide('mindMap.command');
kampfer.provide('mindMap.map');
kampfer.provide('mindMap.mapManager');
kampfer.provide('mindMap.mapsManager');
kampfer.mindMap.map = null;
kampfer.mindMap.mapManager = null;
kampfer.mindMap.mapsManager = new kampfer.mindMap.MapsManager('mindMap');
kampfer.mindMap.command.Base = kampfer.Class.extend({
initializer : function() {},
execute : function() {},
unExecute : function() {},
needPush : false,
dispose : function() {}
});
kampfer.mindMap.command.CreateNewMap = kampfer.mindMap.command.Base.extend({
initializer : function(data, view) {
this.data = data;
this.view = view;
},
execute : function() {
kampfer.mindMap.mapManager = new kampfer.mindMap.MapManager(this.data);
kampfer.mindMap.map = new kampfer.mindMap.Map(kampfer.mindMap.mapManager);
this.view.addChild(kampfer.mindMap.map, true);
},
dispose : function() {
delete this.view;
delete this.data;
}
});
kampfer.mindMap.command.CreateNewMap.isAvailable = function() {
if(kampfer.mindMap.map || kampfer.mindMap.mapManager) {
return false;
}
return true;
};
kampfer.mindMap.command.CreateNewMap.shortcut = 'ctrl+m';
kampfer.mindMap.command.SaveMapInStorage = kampfer.mindMap.command.Base.extend({
initializer : function(data, view) {
if(!kampfer.mindMap.command.OpenMapInStorage.renameMapDialog) {
kampfer.mindMap.command.OpenMapInStorage.renameMapDialog =
new kampfer.mindMap.RenameMapDialog(kampfer.mindMap.mapsManager, view);
kampfer.events.addListener(kampfer.mindMap.command.OpenMapInStorage.renameMapDialog,
'ok', function(event, name) {
kampfer.mindMap.mapManager.setMapName(name);
document.title = name;
var map = kampfer.mindMap.mapManager.getMapData();
kampfer.mindMap.mapsManager.saveMapToLocalStorage(map);
kampfer.mindMap.mapManager._isModified = false;
});
}
},
execute : function() {
if( !kampfer.mindMap.mapManager.getMapName() ) {
kampfer.mindMap.command.OpenMapInStorage.renameMapDialog.show();
} else {
var map = kampfer.mindMap.mapManager.getMapData();
kampfer.mindMap.mapManager._isModified = false;
kampfer.mindMap.mapsManager.saveMapToLocalStorage(map);
}
}
});
kampfer.mindMap.command.SaveMapInStorage.isAvailable = function() {
if(kampfer.mindMap.map && kampfer.mindMap.mapManager) {
return true;
}
return false;
};
kampfer.mindMap.command.SaveMapInStorage.shortcut = 'ctrl+s';
kampfer.mindMap.command.SaveMapInDisk = kampfer.mindMap.command.Base.extend({
execute : function() {
var content = JSON.stringify( kampfer.mindMap.mapManager.getMapData() );
var mapName = kampfer.mindMap.mapManager.getMapName();
//The standard W3C File API BlobBuilder interface is not available in all browsers.
//BlobBuilder.js is a cross-browser BlobBuilder implementation that solves this.
var bb = new kampfer.BlobBuilder();
bb.append(content);
kampfer.saveAs( bb.getBlob('text/plain;charset=utf-8'), mapName + '.json' );
}
});
kampfer.mindMap.command.SaveMapInDisk.isAvailable =
kampfer.mindMap.command.SaveMapInStorage.isAvailable;
kampfer.mindMap.command.SaveMapInDisk.shortcut = 'shift+ctrl+s';
kampfer.mindMap.command.OpenMapInDisk = kampfer.mindMap.command.Base.extend({
initializer : function(data, view) {
if(!kampfer.mindMap.command.OpenMapInStorage.input) {
var input = kampfer.mindMap.command.OpenMapInStorage.input =
document.getElementById('mapJson');
kampfer.events.addListener(input, 'change', function(e){
if (window.File && window.FileReader && window.FileList && window.Blob) {
var files = e.target.files;
var onloadHandler = function(e) {
var result = e.target.result;
var data = JSON.parse(result);
kampfer.mindMap.mapManager = new kampfer.mindMap.MapManager(data);
kampfer.mindMap.map = new kampfer.mindMap.Map(kampfer.mindMap.mapManager);
view.addChild(kampfer.mindMap.map, true);
};
for(var i = 0, f; (f = files[i]); i++) {
var reader = new FileReader();
reader.onload = onloadHandler;
reader.readAsText(f);
}
} else {
alert('html5 files api');
}
});
}
},
execute : function(data, view) {
kampfer.events.dispatch(kampfer.mindMap.command.OpenMapInStorage.input, 'click');
}
});
kampfer.mindMap.command.OpenMapInDisk.isAvailable =
kampfer.mindMap.command.CreateNewMap.isAvailable;
kampfer.mindMap.command.OpenMapInStorage = kampfer.mindMap.command.Base.extend({
initializer : function(data, view) {
kampfer.mindMap.command.OpenMapInStorage.openMapDialog =
new kampfer.OpenMapDialog(kampfer.mindMap.mapsManager, view);
},
execute : function() {
kampfer.mindMap.command.OpenMapInStorage.openMapDialog.show();
}
});
kampfer.mindMap.command.OpenMapInStorage.isAvailable =
kampfer.mindMap.command.CreateNewMap.isAvailable;
kampfer.mindMap.command.CreateNewRootNode = kampfer.mindMap.command.Base.extend({
initializer : function(data) {
var nodeData = kampfer.mindMap.mapManager.createNode(),
window = kampfer.mindMap.map.getParent();
nodeData.offset.x = data.pageX + window.scrollLeft();
nodeData.offset.y = data.pageY + window.scrollTop();
this.nodeData = nodeData;
},
execute : function() {
var node = new kampfer.mindMap.Node(this.nodeData),
parent;
if(this.nodeData.parent) {
parent = kampfer.mindMap.map.getChild(this.nodeData.parent);
} else {
parent = kampfer.mindMap.map;
}
kampfer.mindMap.mapManager.addNode(this.nodeData);
parent.addChild(node, true);
},
unExecute : function() {
var parent;
if(this.nodeData.parent) {
parent = kampfer.mindMap.map.getChild(this.nodeData.parent);
} else {
parent = kampfer.mindMap.map;
}
parent.removeChild(this.nodeData.id, true);
kampfer.mindMap.mapManager.deleteNode(this.nodeData.id);
},
dispose : function() {
delete this.nodeData;
},
needPush : true
});
kampfer.mindMap.command.CreateNewRootNode.isAvailable = function() {
if(kampfer.mindMap.map) {
return true;
}
return false;
};
kampfer.mindMap.command.AppendChildNode = kampfer.mindMap.command.CreateNewRootNode.extend({
initializer : function() {
var nodeData = kampfer.mindMap.mapManager.createNode();
nodeData.parent = kampfer.mindMap.map.currentNode.getId();
this.nodeData = nodeData;
}
});
kampfer.mindMap.command.AppendChildNode.isAvailable = function() {
if(kampfer.mindMap.map.currentNode) {
return true;
}
return false;
};
kampfer.mindMap.command.DeleteNode = kampfer.mindMap.command.Base.extend({
initializer : function(data) {
var id = kampfer.mindMap.map.currentNode.getId();
this.nodeData = kampfer.mindMap.mapManager.getNode(id);
},
needPush : true,
execute : function() {
var parent;
if(this.nodeData.parent) {
parent = kampfer.mindMap.map.getChild(this.nodeData.parent);
} else {
parent = kampfer.mindMap.map;
}
parent.removeChild(this.nodeData.id, true);
kampfer.mindMap.mapManager.deleteNode(this.nodeData.id);
},
unExecute : function() {
var node = new kampfer.mindMap.Node(this.nodeData),
parent;
if(this.nodeData.parent) {
parent = kampfer.mindMap.map.getChild(this.nodeData.parent);
} else {
parent = kampfer.mindMap.map;
}
kampfer.mindMap.mapManager.addNode(this.nodeData);
parent.addChild(node, true);
},
dispose : function() {
delete this.nodeData;
}
});
kampfer.mindMap.command.DeleteNode.isAvailable = function() {
if(!kampfer.mindMap.map || !kampfer.mindMap.map.currentNode) {
return false;
}
return true;
};
kampfer.mindMap.command.SaveNodePosition = kampfer.mindMap.command.Base.extend({
initializer : function(data) {
var id = data.nodeId,
nodeData = kampfer.mindMap.mapManager.getNode(id);
this.oriX = nodeData.offset.x;
this.oriY = nodeData.offset.y;
this.newX = data.x;
this.newY = data.y;
this.nodeData = nodeData;
},
needPush : true,
execute : function() {
kampfer.mindMap.map.getChild(this.nodeData.id).moveTo(this.newX, this.newY);
kampfer.mindMap.mapManager.setNodePosition(this.nodeData.id, this.newX, this.newY);
},
unExecute : function() {
kampfer.mindMap.map.getChild(this.nodeData.id).moveTo(this.oriX, this.oriY);
kampfer.mindMap.mapManager.setNodePosition(this.nodeData.id, this.oriX, this.oriY);
},
dispose : function() {
delete this.nodeData;
delete this.oriY;
delete this.oriX;
delete this.newX;
delete this.newY;
}
});
kampfer.mindMap.command.EditNodeContent = kampfer.mindMap.command.Base.extend({
execute : function() {
kampfer.mindMap.map.currentNode.getCaption().insertTextarea();
}
});
kampfer.mindMap.command.SaveNodeContent = kampfer.mindMap.command.Base.extend({
initializer : function(data) {
this.nodeId = data.nodeId;
var view = kampfer.mindMap.map.getChild(this.nodeId);
this.oriContent = view.getCaption().getContent();
this.newContent = view.getCaption().getTextareaValue();
},
needPush : true,
execute : function() {
kampfer.mindMap.map.getChild(this.nodeId).getCaption().setContent(this.newContent);
kampfer.mindMap.mapManager.setNodeContent(this.nodeId, this.newContent);
},
unExecute : function() {
kampfer.mindMap.map.getChild(this.nodeId).getCaption().setContent(this.oriContent);
kampfer.mindMap.mapManager.setNodeContent(this.nodeId, this.oriContent);
},
dispose : function() {
delete this.view;
delete this.oriContent;
delete this.newContent;
}
});
kampfer.mindMap.command.Copy = kampfer.mindMap.command.Base.extend({
execute : function() {
var nodeId = kampfer.mindMap.map.currentNode.getId();
var node = kampfer.mindMap.mapManager.createNode(
kampfer.mindMap.mapManager.getNode(nodeId) );
kampfer.mindMap.mapsManager.setClipboard(node);
}
});
kampfer.mindMap.command.Copy.isAvailable = function() {
if(!kampfer.mindMap.map || !kampfer.mindMap.map.currentNode) {
return false;
}
return true;
};
kampfer.mindMap.command.Copy.shortcut = 'ctrl+c';
kampfer.mindMap.command.Cut = kampfer.mindMap.command.DeleteNode.extend({
execute : function() {
kampfer.mindMap.command.Cut.superClass.execute.apply(this);
var node = kampfer.mindMap.mapManager.createNode(this.nodeData);
kampfer.mindMap.mapsManager.setClipboard(node);
}
});
kampfer.mindMap.command.Cut.isAvailable = kampfer.mindMap.command.DeleteNode.isAvailable;
kampfer.mindMap.command.Cut.shortcut = 'ctrl+z';
kampfer.mindMap.command.Paste = kampfer.mindMap.command.CreateNewRootNode.extend({
initializer : function(data) {
this.nodeData = kampfer.mindMap.mapsManager.getClipboard();
//重置所有id
kampfer.mindMap.mapManager.traverseNode(this.nodeData, function(node) {
node.id = kampfer.mindMap.mapManager.generateUniqueId();
node.parent = null;
if(node.children) {
var child, i = 0;
while( (child = node.children[i++]) ) {
child.parent = node.id;
}
}
});
if(kampfer.mindMap.map.currentNode) {
this.nodeData.parent = kampfer.mindMap.map.currentNode.getId();
}
if(!this.nodeData.parent) {
var window = kampfer.mindMap.map.getParent();
this.nodeData.offset.x = data.pageX + window.scrollLeft();
this.nodeData.offset.y = data.pageY + window.scrollTop();
}
}
});
kampfer.mindMap.command.Paste.isAvailable = function() {
var clipboard = kampfer.mindMap.mapsManager.getClipboard();
if( !kampfer.mindMap.map || !clipboard || clipboard.length <= 0) {
return false;
}
return true;
};
kampfer.mindMap.command.Paste.shortcut = 'ctrl+v';

View File

@@ -0,0 +1,84 @@
/*global kampfer*/
kampfer.require('Class');
kampfer.require('mindMap.command');
kampfer.require('mindMap.map');
kampfer.require('mindMap.mapManager');
kampfer.require('mindMap.command.stack');
kampfer.require('mindMap.radio');
kampfer.require('mousetrap');
kampfer.provide('mindMap.command.Controller');
//暂时长这样吧#_#
//以后再改
kampfer.mindMap.command.Controller = kampfer.Class.extend({
initializer : function(window) {
this.view = window;
kampfer.mindMap.radio.addListener('executeCommand', this.doCommand, this);
var that = this;
for(var name in kampfer.mindMap.command) {
var command = kampfer.mindMap.command[name];
if(command.shortcut) {
if(!this._shortcut2Command) {
this._shortcut2Command = {};
}
this._shortcut2Command[command.shortcut] = name;
var that = this;
Mousetrap.bind(command.shortcut, function(event, shortcut) {
event.type = 'executeCommand';
event.command = that._shortcut2Command[shortcut];
that.doCommand(event);
return false;
});
}
}
},
getCommand : function(name) {
return kampfer.mindMap.command[name] ||
kampfer.mindMap.command.Base;
},
doCommand : function(event) {
var Command = kampfer.mindMap.command[event.command], command;
if( Command && (!Command.isAvailable || Command.isAvailable()) ) {
command = new Command(event, this.view);
command.execute();
if(command.needPush) {
kampfer.mindMap.command.stack.push(command);
} else {
command.dispose();
}
}
if(kampfer.mindMap.mapManager) {
if( kampfer.mindMap.mapManager.isModified() ) {
document.title = '*' + kampfer.mindMap.mapManager.getMapName();
} else {
document.title = kampfer.mindMap.mapManager.getMapName();
}
}
},
isCommandAvalilable : function(command) {
command = this.getCommand(command);
if( command.isAvailable && !command.isAvailable() ) {
return false;
} else {
return true;
}
},
_shortcut2Command : null,
dispose : function() {
kampfer.mindMap.CommandController.superClass.dispose.apply(this, arguments);
this.publishers = null;
this.commandStack = null;
}
});

View File

@@ -0,0 +1,124 @@
kampfer.require('mindMap.command');
kampfer.provide('mindMap.command.stack');
kampfer.provide('mindMap.command.Redo');
kampfer.provide('mindMap.command.Undo');
kampfer.mindMap.command.stack = {
_queue : [],
// <index 是execute过的命令
// >=index 是被unExecute过的命令
_index : 0,
_maxLength : 50,
push : function(command) {
if(this._queue.length >= this._maxLength) {
this._queue.shift().dispose();
this._index--;
}
//this._queue.push(command);
//this._index++;
this._queue.splice(this._index++, 0, command);
},
stepForward : function() {
if( !this.atEnd() ) {
return this._queue[this._index++];
}
},
stepBackward : function() {
if( !this.atStart() ) {
this._index--;
return this._queue[this._index];
}
},
atEnd : function() {
if(this._index === this._queue.length) {
return true;
}
return false;
},
atStart : function() {
if(this._index === 0) {
return true;
}
return false;
},
get : function(index) {
if(index > 0 && index <= this._queue.length) {
return this._queue[index];
}
},
getStackLength : function() {
return this._queue.length;
},
getStackIndex : function() {
return this._index;
},
isEmpty : function() {
return this._queue.length === 0;
}
};
kampfer.mindMap.command.Undo = kampfer.mindMap.command.Base.extend({
execute : function(level) {
var kmcs = kampfer.mindMap.command.stack;
level = level || this.level;
for(var i = 0; i < this.level; i++) {
var command = kmcs.stepBackward();
if(command) {
command.unExecute();
}
}
},
level : 1
});
kampfer.mindMap.command.Undo.isAvailable = function() {
if( kampfer.mindMap.command.stack.isEmpty() ||
kampfer.mindMap.command.stack.atStart() ) {
return false;
}
return true;
};
kampfer.mindMap.command.Undo.shortcut = 'ctrl+z';
kampfer.mindMap.command.Redo = kampfer.mindMap.command.Base.extend({
execute : function(level) {
var kmcs = kampfer.mindMap.command.stack;
level = level || this.level;
for(var i = 0; i < this.level; i++) {
var command = kmcs.stepForward();
if(command) {
command.execute();
}
}
},
level : 1
});
kampfer.mindMap.command.Redo.isAvailable = function() {
if( kampfer.mindMap.command.stack.isEmpty() ||
kampfer.mindMap.command.stack.atEnd() ) {
return false;
}
return true;
};
kampfer.mindMap.command.Redo.shortcut = 'ctrl+y';

View File

@@ -0,0 +1,165 @@
/*global kampfer*/
kampfer.require('Composition');
kampfer.require('dom');
kampfer.provide('Component');
kampfer.Component = kampfer.Composition.extend({
initializer : function() {
this._wasDecorated = false;
this._inDocument = false;
},
_element : null,
_doc : kampfer.global.document,
_wasDecorated : null,
_inDocument : null,
addChild : function(child, render) {
kampfer.Component.superClass.addChild.apply(this, arguments);
if(child._inDocument && this._inDocument) {
//如果父子component都在文档流中那么将子component剪切到父component
this._element.appendChild( child.getElement() );
} else if(render) {
//如果需要渲染子component那么先确保父component已经生成了dom对象
//注意:这是个强制行为
if(!this._element) {
this.createDom();
}
child.render();
} else if(!child._inDocument && this._inDocument) {
//如果子component不在文档流中而父component在。那么如果子component已生成了dom对象
//就将子component插入文档流
if( child.getElement() ) {
child.enterDocument();
}
}
},
removeChild : function(child, unrender) {
child = kampfer.Component.superClass.removeChild.apply(this, arguments);
if(unrender) {
child.exitDocument();
var childElement = child.getElement();
if(child.childElement) {
child.childElement.parentNode.removeChild(child.childElement);
}
}
},
isInDocument : function() {
return this._inDocument;
},
wasDecorated : function() {
return this._wasDecorated;
},
render : function(parent) {
if(!this._inDocument) {
if(!this._element) {
this.createDom();
}
this.enterDocument(parent);
this.decorate();
this.eachChild(function(child) {
child.render();
});
}
},
createDom : function() {
this._element = this._doc.createElement('div');
},
getElement : function() {
return this._element;
},
/* 子类应该重写这个方法 */
decorate : function() {
if(!this._inDocument) {
throw ('component not in document');
}
this._wasDecorated = true;
},
enterDocument : function(parent) {
this._inDocument = true;
if(parent && parent.nodeType) {
parent.appendChild(this._element);
} else if( this._parent && this._parent.getElement() ) {
this._parent.getElement().appendChild(this._element);
} else {
this._doc.body.appendChild(this._element);
}
},
exitDocument : function() {
//if( this._parent && this._parent.getElement() ) {
// this._parent.getElement().removeChild(this._element);
//} else {
// this._doc.body.removeChild(this._element);
//}
this._element.parentNode.removeChild(this._element);
this._inDocument = false;
},
getPosition : function() {
if(this._element) {
return {
left : parseInt( kampfer.dom.getStyle(this._element, 'left'), 10 ),
top : parseInt( kampfer.dom.getStyle(this._element, 'top'), 10 )
};
}
},
setPosition : function(left, top) {
if(this._element) {
//kampfer.style.setStyle(this._element, {
// left : left + 'px',
// top : top + 'px'
//});
this._element.style.left = left + 'px';
this._element.style.top = top + 'px';
}
},
show : function() {
if(this._element) {
this.dispatch('beforeshow');
this._element.style.display = 'block';
}
},
hide : function() {
if(this._element) {
this.dispatch('beforehide');
this._element.style.display = 'none';
}
},
getSize : function() {
if(this._inDocument) {
return {
width : this._element.offsetWidth,
height : this._element.offsetHeight
};
}
},
dispose : function() {
kampfer.Component.superClass.dispose.apply(this);
}
});

View File

@@ -0,0 +1,197 @@
/*global kampfer*/
kampfer.require('events.EventTarget');
kampfer.provide('Composition');
/**
* 实现一个composition模式的类用于组织对象协调对象的关系。
* 涉及parent的方法(get,set)只会影响到实例对象本身而涉及child的方法不仅会影响对象自己
* 还会影响child实例对象。所以请使用child相关方法维护对象间的组织关系。
*/
kampfer.Composition = kampfer.events.EventTarget.extend({
//initializer : function() {},
//Composition实例
_parent : null,
//对象每一项都应该是Composition实例
_children : null,
_childrenCount : 0,
_id : null,
setId : function(id) {
var oldId = this._id;
this._id = id;
if(this._parent && this._parent._children) {
//this._parent._children[oldId] = null;
delete _parent._children[oldId];
this._parent.addChild(this);
}
},
getId : function() {
return this._id || ( this._id = this.generateUniqueId() );
},
/**
* 设置父对象。不能将parent设置为composition自己。
* 以下情况setParent将抛出异常
* 1. parent非null但不是一个composition实例
* 2. 尝试将parent设置为composition自己
* 3. parent非null且composition已经拥有了一个_parent且_parent!=parent
* @param {kampfer.mindMap.Composition}parent
*/
setParent : function(parent) {
if( parent && !(parent instanceof kampfer.Composition) ) {
throw('parent is not instanceof composition');
}
if( parent === this ) {
throw('parent cant be composition itself');
}
//如果parent已经存在
if( parent && this._parent && this._parent !== parent ) {
throw('parent already exist');
}
this.setParentEventTarget(parent);
this._parent = parent;
if( parent && !parent.getChild(this._id) ) {
parent.addChild(this);
}
},
getParent : function() {
return this._parent;
},
/**
* 添加子对象。
* @param {kampfer.mindMap.Composition} child
*/
addChild : function(child) {
if( !(child instanceof kampfer.Composition) ) {
throw('wrong type param');
}
var id = child.getId();
if(!this._children) {
this._children = {};
}
if(!this._children[id]) {
this._children[id] = child;
this._childrenCount++;
}else{
throw('can not add child');
}
if(child._parent !== this) {
child.setParent(this);
}
},
/**
* 删除子对象
* @param {string|kampfer.mindMap.Composition} child
*/
removeChild : function(child) {
if(child) {
var id, type = kampfer.type(child);
if(type === 'string') {
id = child;
child = this.getChild(id);
} else if(type === 'object') {
if( !(child instanceof kampfer.Composition) ) {
throw('wrong type param');
}
id = child.getId();
}
if(id && (id in this._children)) {
//this._children[id] = null;
delete this._children[id];
this._childrenCount--;
child.setParent(null);
}
if( this.hasNoChild() ) {
//this._children = null;
delete this._children;
}
}
return child;
},
getChild : function(id) {
var node;
this.eachChild(function(child, cid) {
if(cid === id) {
node = child;
return false;
}else {
child.eachChild(arguments.callee);
}
});
return node;
},
//fn(child, id)
eachChild : function(fn, context) {
if(this._children) {
for(var id in this._children) {
if( this._children[id] && fn.call( context, this._children[id], id ) === false ) {
return;
}
}
}
},
getChildrenCount : function() {
return this._childrenCount;
},
hasNoChild : function() {
if(this._childrenCount === 0) {
return true;
}
return false;
},
/*
* 生成唯一id
* 直接使用时间戳不可行
* 以下方法摘自http://www.cnblogs.com/NoRoad/archive/2010/03/12/1684759.html
*/
generateUniqueId : function() {
var guid = "";
for(var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
if((i == 8) || (i == 12) || (i == 16) || (i == 20)) {
guid += "-";
}
}
return guid;
},
dispose : function() {
kampfer.Composition.superClass.dispose.apply(this);
this._parent = null;
this._children = null;
}
});

View File

@@ -0,0 +1,40 @@
kampfer.addDependency('base.js', [], []);
kampfer.addDependency('branch.js', ['mindMap.Branch'], ['Component','dom','events']);
kampfer.addDependency('caption.js', ['mindMap.Caption'], ['Component','dom','events']);
kampfer.addDependency('command.js', ['mindMap.command','mindMap.map','mindMap.mapManager','mindMap.mapsManager'], ['Class','JSON','BlobBuilder','saveAs','mindMap.Node','mindMap.Map','mindMap.MapManager','mindMap.MapsManager','mindMap.OpenMapDialog','mindMap.RenameMapDialog']);
kampfer.addDependency('commandcontroller.js', ['mindMap.command.Controller'], ['Class','mindMap.command','mindMap.map','mindMap.mapManager','mindMap.command.stack','mindMap.radio','mousetrap']);
kampfer.addDependency('commandstack.js', ['mindMap.command.stack','mindMap.command.Redo','mindMap.command.Undo'], ['mindMap.command']);
kampfer.addDependency('component.js', ['Component'], ['Composition','dom']);
kampfer.addDependency('composition.js', ['Composition'], ['events.EventTarget']);
kampfer.addDependency('help.js', [], []);
kampfer.addDependency('kampfer/ajax.js', ['ajax'], []);
kampfer.addDependency('kampfer/base.js', [], []);
kampfer.addDependency('kampfer/class/class.js', ['Class'], []);
kampfer.addDependency('kampfer/class/composition.js', ['class.Composition'], ['events.EventTarget']);
kampfer.addDependency('kampfer/class/dialog.js', ['Dialog'], ['class.UIComponent','dom']);
kampfer.addDependency('kampfer/class/eventtarget.js', ['events.EventTarget'], ['events','Class']);
kampfer.addDependency('kampfer/class/uicomponent.js', ['class.UIComponent'], ['class.Composition','events']);
kampfer.addDependency('kampfer/class.js', ['Class'], []);
kampfer.addDependency('kampfer/data.js', ['data'], ['browser.support']);
kampfer.addDependency('kampfer/dom.js', ['dom'], []);
kampfer.addDependency('kampfer/events.js', ['events','events.Event','events.Listener'], ['data']);
kampfer.addDependency('kampfer/eventtarget.js', ['events.EventTarget'], ['events','Class']);
kampfer.addDependency('kampfer/helper/es5-shim.js', [], []);
kampfer.addDependency('kampfer/helper/json2.js', ['JSON'], []);
kampfer.addDependency('kampfer/support.js', ['browser.support'], []);
kampfer.addDependency('map.js', ['mindMap.Map'], ['events','dom','Component','mindMap.Node','mindMap.radio']);
kampfer.addDependency('MapManager.js', ['mindMap.MapManager'], ['Class']);
kampfer.addDependency('MapsManager.js', ['mindMap.MapsManager'], ['Class','store']);
kampfer.addDependency('menu.js', ['Menu','MenuItem'], ['Component','dom','events','mindMap.radio']);
kampfer.addDependency('mindmap.js', ['mindMap','mindMap.window','mindMap.toolBar','mindMap.nodeContextMenu','mindMap.contextMenu'], ['mindMap.Window','mindMap.ToolBar','mindMap.command.Controller','Menu','events']);
kampfer.addDependency('node.js', ['mindMap.Node'], ['events','dom','Component','mindMap.Branch','mindMap.Caption']);
kampfer.addDependency('openmapdialog.js', ['mindMap.OpenMapDialog'], ['Dialog','mindMap.command']);
kampfer.addDependency('plugins/BlobBuilder.min.js', ['BlobBuilder'], []);
kampfer.addDependency('plugins/FileSaver.min.js', ['saveAs'], []);
kampfer.addDependency('plugins/modernizr-latest.js', [], []);
kampfer.addDependency('plugins/mousetrap.min.js', ['mousetrap'], []);
kampfer.addDependency('plugins/store.min.js', ['store'], []);
kampfer.addDependency('radio.js', ['mindMap.radio'], ['events.EventTarget']);
kampfer.addDependency('renamemapdialog.js', ['mindMap.RenameMapDialog'], ['Dialog','mindMap.command']);
kampfer.addDependency('toolbar.js', ['mindMap.ToolBar'], ['Component','events','Menu']);
kampfer.addDependency('window.js', ['mindMap.Window'], ['Component','events','Menu','dom']);

View File

@@ -0,0 +1,144 @@
var animationName;
var transformName;
var perspectiveName;
var animationStartName;
var animationIterationName;
var animationEndName;
var BringToViewAnimations = ["rotateInLeft", "fadeIn", "whirlIn", "fallFromTop", "slideInSkew", "tumbleIn", "expandIn"];
var RemoveFromViewAnimations = ["rotateOutRight", "fadeOut", "whirlOut", "slideOutSkew", "tumbleOut"];
// Helper for adding an event listener to an element
function addListener(obj, eventName, listener, capture) {
if (obj.addEventListener) {
obj.addEventListener(eventName, listener, capture);
} else {
obj.attachEvent("on" + eventName, listener, capture);
}
}
// Simple function used to detect support for properties from a list of strings
var FirstSupportedPropertyName = function(prefixedPropertyNames) {
var tempDiv = document.createElement("div");
for (var i = 0; i < prefixedPropertyNames.length; ++i) {
if (typeof tempDiv.style[prefixedPropertyNames[i]] != 'undefined')
return prefixedPropertyNames[i];
}
return null;
};
var VerifyTransformAnimationSupport = function() {
if ((animationName != null) && (transformName != null)) {
return true;
}
return false;
};
// Fetches CSS files from the webserver and returns the plaintext
var XHRCSSFiles = function() {
var request = new XMLHttpRequest();
request.open("GET", "../css/FullPageAnimationsPrefixed.css", false);
request.send("");
return request.responseText;
};
function injectCSS(cssString) {
var ele = document.createElement("style");
ele.type = "text/css";
if (ele.styleSheet) {
ele.styleSheet.cssText = cssString;
} else {
ele.appendChild(document.createTextNode(cssString));
}
document.getElementsByTagName("head")[0].appendChild(ele);
}
// Since CSS Animations and Transforms are not always supported in their unprefixed form, we have to perform some feature detection
var DetectPrefixes = function() {
// First we figure out the attribute names for usage with bracket style attribute access notation
transformName = FirstSupportedPropertyName(["transform", "msTransform", "MozTransform", "WebkitTransform", "OTransform"]);
animationName = FirstSupportedPropertyName(["animation", "msAnimation", "MozAnimation", "WebkitAnimation", "OAnimation"]);
perspectiveName = FirstSupportedPropertyName(["perspective", "msPerspective", "MozPerspective", "WebkitPerspective", "OPerspective"]);
// The event names are a bit more tricky to handle due to capitalization
animationEndName = (animationName + "End").replace(/^ms/, "MS").replace(/^Webkit/, "webkit").replace(/^Moz.*/, "animationend").replace(/^animationEnd$/, "animationend");
animationStartName = (animationName + "Start").replace(/^ms/, "MS").replace(/^Webkit/, "webkit").replace(/^Moz.*/, "animationstart").replace(/^animationStart$/, "animationstart");
animationIterationName = (animationName + "Iteration").replace(/^ms/, "MS").replace(/^Webkit/, "webkit").replace(/^Moz.*/, "animationiteration").replace(/^animationIteration/, "animationiteration");
// We also have some declarative markup that we need to patch up (@keyframes rules and various CSS used in our Test Drive Demo)
var prefix = "";
// First we detect the proper prefix
if (animationName == "msAnimation") {
prefix = "-ms-";
} else if (animationName == "MozAnimation") {
prefix = "-moz-";
} else if (animationName == "WebkitAnimation") {
prefix = "-webkit-";
} else if (animationName == "OAnimation") {
prefix = "-o-";
}
// Then we fetch the CSS files (that have been composed using the -ms- prefix)
var CSSFileString = XHRCSSFiles();
// Following we do a simple String.replace of -ms- with the actual vendor prefix
CSSFileString = CSSFileString.replace(/-ms-/gi, prefix);
// And finally we inject the CSS
injectCSS(CSSFileString);
};
var ApplyAnimationToElement = function(element, animName) {
if (element.style[animationName + "Name"] == animName) {
// If we are reapplying an animation, we need to zero out the value and then reset the property after the function returns.
element.style[animationName + "Name"] = "";
setTimeout(function() { element.style[animationName + "Name"] = animName; });
} else {
element.style[animationName + "Name"] = animName;
}
};
var SetupAnimationParameters = function(element) {
element.style[animationName + "Delay"] = "0.0s";
element.style[animationName + "Duration"] = "1s";
element.style[animationName + "IterationCount"] = "1";
// Setting animation-fill-mode to "forwards" will preserve the to{} keyframe values after the animation
// is complete. As a result, we do not have to inject a transform on the body element to maintain the post-animation position
element.style[animationName + "FillMode"] = "forwards";
element.style[animationName + "TimingFunction"] = "linear";
element.style[animationName + "PlayState"] = "running";
};
var SetupBodyBringToViewAnimation = function(animName) {
if (!VerifyTransformAnimationSupport()) return;
//document.body.style.visibility = "visible";
if (!animName) {
animName = GetRandomAnimation(BringToViewAnimations);
}
//SetupProjectionOrigin();
SetupAnimationParameters(document.body);
ApplyAnimationToElement(document.body, animName);
};
var AnimationEndCallback = function(action) {
window.location.href = action;
};
var TriggerBodyRemoveFromViewAnimation = function(animName, action) {
if (!VerifyTransformAnimationSupport()) {
AnimationEndCallback(action);
return;
}
var ele = document.body;
// first we add a listener for the animationend event so we can perform a navigation once the transition is complete
addListener(ele, animationEndName, function() { AnimationEndCallback(action); });
// If you are not using the CSS wrapper pattern described in our article you may want to uncomment this
// in order to mitigate visual skewing from perspective projection
//SetupProjectionOrigin();
SetupAnimationParameters(document.body);
ApplyAnimationToElement(ele, animName);
};
DetectPrefixes();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,132 @@
kampfer.provide('ajax');
/**
* @Author l.w.kampfer@gmail.com
* @Name AJAX工具函数
* @Version 1.0
*/
(function( window, kampfer ) {
//XHR构造函数
var _XHRFactories = [
function() { return new XMLHttpRequest(); },
function() { return new window.ActiveXObject('Microsoft.XMLHTTP'); }
];
//默认设置
var _defaultSettings = {
url : '',
method : 'GET',
async : true,
parameters : {},
timeout : 10000,
ontimeout : function() {},
onerror : function() {},
onsuccess : function() {},
onbeforesend : function() {},
context : null,
headers : {}
};
var responceTypes = {
xml : /xml/,
json : /json/,
//html : /html/,
javascript : /javascript/
};
//将对象序列化为字符串
function _encodeFormData( data ) {
var pairs = [],
regSpace = /%20/g;
for( var name in data ) {
var value = data[name].toString();
//使用encodeURIComponent对名值对进行编码
var pair = encodeURIComponent( name ).replace( regSpace, '+' ) + '=' +
encodeURIComponent( value ).replace( regSpace, '+' );
pairs.push( pair );
}
return pairs.join( '&' );
}
//区别对待返回类型
function _getResponse( request ) {
var contentType = request.getResponseHeader('Content-Type');
if( responceTypes.xml.test( contentType ) ) {
return request.responseXML;
}else if( responceTypes.json.test( contentType ) || responceTypes.javascript.test( contentType ) ) {
return eval( '(' + request.responseText + ')' );
}else{
return request.responseText;
}
}
//创建新的XMLHttpRequest对象
function _createNewXHR() {
for( var i = 0, l = _XHRFactories.length; i < l; i++ ) {
try {
_XHRFactories[i]();
_createNewXHR = _XHRFactories[i];
break;
} catch( e ) {
//consle.log( ' XHR not supported' );
}
}
return _createNewXHR();
}
var ajax = function( options ) {
var newXHR = _createNewXHR(),
timer,
url,
parameters;
options = kampfer.extend( {}, _defaultSettings, options );
//设置执行上下文
if( !options.context ) {
options.context = newXHR;
}
if( options.ontimeout ) {
//闭包
timer = setTimeout( function(){
newXHR.abort();
if ( options.ontimeout ) {
options.ontimeout.call( options.context, options );
}
}, options.timeout );
}
newXHR.onreadystatechange = function() {
if( newXHR.readyState === 4 ) {
if( timer ) {
clearTimeout( timer );
}
if( newXHR.status === 200 ) {
options.onsuccess.call( options.context, _getResponse( newXHR ) );
} else {
if( options.onerror ) {
options.onerror.call( options.context, newXHR );
}
}
}
};
url = options.url;
parameters = options.parameters && _encodeFormData( options.parameters );
if( options.method.toUpperCase() === 'GET' ) {
if( options.parameters ) {
url += '?' + parameters + '&_=' + ( +new Date() );
}
newXHR.open( 'GET', url, options.async );
options.onbeforesend && options.onbeforesend.call( options.context, newXHR );
newXHR.send( null );
} else if( options.method.toUpperCase() === 'POST' ) {
newXHR.open( 'POST', url, options.async );
options.onbeforesend && options.onbeforesend.call( options.context, newXHR );
newXHR.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' );
newXHR.send( parameters );
}
};
kampfer.extend( kampfer, {
ajax : ajax
});
})( window, kampfer );

View File

@@ -0,0 +1,466 @@
/*
* @Author : l.w.kampfer@gmail.com
*/
(function() {
/**
* @define {boolean} Overridden to true by the compiler when --closure_pass
* or --mark_as_compiled is specified.
*/
var COMPILED = false;
/**
* @define {object} 定义命名空间kampfer。
* 所有需要公开的属性和方法都被将绑定在kampfer上。最后将检查全局变量
* 并把kampfer绑定到全局变量上
*/
var kampfer = {};
/**
* @define {object} 保存一个对全局对象的引用。
* 一般情况下global指向window对象。
*/
kampfer.global = this;
/**
* @define {string} base.js的路径
* 在异步加载js文件的时候,也会作为初始目录使用
*/
kampfer.basePath = '';
/**
* 用于保存所有被隐式声明的命名空间,此对象的属性名就是命名空间的名字
* @type {object}
*/
kampfer.implicitNamespaces = {};
/**
* 判断给定的命名空间是否已经初始化。判断条件如下:
* 1.命名空间没有被隐性的声明不在_implicitNamespaces中
* 2.命名空间非空
* 以上两个条件同时满足时说明命名空间已被注册方法返回true
* @param ns{string} 命名空间的名字
* @return {boolean} 已经被注册过则为true反之为false
* @private
*/
kampfer.isProvided = function(name) {
return !kampfer.implicitNamespaces[name] && !!kampfer.getPropertyByName(name);
};
/**
* 通过名字找到指定对象上的某个属性的值
* @param name{string} 命名空间的名字
* @param obj{object} 目标对象,将在这个对象上查找给定的名字空间。
* @return {*}
*/
kampfer.getPropertyByName = function( name, obj ) {
var namespace = name.split('.'),
cur = obj || kampfer;
for( var part; (part = namespace.shift()); ) {
if( kampfer.isDefAndNotNull( cur[part] ) ) {
cur = cur[part];
} else {
return null;
}
}
return cur;
};
/**
* 根据给定的名字空间创建一个对象结构object structure
* 保证已经存在的名字空间不会被覆盖重写。
* @param name{string} 命名空间名字
* @param value{*} 暴露在名字空间最后的对象
* @param objectToExportTo{object} 命名空间的宿主对象。默认为kampfer.global
*/
kampfer.exportPath = function(name, value, objectToExportTo) {
var cur = objectToExportTo || kampfer.global,
namespace = name.split('.');
for( var part; (part = namespace.shift()); ) {
if( !namespace.length && kampfer.isDefAndNotNull(value) ) {
cur[part] = value;
} else if( cur[part] ) {
cur = cur[part];
} else {
cur = cur[part] = {};
}
}
};
/**
* 声明命名空间。此方法将kampfer作为根节点所有新声明的命名空间都将被绑定在kampfer上。
* 构造新命名空间的过程中可能会产生隐性的命名空间provide方法将会将隐性的名字空间保存在
* implicitNamespaces属性中。打包程序将通过扫描provide在deps文件中生成一条关于本文件
* 依赖关系的记录。
* @param name{string} 命名空间的名字。
*/
kampfer.provide = function(name) {
//if(!COMPILED) {
if( kampfer.isProvided(name) ) {
throw Error('Namespace "' + name + '" already declared.');
}
delete kampfer.implicitNamespaces[name];
var namespace = name;
while( (namespace = namespace.substring( 0, namespace.lastIndexOf('.') )) ) {
if( kampfer.getPropertyByName(namespace) ) {
break;
} else {
kampfer.implicitNamespaces[namespace] = true;
}
}
//}
kampfer.exportPath(name, null, kampfer);
};
/**
* 定义文件所依赖的模块。打包程序将通过扫描require在deps文件中生成一条关于本文件
* 依赖关系的记录。合并程序也会扫描require来合并文件。
* @TODO 将来会配合后台在服务器端读取require来合并js文件。
* @param name{string} 依赖的模块名
*/
kampfer.require = function(name) {
if( !COMPILED ) {
if ( !name || kampfer.isProvided(name) ) {
return;
}
var path = kampfer._getPathFromDeps(name);
if (path) {
kampfer._included[path] = true;
kampfer._writeScripts();
}
}
};
/**
* 在kampfer上添加js文件依赖关系的记录。
* @param path{string} 文件的储存路径
* @param names{array} 文件定义的模块列表
* @param requires{array} 文件依赖的模块列表
*/
kampfer.addDependency = function( path, provides, requires ) {
if( !COMPILED ) {
var provide, require, deps;
path = path.replace(/\\/g, '/');
deps = kampfer._dependencies;
for( var i = 0; (provide = provides[i]); i++) {
deps.nameToPath[provide] = path;
if (!(path in deps.pathToNames)) {
deps.pathToNames[path] = {};
}
deps.pathToNames[path][provide] = true;
}
for( var j = 0; (require = requires[j]); j++) {
if (!(path in deps.requires)) {
deps.requires[path] = {};
}
deps.requires[path][require] = true;
}
}
};
if(!COMPILED) {
/**
* 通过模块名从kampfer保存的依赖性列表中获得真实文件路径
* @param name{string} 模块的名称
* @return {string} 模块的真实路径地址
* @private
*/
kampfer._getPathFromDeps = function(name) {
if( name in kampfer._dependencies.nameToPath ) {
return kampfer._dependencies.nameToPath[name];
} else {
return null;
}
};
/**
* 决定添加script标签方式默认使用document.write。
* 记录已经加载的js。
* @param src{string} js的完整路径
* @private
*/
kampfer._importScript = function(src) {
var _importScript = kampfer._writeScriptTag;
if(!kampfer._dependencies.written[src] && _importScript(src)) {
kampfer._dependencies.written[src] = true;
}
};
/**
* 对依赖关系进行拓扑排序决定js文件正确的输出顺序并异步的加载js文件
* 详细算法http://en.wikipedia.org/wiki/Topological_sorting
* @private
*/
kampfer._writeScripts = function() {
var scripts = [],
seenScript = {},
deps = kampfer._dependencies;
function visitNode(path) {
if( path in deps.written ) {
return;
}
// 如果已经访问过次节点
if( path in deps.visited ) {
if( !(path in seenScript) ) {
seenScript[path] = true;
scripts.push(path);
}
return;
}
deps.visited[path] = true;
if (path in deps.requires) {
for (var requireName in deps.requires[path]) {
// 如果依赖的模块已经注册(假设它已经被正确的加载),那么将不会再加载该模块。
if (!kampfer.isProvided(requireName)) {
if (requireName in deps.nameToPath) {
visitNode(deps.nameToPath[requireName]);
} else {
throw Error('Undefined nameToPath for ' + requireName ' in ' + path);
}
}
}
}
if (!(path in seenScript)) {
seenScript[path] = true;
scripts.push(path);
}
}
for( var path in kampfer._included ) {
if( !deps.written[path] ) {
visitNode(path);
}
}
for( var i = 0; i < scripts.length; i++ ) {
if ( scripts[i] ) {
kampfer._importScript( kampfer.basePath + scripts[i] );
} else {
throw Error('Undefined script input');
}
}
};
/**
* 使用document.write的方式输出script标签异步的引入js
* TODO 改用标准的DOM插入方法来添加script标签而不使用document.write方法
* @param src{string} js文件的url
* @return {boolean} 成功返回true失败返回false
* @private
*/
kampfer._writeScriptTag = function(src) {
var doc = kampfer.global.document;
doc.write('<script type="text/javascript" src="' + src + '"></' + 'script>');
return true;
};
kampfer._findBasePath = function() {
var doc = kampfer.global.document,
scripts = doc.getElementsByTagName('script');
for (var i = scripts.length - 1; i >= 0; --i) {
var src = scripts[i].src,
qmark = src.lastIndexOf('?'),
l = (qmark === -1 ? src.length : qmark);
if (src.substr(l - 7, 7) == 'base.js') {
kampfer.basePath = src.substr(0, l - 7);
return;
}
}
};
kampfer._dependencies = {
pathToNames: {}, // 1 to many
nameToPath: {}, // 1 to 1
requires: {}, // 1 to many
visited: {}, // 避免在拓扑排序时循环访问同一个节点。访问过的节点将保存在这里
written: {} // 记录已经被加载到页面的js文件名
};
kampfer._included = {};
kampfer._findBasePath();
kampfer._importScript( kampfer.basePath + 'deps.js' );
}
kampfer.isDef = function(val) {
return val !== undefined;
};
kampfer.isDefAndNotNull = function(val) {
return val != null;
};
var _toString = Object.prototype.toString;
kampfer.type = function(value) {
return value == null ?
String(value) :
_class2type[ _toString.call(value) ] || 'object';
};
kampfer.isArray = function(val) {
return kampfer.type(val) === 'array';
};
kampfer.isObject = function(val) {
return kampfer.type(val) === 'object';
};
kampfer.isEmptyObject = function(val) {
if( kampfer.type(val) !== 'object' ) {
return;
}
for( var name in val ) {
return false;
}
return true;
};
kampfer.isWindow = function(obj) {
if(obj === this.global) {
return true;
}
return false;
};
kampfer.each = function( array, fn, thisObj ) {
for( var i = 0, len = (array && array.length) || 0; i < len; ++i ) {
if( i in array ) {
fn.call( thisObj || kampfer.global, i, array[i], array );
}
}
};
kampfer.extend = function() {
var src, target, name, len, i, deep, copyFrom, copyTo, clone;
i = 1;
len = arguments.length;
deep = false;
target = arguments[0] || {};
if( typeof target === 'boolean' ) {
deep = target;
i = 2;
target = arguments[1] || {};
}
if( i === len ) {
target = this;
--i;
}
for( ; i < len; i++ ) {
src = arguments[i];
if( src !== null ) {
for( name in src ) {
copyFrom = src[name];
copyTo = target[name];
if( copyTo === copyFrom ) {
continue;
}
if( deep && copyFrom && ( kampfer.isArray(copyFrom) ||
kampfer.isObject(copyFrom) ) ) {
if( kampfer.isArray(copyFrom) ) {
clone = copyTo && kampfer.isArray(copyTo) ? copyTo : [];
} else if( kampfer.isObject(copyFrom) ) {
clone = copyTo && kampfer.isObject(copyTo) ? copyTo : {};
}
target[name] = kampfer.extend( deep, clone, copyFrom );
} else if( copyFrom !== undefined ) {
target[name] = copyFrom;
}
}
}
}
return target;
};
kampfer.emptyFn = function() {};
kampfer.now = function() {
return +new Date();
};
kampfer.expando = 'kampfer' + kampfer.now();
var _class2type = {};
kampfer.each( "Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
_class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
if( kampfer.type( kampfer.global.kampfer ) != 'undefined' ) {
kampfer._kampfer = kampfer.global.kampfer;
}
if( kampfer.type( kampfer.global.k ) != 'undefined' ) {
kampfer._k = kampfer.global.k;
}
kampfer.global.kampfer = kampfer.global.k = kampfer;
})();

View File

@@ -0,0 +1,31 @@
kampfer.provide('Class');
kampfer.Class = function() {};
kampfer.Class.initializing = false;
kampfer.Class.extend = function(props) {
var Class = function() {
if(!kampfer.Class.initializing && this.initializer) {
this.initializer.apply(this, arguments);
}
};
kampfer.Class.initializing = true;
// this === 构造函数。
//能否直接使用this.prototype考虑使用this.prototype。
var prototype = new this();
kampfer.Class.initializing = false;
prototype = kampfer.extend(prototype, props);
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.superClass = this.prototype;
Class.extend = kampfer.Class.extend;
return Class;
};

View File

@@ -0,0 +1,31 @@
kampfer.provide('Class');
kampfer.Class = function() {};
kampfer.Class.initializing = false;
kampfer.Class.extend = function(props) {
var Class = function() {
if(!kampfer.Class.initializing && this.initializer) {
this.initializer.apply(this, arguments);
}
};
kampfer.Class.initializing = true;
// this === 构造函数。
//能否直接使用this.prototype考虑使用this.prototype。
var prototype = new this();
kampfer.Class.initializing = false;
prototype = kampfer.extend(prototype, props);
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.superClass = this.prototype;
Class.extend = kampfer.Class.extend;
return Class;
};

View File

@@ -0,0 +1,198 @@
kampfer.require('events.EventTarget');
kampfer.provide('class.Composition');
kampfer.class.Composition = kampfer.events.EventTarget.extend({
_id : null,
_parent : null,
//array
//_children必须与_childrenIndex同步
//懒加载
_children : null,
//object
//_childrenIndex必须与_children同步
//懒加载
_childrenIndex : null,
//递归调用子节点的指定方法
//实现composition模式的关键方法之一
walk : function(method) {
var args = Array.prototype.slice.call(arguments, 1);
this.forEachChild(function(child, i) {
if( kampfer.type(child[method]) === 'function' ) {
child[method].apply(child, args);
}
});
},
getId : function() {
return this._id ||
( this._id = kampfer.Composition.generateUniqueId() );
},
setId : function(id) {
if(this._parent && this._parent._childrenIndex) {
delete this._parent._childrenIndex[this._id];
this._parent._childrenIndex[id] = this;
}
this._id = id;
},
getParent : function() {
return this._parent;
},
setParent : function(parent) {
//新的parent不为空时必须是component实例
if( parent && !(parent instanceof kampfer.UIComponent) ) {
return;
}
//新的parent不能是对象自己
if(parent === this) {
return;
}
//对象已经是另一个对象的child那么必须先调用removeChild之后再调用setParent
//对象不可能同时是另外两个对象的child
if( parent && this._parent && this._id &&
this._parent.getChild(this._id) && parent !== this._parent ) {
return;
}
this._parent = parent;
this.setParentEventTarget(parent);
//对象不是新parent的child那么将child添加到parnet的子列表中
//因为addchild方法会检查_parent属性所以必须在设置完_parent属性后才能执行添加操作
//closure没有这一步, 它的setParent方法只保证child的parent属性正确,
//但不保证child一定在parnet的子节点列表中
if( parent && !parent.getChild(this._id) ) {
parent.addChild(this);
}
},
addChild : function(child, render) {
this.addChildAt(child, this.getChildCount(), render);
},
addChildAt : function(child, index, render) {
if( !(child instanceof kampfer.UIComponent) ) {
return;
}
if(index < 0 || index > this.getChildCount() ) {
return;
}
if(!this._children || !this._childrenIndex) {
this._children = [];
this._childrenIndex = {};
}
if( child.getParent() === this ) {
//删除_children中保存的child引用
//避免_children中保存多个child引用
for(var i = 0, c; (c = this._children[i]); i++) {
if(c === child) {
this._children.splice(i, 1);
}
}
}
this._childrenIndex[child.getId()] = child;
this._children.splice(index, 0, child);
//closure没有这一步, 它的addChildAt方法只保证child在parent的子节点列表中,
//不保证child的parent一定是this. 这里我尝试增加这种确定性.
if(child._parent !== this) {
child.setParent(this);
}
},
getChild : function(id) {
if(id && this._childrenIndex) {
return this._childrenIndex[id];
}
},
getChildAt : function(index) {
if(this._children) {
return this._children[index];
}
},
removeChild : function(child) {
if(child) {
var id;
if( kampfer.type(child) === 'string' ) {
id = child;
child = this.getChild(id);
} else {
id = child.getId();
}
for(var i = 0, c; (c = this._children[i]); i++) {
if(c === child) {
this._children.splice(i, 1);
}
}
delete this._childrenIndex[id];
child.setParent(null);
}
return child;
},
removeChildAt : function(index) {
this.remochild( this.getChildAt(index) );
},
forEachChild : function(callback, context) {
if(!this._children) {
return;
}
for(var i = 0, child; (child = this._children[i]); i++) {
if( calllback.call(context || child, child, i) === false ) {
return;
}
}
},
indexOfChild : function(child) {
this.forEachChild(function(c, i) {
if(c === child) {
return i;
}
});
},
getChildCount : function() {
if(this._children) {
return this._children.length;
}
},
dispose : function() {
kampfer.Composition.superClass.dispose.call(this);
delete this._parent;
delete this._children;
delete this._childrenIndex;
}
});
kampfer.Composition.generateUniqueId = function() {
var guid = "";
for(var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
guid += n;
if((i == 8) || (i == 12) || (i == 16) || (i == 20)) {
guid += "-";
}
}
return guid;
};

View File

@@ -0,0 +1,94 @@
kampfer.require('class.UIComponent');
kampfer.require('dom');
kampfer.provide('Dialog');
kampfer.Dialog = kampfer.class.UIComponent.extend({
initializer : function() {},
createDom : function() {
kampfer.Dialog.superClass.createDom.call(this);
var element = this.getElement();
//header
this._headerElement = document.createElement('div');
//title
this._titleElement = document.createElement('h3');
//close
var closeButton = document.createElement('button');
//body
this._bodyElement = document.createElement('div');
//footer
this._footerElement = document.createElement('div');
this._headerElement.appendChild(closeButton);
this._headerElement.appendChild(this._titleElement);
element.appendChild(this._headerElement);
element.appendChild(this._bodyElement);
element.appendChild(this._footerElement);
kampfer.dom.addClass(this._element, 'modal');
kampfer.dom.addClass(this._headerElement, 'modal-header');
kampfer.dom.addClass(this._bodyElement, 'modal-body');
kampfer.dom.addClass(this._footerElement, 'modal-footer');
kampfer.dom.addClass(closeButton, 'close');
closeButton.innerHTML = 'x';
closeButton.setAttribute('data-action', 'close');
if(!this._buttons) {
this._footerElement.style.display = 'none';
} else {
for(var i = this._buttons.length - 1, buttonElment; (buttonElement = this._buttons[i]); i--) {
kampfer.dom.addClass(buttonElement, 'btn');
if(i === 0) {
kampfer.dom.addClass(buttonElement, 'btn-primary');
}
this._footerElement.appendChild(buttonElement);
}
}
},
setContent : function(html) {
this._bodyElement.innerHTML = html;
},
getContent : function(html) {
return this._bodyElement.innerHTML;
},
setTitle : function(title) {
this._titleElement.innerHTML = title;
},
//modal居中.但是bootstrap貌似直接定死了modal的宽度然后用样式居中.
reposition : function() {
var winWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth),
winHeight = Math.max(document.documentElement.offsetHeight, document.body.offsetHeight);
this._element.style.left = kampfer.dom.scrollLeft(window) + winWidth / 2 -
this._element.offsetWidth / 2 + 'px';
this._element.style.top = kampfer.dom.scrollTop(window) + winHeight / 2 -
this._element.offsetHeight / 2 + 'px';
},
show : function() {
if(!this._element) {
this.render();
}
this._element.style.display = '';
},
hide : function() {
this._element.style.display = 'none';
},
dispose : function() {
kampfer.Dialog.superClass.dispose.call(this);
delete this._titleElement;
delete this._headerElement;
delete this._bodyElement;
delete this._buttons;
delete this._footerElement;
}
});

View File

@@ -0,0 +1,43 @@
kampfer.require('events');
kampfer.require('Class');
kampfer.provide('events.EventTarget');
/*
* 所有需要实现自定义事件的类都必须继承EventTarget类。
*/
kampfer.events.EventTarget = kampfer.Class.extend({
_parentNode : null,
addListener : function(type, listener, context) {
k.events.addListener(this, type, listener, context);
},
removeListener : function(type, listener) {
k.events.removeListener(this, type, listener);
},
dispatch : function(type) {
if(type) {
var args = Array.prototype.slice.apply(arguments);
args.unshift(this);
k.events.dispatch.apply(null, args);
}
},
getParentEventTarget : function() {
return this._parentNode;
},
setParentEventTarget : function(obj) {
this._parentNode = obj;
},
dispose : function() {
this._parentNode = null;
k.events.removeListener(this);
}
});

View File

@@ -0,0 +1,150 @@
kampfer.require('class.Composition');
kampfer.require('events');
kampfer.provide('class.UIComponent');
kampfer.class.UIComponent = kampfer.class.Composition.extend({
_element : null,
_inDocument : false,
/**
* @type {object}
*/
events : null,
isInDocument : function() {
return this._inDocument;
},
setElement : function() {
this._element = element;
},
getElement : function() {
return this._element;
},
createDom : function() {
this._element = document.createElement('div');
return this._element;
},
//component有两种初始化的方式:
//1.动态生成
//2.传入已有dom,component解析
//decorate方法就是针对第二种方式处理解析和预处理逻辑
decorate : function(element) {},
enterDocument : function() {
this._inDocument = true;
var that = this;
if(this.events) {
for(var attr in this.events) {
kampfer.events.addListener(this._element, attr, this._transition, this);
}
}
this.walk('enterDocument');
},
_transition : function(event) {
var element = event.target,
handlers = this.events[event.type],
action = element.getAttribute('data-action');
while( !action && (element = element.parentNode) ) {
if(element.getAttribute) {
action = element.getAttribute('data-action');
}
}
if( !action || !handlers || !(action in handlers) ) {
return;
}
event.target = element;
if(typeof handlers[action] === 'string') {
handlers = handlers[action].split(' ');
for(var i = 0, handle; (handle = handlers[i]); i++) {
if( this[handle] && this[handle](event) === false ) {
return false;
}
}
} else if(typeof handlers[action] === 'function') {
handlers[action].call(this, event);
}
},
exitDocument : function() {
this._inDocument = true;
kampfer.events.removeListener(this._element);
this.walk('exitDocument');
},
render : function(parentElement, beforeNode) {
if(this._inDocument) {
return;
}
if(!this._element) {
this.createDom();
}
if(parentElement) {
parentElement.insertBefore(this._element, beforeNode || null);
} else {
document.body.appendChild(this._element);
}
//父component存在,但是它不在document中,那么子component不进入document
if( !this._parent || this._parent.isInDocument() ) {
this.enterDocument();
}
},
addChild : function(child, render) {
this.addChildAt(child, this.getChildCount(), render);
},
addChildAt : function(child, index, render) {
kampfer.UIComponent.superClass.addChildAt.call(this, child, index);
if( child._inDocument && this._inDocument && child.getParent() === this ) {
var parentElement = this.getElement();
parentElement.insertBefore( child.getElement(),
(parentElement.childNodes[index] || null) );
} else if(render) {
if (!this._element) {
this.createDom();
}
var sibling = this.getChildAt(index + 1);
child.render_(this.getElement(), sibling ? sibling._element : null);
}
},
removeChild : function(child, unrender) {
kampfer.UIComponent.superClass.removeChild.call(this, child);
if(unrender) {
child.exitDocument();
if( child._element ) {
child._element.parentNode.removeChild(child._element);
}
}
},
removeChildAt : function(index, unrender) {
this.remochild( this.getChildAt(index), unrender );
},
dispose : function() {
kampfer.UIComponent.superClass.dispose.call(this);
this.exitDocument();
delete this._element;
}
});

View File

@@ -0,0 +1,255 @@
/*global kampfer*/
/**
* 为对象管理数据
* @module data
* https://github.com/jquery/jquery/blob/master/src/data.js
*/
kampfer.require('browser.support');
kampfer.provide('data');
//kampfer的数据缓存
kampfer.data.cache = {};
//用于标记缓存的id
kampfer.data.cacheId = 0;
//不能设置自定义属性的HTML tag名单
kampfer.data.noData = {
"embed": true,
//object标签的clsid为以下值时可以设置自定义属性,
//其他情况object也不能设置自定义属性
"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
"applet": true
};
/*
* 判断对象是否能够设置自定义属性。所有plain object都能设置自定义属性
* 而html dom中embed/applet无法设置obeject只有当clsid为特定值时可以设置。
* @param {object||html dom}elem
* @return {boolean}
*/
kampfer.data.acceptData = function(elem) {
if(kampfer.type(elem) === 'object') {
if(elem.nodeName) {
var match = kampfer.data.noData[ elem.nodeName.toLowerCase() ];
if( match ) {
return !(match === true || elem.getAttribute('classid') !== match);
}
}
return true;
}
};
/*
* 判断数据对象是否为空。必须区分两种情况:
* 1。用户的数据对象 所有用户的数据都储存在数据对象的data属性中。
* 2。kampfer的数据对象 kampfer的数据会被直接储存在数据对象中。
* @param {plain object}obj 这个对象一般取自kampfer.data.cache[expando]
* 或者elem[expando]
* @return {boolean}
*/
kampfer.data.isEmptyDataObj = function(obj) {
for(var name in obj) {
//检查用户定义的data即cache.data
if( name === 'data' && kampfer.isEmptyObject(obj[name]) ) {
continue;
}
if( name !== 'toJSON' ) {
return false;
}
}
return true;
};
//判断对象是否储存了数据。此方法先取到elem的数据对象
//再调用kampfer.data.isEmptyDataObj判断对象是否为空
kampfer.data.hasData = function(elem) {
elem = elem.nodeType ?
kampfer.data.cache[ elem[kampfer.expando] ] :
elem[kampfer.expando];
return !!elem && !kampfer.data.isEmptyDataObj(elem);
};
/*
* 写缓存. 只接受key-value形式的参数.
* @param {object||html dom}elem
* @param {string}name
* @param {*}value
* @param {boolean}internal
* @return
*/
kampfer.data.setData = function(elem, name, value, internal) {
if( !kampfer.data.acceptData(elem) ) {
return;
}
var expando = kampfer.expando,
isNode = !!elem.nodeType,
cache = isNode ? kampfer.data.cache : elem,
cacheId = isNode ? elem[expando] : elem[expando] && expando,
thisCache;
// 设置cacheId
if(!cacheId) {
if(isNode) {
elem[expando] = cacheId = ++kampfer.data.cacheId;
} else {
cacheId = expando;
}
}
// 取得cache object
if(!cache[cacheId]) {
cache[cacheId] = {};
}
thisCache = cache[cacheId];
// 区分内部调用和客户调用时数据的储存位置
if(!internal) {
if(!thisCache.data) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
// 不做判断,直接覆盖旧值
if(kampfer.type(name) === 'object') {
thisCache = kampfer.extend(thisCache, name);
} else if(value !== undefined) {
thisCache[name] = value;
}
return thisCache;
};
/*
* 读缓存。如果不提供name,直接返回整个cache。
* @param {object||html dom}elem
* @param {string}name option
* @param {boolean}internal option
* @return {*}
*/
kampfer.data.getData = function(elem, name, internal) {
if( !kampfer.data.acceptData(elem) ) {
return;
}
var expando = kampfer.expando,
isNode = !!elem.nodeType,
cache = isNode ? kampfer.data.cache : elem,
cacheId = isNode ? elem[expando] : elem[expando] && expando,
hasName = kampfer.type(name) !== 'boolean' && name !== undefined,
thisCache, ret;
if(!cacheId || !cache[cacheId]) {
return;
}
if(!hasName) {
internal = name;
}
thisCache = cache[cacheId];
if(!internal) {
thisCache = thisCache.data || {};
}
if(hasName) {
ret = thisCache[name];
} else {
ret = thisCache;
}
return ret;
};
/*
* 删除缓存。如果不提供name,不执行任何操作。
* @param {object||html dom}elem
* @param {string}name
* @param {boolean}internal option
* @return void
*/
kampfer.data.removeData = function(elem, name, internal) {
if( !kampfer.data.acceptData(elem) ) {
return;
}
var expando = kampfer.expando,
isNode = !!elem.nodeType,
cache = isNode ? kampfer.data.cache : elem,
cacheId = isNode ? elem[expando] : elem[expando] && expando,
hasName = kampfer.type(name) !== 'bool' && name !== undefined,
thisCache;
if(!cacheId || !cache[cacheId] ||!hasName) {
return;
}
thisCache = cache[cacheId];
if(!internal) {
thisCache = thisCache.data;
}
if(thisCache) {
if(kampfer.type(name) !== 'array') {
if(name in thisCache) {
name = [name];
}
}
for(var i = 0, n; n = name[i]; i++) {
delete thisCache[n];
}
if( !kampfer.data.isEmptyDataObj(thisCache) ) {
return;
}
}
if(!internal) {
delete cache[cacheId].data;
if( !kampfer.data.isEmptyDataObj( cache[cacheId] ) ) {
return;
}
}
// 清空数据cache
// as window.nodeType === undefined, so when elem === window isNode === false
if ( kampfer.browser.support.deleteExpando || !cache.setInterval ) {
delete cache[cacheId];
} else {
cache[cacheId] = null;
}
// 清除html dom的expando
if(isNode) {
// IE does not allow us to delete expando properties from nodes,
// nor does it have a removeAttribute function on Document nodes;
// we must handle all of these cases
if ( kampfer.browser.support.deleteExpando ) {
delete elem[ expando ];
} else if ( elem.removeAttribute ) {
elem.removeAttribute( expando );
} else {
elem[ expando ] = null;
}
}
};
//kampfer内部调用
kampfer.data.setDataInternal = function(elem, name, value) {
kampfer.data.setData(elem, name, value, true);
};
//kampfer内部调用
kampfer.data.getDataInternal = function(elem, name) {
return kampfer.data.getData(elem, name, true);
};
//kampfer内部调用
kampfer.data.removeDataInternal = function(elem, name) {
kampfer.data.removeData(elem, name, true);
};

View File

@@ -0,0 +1,7 @@
kampfer.addDependency('ajax.js', ['ajax'], []);
kampfer.addDependency('base.js', [], []);
kampfer.addDependency('class.js', ['Class'], []);
kampfer.addDependency('data.js', ['data'], ['browser.support']);
kampfer.addDependency('events.js', ['events','events.Event','events.Listener'], ['data']);
kampfer.addDependency('eventtarget.js', ['events.EventTarget'], ['events','Class']);
kampfer.addDependency('support.js', ['browser.support'], []);

View File

@@ -0,0 +1,165 @@
/*global kampfer*/
kampfer.provide('dom');
kampfer.dom.create = function(name) {
return kampfer.global.document.createElement(name);
};
kampfer.dom.addClass = function(elem, value) {
var classNames, i, l,
setClass, c, cl;
if ( value && typeof value === "string" ) {
classNames = value.split( /\s+/ );
if ( elem.nodeType === 1 ) {
if ( !elem.className && classNames.length === 1 ) {
elem.className = value;
} else {
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
setClass += classNames[ c ] + " ";
}
}
elem.className = setClass.trim();
}
}
}
};
kampfer.dom.removeClass = function(elem, value) {
var classNames, i, l, className, c, cl;
if ( (value && typeof value === "string") || value === undefined ) {
classNames = ( value || "" ).split( /\s+/ );
if ( elem.nodeType === 1 && elem.className ) {
if ( value ) {
className = (" " + elem.className + " ").replace( /[\n\t\r]/g, " " );
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
className = className.replace(" " + classNames[ c ] + " ", " ");
}
//elem.className = kampfer.string.trim( className );
elem.className = className.trim();
} else {
elem.className = "";
}
}
}
};
kampfer.dom.getComputedStyle = function(element, property) {
var doc = kampfer.global.document;
if(doc.defaultView && doc.defaultView.getComputedStyle) {
var styles = doc.defaultView.getComputedStyle(element, null);
if(styles) {
// element.style[..] is undefined for browser specific styles
// as 'filter'.
return styles[property] || styles.getPropertyValue(property);
}
}
return '';
};
//for IE
kampfer.dom.getCascadedStyle = function(element, style) {
return element.currentStyle ? element.currentStyle[style] : null;
};
kampfer.dom.getStyle = function(element, style) {
return kampfer.dom.getComputedStyle(element, style) ||
kampfer.dom.getCascadedStyle(element, style) ||
element.style[style];
};
//需要输入正确的javascript格式名
//TODO 处理样式名
kampfer.dom.setStyle = function(element, name, value) {
if( kampfer.isDefAndNotNull(value) &&
kampfer.type(name) === 'string' ) {
element.style[name] = value;
} else if( kampfer.isObject(name) ) {
for(var attr in name) {
kampfer.dom.setStyle(element, attr, name[attr]);
}
}
};
// http://code.jquery.com/jquery-1.8.3.js
kampfer.dom.getWindow = function(elem) {
return kampfer.isWindow(elem) ?
elem :
elem.nodeType === 9 ?
elem.defaultView || elem.parentWindow :
false;
};
// http://code.jquery.com/jquery-1.8.3.js
kampfer.dom.scrollLeft = function(elem, val) {
var win = kampfer.dom.getWindow( elem ),
prop = 'pageXOffset',
method = 'scrollLeft';
if ( val === undefined ) {
return win ? (prop in win) ? win[ prop ] :
win.document.documentElement[ method ] :
elem[ method ];
}
if ( win ) {
win.scrollTo( val, kampfer.dom.scrollTop( win ));
} else {
elem[ method ] = val;
}
};
// http://code.jquery.com/jquery-1.8.3.js
kampfer.dom.scrollTop = function(elem, val) {
var win = kampfer.dom.getWindow( elem ),
prop = 'pageYOffset',
method = 'scrollTop';
if ( val === undefined ) {
return win ? (prop in win) ? win[ prop ] :
win.document.documentElement[ method ] :
elem[ method ];
}
if ( win ) {
win.scrollTo( kampfer.dom.scrollLeft( win ), val);
} else {
elem[ method ] = val;
}
};
//http://www.cnblogs.com/rubylouvre/archive/2011/05/30/1583523.html
kampfer.dom.contains = function(parent, child) {
if(parent.compareDocumentPosition) {
return parent === child || !!(parent.compareDocumentPosition(child) & 16);
}
if(parent.contains && child.nodeType === 1) {
return parent.contains(child) && parent !== child;
}
while( (child = child.parentNode) ) {
if(child === parent) {
return true;
}
}
return false;
};

View File

@@ -0,0 +1,468 @@
/*global kampfer*/
kampfer.require('data');
kampfer.provide('events');
kampfer.provide('events.Event');
kampfer.provide('events.Listener');
/*
* 包裹浏览器event对象提供统一的、跨浏览器的接口。
* 新的对象将包含以下接口:
* - type {string} 事件种类
* - target {object} 触发事件的对象
* - relatedTarget {object} 鼠标事件mouseover和mouseout的修正
* - currentTarget {object}
* - stopPropagation {function} 阻止冒泡
* - preventDefault {function} 阻止默认行为
* - dispose {function}
* - which {number}
* - pageX/pageY {number}
*/
kampfer.events.Event = function(src, props) {
var srcType = kampfer.type(src);
if(srcType === 'object' && src.type) {
this.src = src;
this.type = src.type;
} else if(srcType === 'string') {
this.type = src;
}
if(kampfer.type(props) === 'object') {
kampfer.extend(this, props);
}
this.isImmediatePropagationStopped = false;
this.propagationStopped = false;
this.isDefaultPrevented = false;
this[kampfer.expando] = true;
};
kampfer.events.Event.prototype = {
constructor : kampfer.events.Event,
//停止冒泡
stopPropagation : function() {
//触发事件时需要读取propagationStopped判断冒泡是否取消。
this.propagationStopped = true;
var e = this.src;
if(!e) {
return;
}
if(e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
},
//立即停止冒泡
stopImmediatePropagation : function() {
this.isImmediatePropagationStopped = true;
this.stopPropagation();
},
//阻止默认行为
preventDefault : function() {
this.isDefaultPrevented = true;
var e = this.src;
if(!e) {
return;
}
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
dispose : function() {
delete this.src;
}
};
//所有事件对象都拥有下面的属性
kampfer.events.Event.props = 'altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which'.split(' ');
//键盘事件对象拥有下面的属性
kampfer.events.Event.keyProps = 'char charCode key keyCode'.split(' ');
//鼠标事件对象拥有下面的属性
kampfer.events.Event.mouseProps = 'button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' ');
/*
* 修复event,处理兼容性问题
* @param {object||string}event
* @return {object} 修复的event对象
*/
kampfer.events.fixEvent = function(event) {
if( event[kampfer.expando] ) {
return event;
}
var oriEvent = event;
event = new kampfer.events.Event(oriEvent);
kampfer.each(kampfer.events.Event.props, function(i, prop) {
event[prop] = oriEvent[prop];
});
if(!event.target) {
event.target = oriEvent.srcElement || document;
}
// Target should not be a text node (jQuery bugs#504, Safari)
if(event.target.nodeType === 3) {
event.target = event.target.parentNode;
}
event.currentTarget = null;
// ie不支持metaKey, 设置值为false
event.metaKey = !!event.metaKey;
//修复鼠标事件之前必须保证event.target存在
if( kampfer.events.isKeyEvent(event.type) ) {
kampfer.events.fixKeyEvent(event, oriEvent);
} else {
kampfer.events.fixMouseEvent(event, oriEvent);
}
return event;
};
//判断事件是否为键盘事件
kampfer.events.isKeyEvent = function(type) {
return /^key/.test(type);
};
//判断事件是否为鼠标事件
kampfer.events.isMouseEvent = function(type) {
return /^(?:mouse|contextmenu)|click/.test(type);
};
//修复鼠标键盘对象
kampfer.events.fixKeyEvent = function(event, oriEvent) {
kampfer.each(kampfer.events.Event.keyProps, function(i, prop) {
event[prop] = oriEvent[prop];
});
// Add which for key events
if ( event.which == null ) {
event.which = oriEvent.charCode != null ? oriEvent.charCode : oriEvent.keyCode;
}
return event;
};
//修复鼠标事件对象
kampfer.events.fixMouseEvent = function(event, oriEvent) {
kampfer.each(kampfer.events.Event.mouseProps, function(i, prop) {
event[prop] = oriEvent[prop];
});
var eventDoc, doc, body,
button = oriEvent.button,
fromElement = oriEvent.fromElement;
// Calculate pageX/Y if missing and clientX/Y available
if ( event.pageX == null && oriEvent.clientX != null ) {
eventDoc = event.target.ownerDocument || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = oriEvent.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
( doc && doc.clientLeft || body && body.clientLeft || 0 );
event.pageY = oriEvent.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
( doc && doc.clientTop || body && body.clientTop || 0 );
}
// Add relatedTarget, if necessary
if ( !event.relatedTarget && fromElement ) {
event.relatedTarget = fromElement === event.target ? oriEvent.toElement : fromElement;
}
// Add which for click: 1 === left; 2 === middle; 3 === right
// Note: button is not normalized, so don't use it
if ( !event.which && button !== undefined ) {
event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
}
return event;
};
/*
* 生成handler的一个包裹对象记录一些额外信息并且生成一个唯一的key值
* @param {function}handler
* @param {string}type
* @param {object}scope
*/
kampfer.events.Listener = function(listener, eventType, context) {
this.listener = listener;
this.eventType = eventType;
this.context = context;
this.key = kampfer.events.Listener.key++;
};
//销毁对象中指向其他对象的引用
kampfer.events.Listener.prototype.dispose = function() {
this.listener = null;
this.context = null;
};
kampfer.events.Listener.key = 0;
/*
* 添加事件
* @param {object}elem
* @param {string||array}eventType
* @param {function}listener
* @param {object}context
*/
kampfer.events.addListener = function(elem, eventType, listener, context) {
// filter commet and text node
// nor undefined eventType or listener
if( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !eventType ||
kampfer.type(listener) !== 'function' ) {
return;
}
var type = kampfer.type(eventType);
if( type === 'array' ) {
for(var i = 0, e; e = eventType[i]; i++) {
kampfer.events.addListener(elem, e, listener, context);
}
return;
}
if( type === 'string') {
var listenerObj = new kampfer.events.Listener(listener, eventType, context || elem);
var events = kampfer.data.getDataInternal(elem, 'events');
if(!events) {
events = {};
kampfer.data.setDataInternal(elem, 'events', events);
}
if(!events.proxy) {
events.proxy = function(e) {
if(kampfer.events.triggered !== e.type) {
return kampfer.events.dispatchEvent.apply(events.proxy.elem, arguments);
}
};
events.proxy.elem = elem;
}
if(!events.listeners) {
events.listeners = {};
}
if(!events.listeners[eventType]) {
events.listeners[eventType] = [];
//events.listeners[eventType]不存在说明没有绑定过此事件
if(elem.addEventListener) {
elem.addEventListener(eventType, events.proxy, false);
} else if(elem.attachEvent) {
elem.attachEvent('on' + eventType, events.proxy);
}
}
events.listeners[eventType].push(listenerObj);
}
// fix ie memory leak
elem = null;
};
/*
* 删除事件。此方法用于删除绑定在某类事件下的全部操作。
* @param {object}elem
* @param {string}eventType
*/
kampfer.events.removeListener = function(elem, eventType, listener) {
var events = kampfer.data.getDataInternal(elem, 'events');
if( !events || !events.listeners ) {
return;
}
var type = kampfer.type(eventType);
if(type === 'array') {
for(var i = 0; type = eventType[0]; i++) {
kampfer.events.removeListener(elem, type, listener);
}
return;
}
if(type === 'undefined') {
for(type in events.listeners) {
kampfer.events.removeListener(elem, type, listener);
}
return;
}
if(type === 'string') {
for(var i = 0, l; l = events.listeners[eventType][i]; i++) {
if( !listener || (l.eventType === eventType && l.listener === listener) ) {
// 注意splice会改变数组长度以及元素对应的下标
events.listeners[eventType].splice(i--, 1);
}
}
if(!events.listeners[eventType].length) {
if(elem.removeEventListener) {
elem.removeEventListener(eventType, events.proxy, false);
} else if(elem.detachEvent) {
elem.detachEvent('on' + eventType, events.proxy);
}
delete events.listeners[eventType];
}
if( kampfer.isEmptyObject(events.listeners) ) {
delete events.listeners;
delete events.proxy;
kampfer.data.removeDataInternal(elem, 'events');
}
}
};
/*
* 触发对象的指定事件
* @param {object}elem
* @param {string||array}eventType
*/
kampfer.events.dispatch = function(elem, event) {
if(elem.nodeType === 3 || elem.nodeType === 8 || !event) {
return;
}
var eventType = event.type || event,
args = Array.prototype.slice.call(arguments),
bubblePath = [],
onType = 'on' + eventType;
if(typeof event === 'object') {
if( !event[kampfer.expando] ) {
event = new kampfer.events.Event(eventType, event);
}
} else {
event = new kampfer.events.Event(event);
}
args = Array.prototype.slice.call(arguments, 2);
args.unshift(event);
// event.target始终指向事件的起点对象
if(!event.target) {
event.target = elem;
}
//建立冒泡的dom树路径
for(var cur = elem; cur; cur = cur.parentNode) {
bubblePath.push(cur);
}
//W3C标准中事件冒泡的终点时document,而jQuery.trigger会冒泡到window
//这里有必要跟jQuery一样吗
//冒泡的最后一站始终是window对象
if( cur === (elem.ownerDocument || document) ) {
bubblePath.push(elem.defaultView || elem.parentWindow || window);
}
for(i = 0; cur = !event.propagationStopped && bubblePath[i]; i++) {
var eventsObj = kampfer.data.getDataInternal(cur, 'events');
if( !eventsObj || !eventsObj.listeners[eventType] ) {
continue;
}
// 冒泡的每一阶段currentTarget都不同
event.currentTarget = cur;
// 执行kampfer绑定的事件处理函数
var proxy = eventsObj.proxy;
proxy.apply(cur, args);
// 执行使用行内方式绑定的事件处理函数
proxy = cur[onType];
if(proxy && proxy.apply(cur, args) === false) {
event.preventDefault();
event.stopPropagation();
}
}
// 触发浏览器default action
if(!event.isDefaultPrevented && !kampfer.isWindow(elem) && elem[eventType]) {
var old = elem[onType];
if(old) {
elem[onType] = null;
}
kampfer.events.triggered = eventType;
try {
elem[eventType]();
} catch(e) {}
delete kampfer.events.triggered;
if(old) {
elem[onType] = old;
}
}
return event.result;
};
/**
* 正确的将一个事件派发给所有相关对象
*/
kampfer.events.dispatchEvent = function(event) {
event = kampfer.events.fixEvent(event);
// ie6/7/8不支持event.currentTarget 于是无法使用解决this的问题
var eventsObj = kampfer.data.getDataInternal(this, 'events'),
listeners = eventsObj && eventsObj.listeners[event.type],
args = Array.prototype.slice.call(arguments);
if(!listeners) {
return;
}
// fix currentTarget in ie6/7/8
event.currentTarget = this;
for(var i = 0, l; l = listeners[i]; i++) {
event.result = l.listener.apply(l.context, args);
if(event.result === false) {
event.preventDefault();
event.stopPropagation();
}
if(event.isImmediatePropagationStopped) {
break;
}
}
// for beforeunload on firefox
if(event.result !== undefined && event.src) {
event.src.returnValue = event.result;
}
return event.result;
};

View File

@@ -0,0 +1,43 @@
kampfer.require('events');
kampfer.require('Class');
kampfer.provide('events.EventTarget');
/*
* 所有需要实现自定义事件的类都必须继承EventTarget类。
*/
kampfer.events.EventTarget = kampfer.Class.extend({
parentNode : null,
addListener : function(type, listener, context) {
k.events.addListener(this, type, listener, context);
},
removeListener : function(type, listener) {
k.events.removeListener(this, type, listener);
},
dispatch : function(type) {
if(type) {
var args = Array.prototype.slice.apply(arguments);
args.unshift(this);
k.events.dispatch.apply(null, args);
}
},
getParentEventTarget : function() {
return this.parentNode;
},
setParentEventTarget : function(obj) {
this.parentNode = obj;
},
dispose : function() {
this.parentNode = null;
k.events.removeListener(this);
}
});

View File

@@ -0,0 +1,981 @@
// Copyright 2009-2012 by contributors, MIT License
// vim: ts=4 sts=4 sw=4 expandtab
// Module systems magic dance
(function (definition) {
// RequireJS
if (typeof define == "function") {
define(definition);
// YUI3
} else if (typeof YUI == "function") {
YUI.add("es5", definition);
// CommonJS and <script>
} else {
definition();
}
})(function () {
/**
* Brings an environment as close to ECMAScript 5 compliance
* as is possible with the facilities of erstwhile engines.
*
* Annotated ES5: http://es5.github.com/ (specific links below)
* ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
* Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
*/
//
// Function
// ========
//
// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5
function Empty() {}
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) { // .length is 1
// 1. Let Target be the this value.
var target = this;
// 2. If IsCallable(Target) is false, throw a TypeError exception.
if (typeof target != "function") {
throw new TypeError("Function.prototype.bind called on incompatible " + target);
}
// 3. Let A be a new (possibly empty) internal list of all of the
// argument values provided after thisArg (arg1, arg2 etc), in order.
// XXX slicedArgs will stand in for "A" if used
var args = slice.call(arguments, 1); // for normal call
// 4. Let F be a new native ECMAScript object.
// 11. Set the [[Prototype]] internal property of F to the standard
// built-in Function prototype object as specified in 15.3.3.1.
// 12. Set the [[Call]] internal property of F as described in
// 15.3.4.5.1.
// 13. Set the [[Construct]] internal property of F as described in
// 15.3.4.5.2.
// 14. Set the [[HasInstance]] internal property of F as described in
// 15.3.4.5.3.
var bound = function () {
if (this instanceof bound) {
// 15.3.4.5.2 [[Construct]]
// When the [[Construct]] internal method of a function object,
// F that was created using the bind function is called with a
// list of arguments ExtraArgs, the following steps are taken:
// 1. Let target be the value of F's [[TargetFunction]]
// internal property.
// 2. If target has no [[Construct]] internal method, a
// TypeError exception is thrown.
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Construct]] internal
// method of target providing args as the arguments.
var result = target.apply(
this,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
// 15.3.4.5.1 [[Call]]
// When the [[Call]] internal method of a function object, F,
// which was created using the bind function is called with a
// this value and a list of arguments ExtraArgs, the following
// steps are taken:
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 2. Let boundThis be the value of F's [[BoundThis]] internal
// property.
// 3. Let target be the value of F's [[TargetFunction]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Call]] internal method
// of target providing boundThis as the this value and
// providing args as the arguments.
// equiv: target.call(this, ...boundArgs, ...args)
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
if(target.prototype) {
Empty.prototype = target.prototype;
bound.prototype = new Empty();
// Clean up dangling references.
Empty.prototype = null;
}
// XXX bound.length is never writable, so don't even try
//
// 15. If the [[Class]] internal property of Target is "Function", then
// a. Let L be the length property of Target minus the length of A.
// b. Set the length own property of F to either 0 or L, whichever is
// larger.
// 16. Else set the length own property of F to 0.
// 17. Set the attributes of the length own property of F to the values
// specified in 15.3.5.1.
// TODO
// 18. Set the [[Extensible]] internal property of F to true.
// TODO
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
// 20. Call the [[DefineOwnProperty]] internal method of F with
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
// false.
// 21. Call the [[DefineOwnProperty]] internal method of F with
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
// and false.
// TODO
// NOTE Function objects created using Function.prototype.bind do not
// have a prototype property or the [[Code]], [[FormalParameters]], and
// [[Scope]] internal properties.
// XXX can't delete prototype in pure-js.
// 22. Return F.
return bound;
};
}
// Shortcut to an often accessed properties, in order to avoid multiple
// dereference that costs universally.
// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
// us it in defining shortcuts.
var call = Function.prototype.call;
var prototypeOfArray = Array.prototype;
var prototypeOfObject = Object.prototype;
var slice = prototypeOfArray.slice;
// Having a toString local variable name breaks in Opera so use _toString.
var _toString = call.bind(prototypeOfObject.toString);
var owns = call.bind(prototypeOfObject.hasOwnProperty);
// If JS engine supports accessors creating shortcuts.
var defineGetter;
var defineSetter;
var lookupGetter;
var lookupSetter;
var supportsAccessors;
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
defineGetter = call.bind(prototypeOfObject.__defineGetter__);
defineSetter = call.bind(prototypeOfObject.__defineSetter__);
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
}
//
// Array
// =====
//
// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.12
// Default value for second param
// [bugfix, ielt9, old browsers]
// IE < 9 bug: [1,2].splice(0).join("") == "" but should be "12"
if ([1,2].splice(0).length != 2) {
var array_splice = Array.prototype.splice;
Array.prototype.splice = function(start, deleteCount) {
if (!arguments.length) {
return [];
} else {
return array_splice.apply(this, [
start === void 0 ? 0 : start,
deleteCount === void 0 ? (this.length - start) : deleteCount
].concat(slice.call(arguments, 2)))
}
};
}
// ES5 15.4.4.12
// http://es5.github.com/#x15.4.4.13
// Return len+argCount.
// [bugfix, ielt8]
// IE < 8 bug: [].unshift(0) == undefined but should be "1"
if ([].unshift(0) != 1) {
var array_unshift = Array.prototype.unshift;
Array.prototype.unshift = function() {
array_unshift.apply(this, arguments);
return this.length;
};
}
// ES5 15.4.3.2
// http://es5.github.com/#x15.4.3.2
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray) {
Array.isArray = function isArray(obj) {
return _toString(obj) == "[object Array]";
};
}
// The IsCallable() check in the Array functions
// has been replaced with a strict check on the
// internal class of the object to trap cases where
// the provided function was actually a regular
// expression literal, which in V8 and
// JavaScriptCore is a typeof "function". Only in
// V8 are regular expression literals permitted as
// reduce parameters, so it is desirable in the
// general case for the shim to match the more
// strict and common behavior of rejecting regular
// expressions.
// ES5 15.4.4.18
// http://es5.github.com/#x15.4.4.18
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
// Check failure of by-index access of string characters (IE < 9)
// and failure of `0 in boxedString` (Rhino)
var boxedString = Object("a"),
splitString = boxedString[0] != "a" || !(0 in boxedString);
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(fun /*, thisp*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
thisp = arguments[1],
i = -1,
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
while (++i < length) {
if (i in self) {
// Invoke the callback function with call, passing arguments:
// context, property value, property key, thisArg object
// context
fun.call(thisp, self[i], i, object);
}
}
};
}
// ES5 15.4.4.19
// http://es5.github.com/#x15.4.4.19
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
if (!Array.prototype.map) {
Array.prototype.map = function map(fun /*, thisp*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
result = Array(length),
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self)
result[i] = fun.call(thisp, self[i], i, object);
}
return result;
};
}
// ES5 15.4.4.20
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
if (!Array.prototype.filter) {
Array.prototype.filter = function filter(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
result = [],
value,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self) {
value = self[i];
if (fun.call(thisp, value, i, object)) {
result.push(value);
}
}
}
return result;
};
}
// ES5 15.4.4.16
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
if (!Array.prototype.every) {
Array.prototype.every = function every(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && !fun.call(thisp, self[i], i, object)) {
return false;
}
}
return true;
};
}
// ES5 15.4.4.17
// http://es5.github.com/#x15.4.4.17
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
if (!Array.prototype.some) {
Array.prototype.some = function some(fun /*, thisp */) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && fun.call(thisp, self[i], i, object)) {
return true;
}
}
return false;
};
}
// ES5 15.4.4.21
// http://es5.github.com/#x15.4.4.21
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(fun /*, initial*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
// no value to return if no initial value and an empty array
if (!length && arguments.length == 1) {
throw new TypeError("reduce of empty array with no initial value");
}
var i = 0;
var result;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i++];
break;
}
// if array contains no values, no initial value to return
if (++i >= length) {
throw new TypeError("reduce of empty array with no initial value");
}
} while (true);
}
for (; i < length; i++) {
if (i in self) {
result = fun.call(void 0, result, self[i], i, object);
}
}
return result;
};
}
// ES5 15.4.4.22
// http://es5.github.com/#x15.4.4.22
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
var object = toObject(this),
self = splitString && _toString(this) == "[object String]" ?
this.split("") :
object,
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
// no value to return if no initial value, empty array
if (!length && arguments.length == 1) {
throw new TypeError("reduceRight of empty array with no initial value");
}
var result, i = length - 1;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i--];
break;
}
// if array contains no values, no initial value to return
if (--i < 0) {
throw new TypeError("reduceRight of empty array with no initial value");
}
} while (true);
}
do {
if (i in this) {
result = fun.call(void 0, result, self[i], i, object);
}
} while (i--);
return result;
};
}
// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
var self = splitString && _toString(this) == "[object String]" ?
this.split("") :
toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = 0;
if (arguments.length > 1) {
i = toInteger(arguments[1]);
}
// handle negative indices
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
if (i in self && self[i] === sought) {
return i;
}
}
return -1;
};
}
// ES5 15.4.4.15
// http://es5.github.com/#x15.4.4.15
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
var self = splitString && _toString(this) == "[object String]" ?
this.split("") :
toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = length - 1;
if (arguments.length > 1) {
i = Math.min(i, toInteger(arguments[1]));
}
// handle negative indices
i = i >= 0 ? i : length - Math.abs(i);
for (; i >= 0; i--) {
if (i in self && sought === self[i]) {
return i;
}
}
return -1;
};
}
//
// Object
// ======
//
// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14
if (!Object.keys) {
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = true,
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
for (var key in {"toString": null}) {
hasDontEnumBug = false;
}
Object.keys = function keys(object) {
if (
(typeof object != "object" && typeof object != "function") ||
object === null
) {
throw new TypeError("Object.keys called on a non-object");
}
var keys = [];
for (var name in object) {
if (owns(object, name)) {
keys.push(name);
}
}
if (hasDontEnumBug) {
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
var dontEnum = dontEnums[i];
if (owns(object, dontEnum)) {
keys.push(dontEnum);
}
}
}
return keys;
};
}
//
// Date
// ====
//
// ES5 15.9.5.43
// http://es5.github.com/#x15.9.5.43
// This function returns a String value represent the instance in time
// represented by this Date object. The format of the String is the Date Time
// string format defined in 15.9.1.15. All fields are present in the String.
// The time zone is always UTC, denoted by the suffix Z. If the time value of
// this object is not a finite Number a RangeError exception is thrown.
var negativeDate = -62198755200000,
negativeYearString = "-000001";
if (
!Date.prototype.toISOString ||
(new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1)
) {
Date.prototype.toISOString = function toISOString() {
var result, length, value, year, month;
if (!isFinite(this)) {
throw new RangeError("Date.prototype.toISOString called on non-finite value.");
}
year = this.getUTCFullYear();
month = this.getUTCMonth();
// see https://github.com/kriskowal/es5-shim/issues/111
year += Math.floor(month / 12);
month = (month % 12 + 12) % 12;
// the date time string format is specified in 15.9.1.15.
result = [month + 1, this.getUTCDate(),
this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
year = (
(year < 0 ? "-" : (year > 9999 ? "+" : "")) +
("00000" + Math.abs(year))
.slice(0 <= year && year <= 9999 ? -4 : -6)
);
length = result.length;
while (length--) {
value = result[length];
// pad months, days, hours, minutes, and seconds to have two
// digits.
if (value < 10) {
result[length] = "0" + value;
}
}
// pad milliseconds to have three digits.
return (
year + "-" + result.slice(0, 2).join("-") +
"T" + result.slice(2).join(":") + "." +
("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
);
};
}
// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// This function provides a String representation of a Date object for use by
// JSON.stringify (15.12.3).
var dateToJSONIsSupported = false;
try {
dateToJSONIsSupported = (
Date.prototype.toJSON &&
new Date(NaN).toJSON() === null &&
new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
Date.prototype.toJSON.call({ // generic
toISOString: function () {
return true;
}
})
);
} catch (e) {
}
if (!dateToJSONIsSupported) {
Date.prototype.toJSON = function toJSON(key) {
// When the toJSON method is called with argument key, the following
// steps are taken:
// 1. Let O be the result of calling ToObject, giving it the this
// value as its argument.
// 2. Let tv be toPrimitive(O, hint Number).
var o = Object(this),
tv = toPrimitive(o),
toISO;
// 3. If tv is a Number and is not finite, return null.
if (typeof tv === "number" && !isFinite(tv)) {
return null;
}
// 4. Let toISO be the result of calling the [[Get]] internal method of
// O with argument "toISOString".
toISO = o.toISOString;
// 5. If IsCallable(toISO) is false, throw a TypeError exception.
if (typeof toISO != "function") {
throw new TypeError("toISOString property is not callable");
}
// 6. Return the result of calling the [[Call]] internal method of
// toISO with O as the this value and an empty argument list.
return toISO.call(o);
// NOTE 1 The argument is ignored.
// NOTE 2 The toJSON function is intentionally generic; it does not
// require that its this value be a Date object. Therefore, it can be
// transferred to other kinds of objects for use as a method. However,
// it does require that any such object have a toISOString method. An
// object is free to use the argument key to filter its
// stringification.
};
}
// ES5 15.9.4.2
// http://es5.github.com/#x15.9.4.2
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
if (!Date.parse || "Date.parse is buggy") {
// XXX global assignment won't work in embeddings that use
// an alternate object for the context.
Date = (function(NativeDate) {
// Date.length === 7
function Date(Y, M, D, h, m, s, ms) {
var length = arguments.length;
if (this instanceof NativeDate) {
var date = length == 1 && String(Y) === Y ? // isString(Y)
// We explicitly pass it through parse:
new NativeDate(Date.parse(Y)) :
// We have to manually make calls depending on argument
// length here
length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
length >= 5 ? new NativeDate(Y, M, D, h, m) :
length >= 4 ? new NativeDate(Y, M, D, h) :
length >= 3 ? new NativeDate(Y, M, D) :
length >= 2 ? new NativeDate(Y, M) :
length >= 1 ? new NativeDate(Y) :
new NativeDate();
// Prevent mixups with unfixed Date object
date.constructor = Date;
return date;
}
return NativeDate.apply(this, arguments);
};
// 15.9.1.15 Date Time String Format.
var isoDateExpression = new RegExp("^" +
"(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
// 6-digit extended year
"(?:-(\\d{2})" + // optional month capture
"(?:-(\\d{2})" + // optional day capture
"(?:" + // capture hours:minutes:seconds.milliseconds
"T(\\d{2})" + // hours capture
":(\\d{2})" + // minutes capture
"(?:" + // optional :seconds.milliseconds
":(\\d{2})" + // seconds capture
"(?:\\.(\\d{3}))?" + // milliseconds capture
")?" +
"(" + // capture UTC offset component
"Z|" + // UTC capture
"(?:" + // offset specifier +/-hours:minutes
"([-+])" + // sign capture
"(\\d{2})" + // hours offset capture
":(\\d{2})" + // minutes offset capture
")" +
")?)?)?)?" +
"$");
var months = [
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
];
function dayFromMonth(year, month) {
var t = month > 1 ? 1 : 0;
return (
months[month] +
Math.floor((year - 1969 + t) / 4) -
Math.floor((year - 1901 + t) / 100) +
Math.floor((year - 1601 + t) / 400) +
365 * (year - 1970)
);
}
// Copy any custom methods a 3rd party library may have added
for (var key in NativeDate) {
Date[key] = NativeDate[key];
}
// Copy "native" methods explicitly; they may be non-enumerable
Date.now = NativeDate.now;
Date.UTC = NativeDate.UTC;
Date.prototype = NativeDate.prototype;
Date.prototype.constructor = Date;
// Upgrade Date.parse to handle simplified ISO 8601 strings
Date.parse = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
// parse months, days, hours, minutes, seconds, and milliseconds
// provide default values if necessary
// parse the UTC offset component
var year = Number(match[1]),
month = Number(match[2] || 1) - 1,
day = Number(match[3] || 1) - 1,
hour = Number(match[4] || 0),
minute = Number(match[5] || 0),
second = Number(match[6] || 0),
millisecond = Number(match[7] || 0),
// When time zone is missed, local offset should be used
// (ES 5.1 bug)
// see https://bugs.ecmascript.org/show_bug.cgi?id=112
offset = !match[4] || match[8] ?
0 : Number(new NativeDate(1970, 0)),
signOffset = match[9] === "-" ? 1 : -1,
hourOffset = Number(match[10] || 0),
minuteOffset = Number(match[11] || 0),
result;
if (
hour < (
minute > 0 || second > 0 || millisecond > 0 ?
24 : 25
) &&
minute < 60 && second < 60 && millisecond < 1000 &&
month > -1 && month < 12 && hourOffset < 24 &&
minuteOffset < 60 && // detect invalid offsets
day > -1 &&
day < (
dayFromMonth(year, month + 1) -
dayFromMonth(year, month)
)
) {
result = (
(dayFromMonth(year, month) + day) * 24 +
hour +
hourOffset * signOffset
) * 60;
result = (
(result + minute + minuteOffset * signOffset) * 60 +
second
) * 1000 + millisecond + offset;
if (-8.64e15 <= result && result <= 8.64e15) {
return result;
}
}
return NaN;
}
return NativeDate.parse.apply(this, arguments);
};
return Date;
})(Date);
}
// ES5 15.9.4.4
// http://es5.github.com/#x15.9.4.4
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
//
// String
// ======
//
// ES5 15.5.4.14
// http://es5.github.com/#x15.5.4.14
// [bugfix, chrome]
// If separator is undefined, then the result array contains just one String,
// which is the this value (converted to a String). If limit is not undefined,
// then the output array is truncated so that it contains no more than limit
// elements.
// "0".split(undefined, 0) -> []
if("0".split(void 0, 0).length) {
var string_split = String.prototype.split;
String.prototype.split = function(separator, limit) {
if(separator === void 0 && limit === 0)return [];
return string_split.apply(this, arguments);
}
}
// ECMA-262, 3rd B.2.3
// Note an ECMAScript standart, although ECMAScript 3rd Edition has a
// non-normative section suggesting uniform semantics and it should be
// normalized across all browsers
// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
if("".substr && "0b".substr(-1) !== "b") {
var string_substr = String.prototype.substr;
/**
* Get the substring of a string
* @param {integer} start where to start the substring
* @param {integer} length how many characters to return
* @return {string}
*/
String.prototype.substr = function(start, length) {
return string_substr.call(
this,
start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
length
);
}
}
// ES5 15.5.4.20
// http://es5.github.com/#x15.5.4.20
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF";
if (!String.prototype.trim || ws.trim()) {
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
// http://perfectionkills.com/whitespace-deviations/
ws = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
trimEndRegexp = new RegExp(ws + ws + "*$");
String.prototype.trim = function trim() {
if (this === undefined || this === null) {
throw new TypeError("can't convert "+this+" to object");
}
return String(this)
.replace(trimBeginRegexp, "")
.replace(trimEndRegexp, "");
};
}
//
// Util
// ======
//
// ES5 9.4
// http://es5.github.com/#x9.4
// http://jsperf.com/to-integer
function toInteger(n) {
n = +n;
if (n !== n) { // isNaN
n = 0;
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
return n;
}
function isPrimitive(input) {
var type = typeof input;
return (
input === null ||
type === "undefined" ||
type === "boolean" ||
type === "number" ||
type === "string"
);
}
function toPrimitive(input) {
var val, valueOf, toString;
if (isPrimitive(input)) {
return input;
}
valueOf = input.valueOf;
if (typeof valueOf === "function") {
val = valueOf.call(input);
if (isPrimitive(val)) {
return val;
}
}
toString = input.toString;
if (typeof toString === "function") {
val = toString.call(input);
if (isPrimitive(val)) {
return val;
}
}
throw new TypeError();
}
// ES5 9.9
// http://es5.github.com/#x9.9
var toObject = function (o) {
if (o == null) { // this matches both null and undefined
throw new TypeError("can't convert "+o+" to object");
}
return Object(o);
};
});

View File

@@ -0,0 +1,488 @@
/*
json2.js
2012-10-08
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, regexp: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (typeof JSON !== 'object') {
JSON = {};
}
(function () {
'use strict';
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf())
? this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z'
: null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string'
? c
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
if (typeof rep[i] === 'string') {
k = rep[i];
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk({'': j}, '')
: j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
kampfer.provide('JSON');

View File

@@ -0,0 +1,18 @@
/**
* 用于检测浏览器的功能特性
* @module support.js
* @author l.w.kampfer@gmail.com
*/
kampfer.provide('browser.support');
kampfer.browser.support.deleteExpando = (function() {
var div = document.createElement('div');
try{
delete div.test;
return true;
} catch(e) {
return false;
}
})();

View File

@@ -0,0 +1,92 @@
/*global kampfer console*/
kampfer.require('events');
kampfer.require('dom');
kampfer.require('Component');
kampfer.require('mindMap.Node');
kampfer.require('mindMap.radio');
kampfer.provide('mindMap.Map');
//TODO 将map改造成controller
kampfer.mindMap.Map = kampfer.Component.extend({
_id : 'map',
currentNode : null,
initializer : function(mapManager) {
kampfer.mindMap.Map.superClass.initializer.apply(this, arguments);
this.addChildren( mapManager.getNodeTree() );
},
decorate : function() {
this._element.id = this.getId();
this._element.setAttribute('role', 'map');
kampfer.dom.addClass(this._element, 'map');
var that = this, dragingNode = false, x, y;
kampfer.events.addListener(this._element, 'mousedown', function(event) {
var role = event.target.getAttribute('role');
if(role === 'map' || role === 'branch') {
if( that.currentNode && that.currentNode.isEditing() ) {
kampfer.mindMap.radio.dispatch({
type : 'executeCommand',
command : 'SaveNodeContent',
nodeId : that.currentNode.getId()
});
}
that.currentNode = null;
} else if(role === 'content' || role === 'caption') {
that.currentNode = role === 'caption' ?
that.getChild(event.target.id).getParent() :
that.getChild(event.target.parentNode.id).getParent();
if( event.which === 1 && !that.currentNode.isEditing() ) {
dragingNode = true;
var position = that.currentNode.getPosition();
x = event.pageX - position.left;
y = event.pageY - position.top;
}
}
});
kampfer.events.addListener(this._element, 'mouseup', function(event) {
if(dragingNode) {
dragingNode = false;
kampfer.mindMap.radio.dispatch({
type : 'executeCommand',
command : 'SaveNodePosition',
nodeId : that.currentNode.getId(),
x : event.pageX - x,
y : event.pageY - y
});
}
});
kampfer.events.addListener(this._element, 'mousemove', function(event) {
if(dragingNode) {
that.currentNode.moveTo(event.pageX - x, event.pageY - y);
return false;
}
});
},
addChildren : function(children) {
if(children) {
for(var i = 0, l = children.length; i < l; i++) {
var child = children[i];
this.addChild( new kampfer.mindMap.Node(child) );
}
}
},
dispose : function() {
kampfer.mindMap.Menu.superClass.dispose.apply(this);
this.currentNode = null;
kampfer.events.removeListener(this._element);
}
});

View File

@@ -0,0 +1,98 @@
kampfer.require('Component');
kampfer.require('dom');
kampfer.require('events');
kampfer.require('mindMap.radio');
kampfer.provide('Menu');
kampfer.provide('MenuItem');
kampfer.Menu = kampfer.Component.extend({
/*
* @param {dom||string}elem 传入的elem参数是对象, 说明menu已经在文档流中,
* 不需要再创建全新的dom对象插入文档流。传入的elem是字符串那么Menu
* 类将创建新的dom并插入文档elem将作为menu的id使用。
*/
initializer : function(elem, trigger) {
kampfer.Menu.superClass.initializer.apply(this, arguments);
var type = kampfer.type(elem);
if(type === 'string') {
this._id = elem;
this.render();
} else if(type === 'object' && elem.nodeType) {
this._element = elem;
this._id = elem.id;
this._wasDecorated = true;
this._inDocument = true;
} else {
return;
}
this._element.style.display = 'none';
kampfer.events.addListener(this._element, 'click', function(event) {
var command = event.target.getAttribute('command');
//点击菜单后菜单项自动获得焦点并且高亮显示,我们不需要这种效果,
//所以这里使菜单项失去焦点
event.target.blur();
//如果菜单项绑定了命令并且没有被禁用就触发相应事件
if( command && !(/disabled/.test(event.target.parentNode.className)) ) {
this.hide();
event.type = 'executeCommand';
event.command = command;
kampfer.mindMap.radio.dispatch(event);
return false;
}
}, this);
if(trigger && trigger.nodeType) {
this.trigger = trigger;
//trigger的子元素的mouseover&mouseout冒泡到trigger上导致处理函数重复触发
//webkit浏览器不支持mouseenter和mouseleave, 无法使用. 这里使用hook处理处理函数重复触发的问题
kampfer.events.addListener(trigger, 'mouseover', function(event) {
var relatedElement = event.relatedTarget;
if( !kampfer.dom.contains(trigger, relatedElement) ) {
this.show();
}
}, this);
kampfer.events.addListener(trigger, 'mouseout', function(event) {
var relatedElement = event.relatedTarget;
if( !kampfer.dom.contains(trigger, relatedElement) ) {
this.hide();
}
}, this);
}
},
trigger : null,
show : function() {
this.dispatch('beforemenushow', this);
kampfer.Menu.superClass.show.apply(this);
},
disable : function(index) {
if(typeof index === 'number') {
var commandItems = this._element.querySelectorAll('[command]');
kampfer.dom.addClass(commandItems[index].parentNode, 'disabled');
}
},
enable : function(index) {
if(typeof index === 'number') {
var commandItems = this._element.querySelectorAll('[command]');
kampfer.dom.removeClass(commandItems[index].parentNode, 'disabled');
}
},
dispose : function() {
kampfer.Menu.superClass.dispose.apply(this, arguments);
kampfer.events.removeListener(this._element);
kampfer.events.removeListener(this.trigger);
}
});

View File

@@ -0,0 +1,48 @@
kampfer.require('mindMap.Window');
kampfer.require('mindMap.ToolBar');
kampfer.require('mindMap.command.Controller');
kampfer.require('Menu');
kampfer.require('events');
kampfer.provide('mindMap');
kampfer.provide('mindMap.window');
kampfer.provide('mindMap.toolBar');
kampfer.provide('mindMap.nodeContextMenu');
kampfer.provide('mindMap.contextMenu');
kampfer.mindMap.init = function() {
var nodeContextMenu = document.getElementById('node-context-menu'),
contextMenu = document.getElementById('context-menu');
kampfer.mindMap.toolBar = new kampfer.mindMap.ToolBar('app-tool-bar');
kampfer.mindMap.window = new kampfer.mindMap.Window('map-container');
kampfer.mindMap.nodeContextMenu = new kampfer.Menu(nodeContextMenu);
kampfer.mindMap.contextMenu = new kampfer.Menu(contextMenu);
kampfer.mindMap.command.controller = new kampfer.mindMap.command.Controller(kampfer.mindMap.window);
function checkMenuCommand(event) {
var commands = event.currentTarget.getElement().querySelectorAll('[command]');
for(var i = 0, command; (command = commands[i]); i++) {
var name = command.getAttribute('command');
if( !kampfer.mindMap.command.controller.isCommandAvalilable(name) ) {
this.disable(i);
} else {
this.enable(i);
}
}
}
kampfer.mindMap.toolBar.eachChild(function(child) {
child.addListener('beforemenushow', checkMenuCommand);
});
kampfer.mindMap.contextMenu.addListener('beforemenushow', checkMenuCommand);
kampfer.mindMap.nodeContextMenu.addListener('beforemenushow', checkMenuCommand);
kampfer.events.addListener(window, 'beforeunload', function(event) {
if( kampfer.mindMap.mapManager && kampfer.mindMap.mapManager.isModified() ) {
event.returnValue = 'map未保存,确定退出?';
return 'map未保存,确定退出?';
}
});
};

View File

@@ -0,0 +1,86 @@
/*global kampfer console*/
kampfer.require('events');
kampfer.require('dom');
kampfer.require('Component');
kampfer.require('mindMap.Branch');
kampfer.require('mindMap.Caption');
kampfer.provide('mindMap.Node');
kampfer.mindMap.Node = kampfer.Component.extend({
initializer : function(data) {
kampfer.mindMap.Node.superClass.initializer.apply(this, arguments);
this._id = data.id;
this.addCaption(data);
this.addBranch(data);
this.addChildren(data.children);
this.createDom();
this.setPosition(data.offset.x, data.offset.y);
},
addCaption : function(data) {
var caption = new kampfer.mindMap.Caption(data);
this.addChild(caption);
},
addBranch : function(data) {
if(data.parent) {
var branch = new kampfer.mindMap.Branch(data);
this.addChild(branch);
}
},
addChildren : function(children) {
if(children) {
for(var i = 0, l = children.length; i < l; i++) {
var child = children[i];
this.addChild( new kampfer.mindMap.Node(child) );
}
}
},
getBranch : function() {
return this.getChild('branch-' + this._id);
},
getCaption : function() {
return this.getChild('caption-' + this._id);
},
/* 拓展此方法 */
decorate : function() {
kampfer.mindMap.Node.superClass.decorate.apply(this, arguments);
this._element.id = this._id;
kampfer.dom.addClass(this._element, 'node');
this._element.setAttribute('role', 'node');
},
move : function(x, y) {
var oriPosition = this.getPosition();
x += oriPosition.left;
y += oriPosition.top;
this.moveTo(x, y);
},
moveTo : function(x, y) {
this.setPosition(x, y);
//如果是node就同步更新branch视图
if(this._parent._id !== 'map') {
this.getBranch().decorate();
}
},
isEditing : function() {
return this.getCaption().isEditing;
},
dispose : function() {}
});

View File

@@ -0,0 +1,128 @@
kampfer.require('Dialog');
kampfer.require('mindMap.command');
kampfer.provide('mindMap.OpenMapDialog');
kampfer.OpenMapDialog = kampfer.Dialog.extend({
initializer : function(storage, view) {
this._storage = storage;
this._view = view;
this.render();
this.setContent(this._content);
this.setTitle('Chose:');
},
events : {
click : {
'ok' : 'openMap hide',
'close' : 'hide',
'cancel' : 'hide',
map : function(event) {
var element = event.target,
name = element.querySelectorAll('td')[1].innerHTML;
kampfer.dom.addClass(element, 'info');
this.selectMap(name);
}
}
},
_content : '<p class=\"text-info\">There are <span>0</span> maps in your localstorage.<\/p>' +
'<div class=\"app-file-list\">' +
'<table class=\"table table-condensed table-hover table-striped\">' +
'<thead>' +
'<tr>' +
'<th>#<\/th>' +
'<th>map name<\/th>' +
'<th>lastModified<\/th>' +
'<\/tr>' +
'<\/thead>' +
'<tbody><\/tbody>' +
'<\/table>' +
'<\/div>' +
'<div class=\"app-file-name\">' +
'<div class=\"input-prepend\">' +
'<span class=\"add-on\">File name :<\/span>' +
'<input class=\"span4\" id=\"map-name\" type=\"text\" placeholder=\"Please write file name\">' +
'<\/div>' +
'<\/div>',
_buttons : (function() {
var buttons = [
document.createElement('button'),
document.createElement('button')
];
buttons[0].setAttribute('data-action', 'ok');
buttons[0].innerHTML = 'Open Map';
buttons[1].setAttribute('data-action', 'cancel');
buttons[1].innerHTML = 'Cancel';
return buttons;
})(),
updateMapCount : function() {
var mapCount = this._storage.getMapCount();
if(!this._mapCountElement) {
this._mapCountElement = this._element.querySelector('.text-info>span');
}
this._mapCountElement.innerHTML = mapCount;
},
updateMapList : function() {
var mapList = this._storage.getMapList();
if(!mapList) {
return;
}
for(var i = 0, map; (map = mapList[i]); i++) {
this.addMap2List(map, i + 1);
}
},
addMap2List : function(map, index) {
var tr = document.createElement('tr'),
name = map.name,
lastModified = new Date(map.lastModified).toLocaleDateString();
tr.innerHTML = ['<td>', index, '</td><td>', name, '</td><td>', lastModified, '</td'].join('');
tr.setAttribute('data-action', 'map');
if(!this._mapListElment) {
this._mapListElment = this._element.querySelector('tbody');
}
this._mapListElment.appendChild(tr);
},
selectMap : function(name) {
this._element.querySelector('#map-name').value = name;
this._selectedMap = this._storage.getMapData(name);
},
getSelectedMap : function() {
return this._selectedMap;
},
openMap : function() {
var mapData = this.getSelectedMap();
if(!mapData) {
return false;
}
var command = new kampfer.mindMap.command.CreateNewMap(mapData, this._view);
command.execute();
},
show : function() {
this.updateMapCount();
this.updateMapList();
kampfer.OpenMapDialog.superClass.show.call(this);
},
dispose : function() {
kampfer.OpenMapDialog.superClass.dispose.call(this);
delete this._storage;
delete this._view;
delete this._buttons;
delete this._mapListElment;
delete this._mapCountElement;
}
});

View File

@@ -0,0 +1,6 @@
/*! @source http://purl.eligrey.com/github/BlobBuilder.js/blob/master/BlobBuilder.js */
var BlobBuilder=BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||(function(j){"use strict";var c=function(v){return Object.prototype.toString.call(v).match(/^\[object\s(.*)\]$/)[1]},u=function(){this.data=[]},t=function(x,v,w){this.data=x;this.size=x.length;this.type=v;this.encoding=w},k=u.prototype,s=t.prototype,n=j.FileReaderSync,a=function(v){this.code=this[this.name=v]},l=("NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR").split(" "),r=l.length,o=j.URL||j.webkitURL||j,p=o.createObjectURL,b=o.revokeObjectURL,e=o,i=j.btoa,f=j.atob,m=false,h=function(v){m=!v},d=j.ArrayBuffer,g=j.Uint8Array;u.fake=s.fake=true;while(r--){a.prototype[l[r]]=r+1}try{if(g){h.apply(0,new g(1))}}catch(q){}if(!o.createObjectURL){e=j.URL={}}e.createObjectURL=function(w){var x=w.type,v;if(x===null){x="application/octet-stream"}if(w instanceof t){v="data:"+x;if(w.encoding==="base64"){return v+";base64,"+w.data}else{if(w.encoding==="URI"){return v+","+decodeURIComponent(w.data)}}if(i){return v+";base64,"+i(w.data)}else{return v+","+encodeURIComponent(w.data)}}else{if(real_create_object_url){return real_create_object_url.call(o,w)}}};e.revokeObjectURL=function(v){if(v.substring(0,5)!=="data:"&&real_revoke_object_url){real_revoke_object_url.call(o,v)}};k.append=function(z){var B=this.data;if(g&&z instanceof d){if(m){B.push(String.fromCharCode.apply(String,new g(z)))}else{var A="",w=new g(z),x=0,y=w.length;for(;x<y;x++){A+=String.fromCharCode(w[x])}}}else{if(c(z)==="Blob"||c(z)==="File"){if(n){var v=new n;B.push(v.readAsBinaryString(z))}else{throw new a("NOT_READABLE_ERR")}}else{if(z instanceof t){if(z.encoding==="base64"&&f){B.push(f(z.data))}else{if(z.encoding==="URI"){B.push(decodeURIComponent(z.data))}else{if(z.encoding==="raw"){B.push(z.data)}}}}else{if(typeof z!=="string"){z+=""}B.push(unescape(encodeURIComponent(z)))}}}};k.getBlob=function(v){if(!arguments.length){v=null}return new t(this.data.join(""),v,"raw")};k.toString=function(){return"[object BlobBuilder]"};s.slice=function(y,v,x){var w=arguments.length;if(w<3){x=null}return new t(this.data.slice(y,w>1?v:this.data.length),x,this.encoding)};s.toString=function(){return"[object Blob]"};return u}(self));
kampfer.provide('BlobBuilder');
kampfer.BlobBuilder = BlobBuilder;

View File

@@ -0,0 +1,6 @@
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs=saveAs||navigator.msSaveBlob&&navigator.msSaveBlob.bind(navigator)||function(a){"use strict";var b=a.document,c=function(){return a.URL||a.webkitURL||a},d=a.URL||a.webkitURL||a,e=b.createElementNS("http://www.w3.org/1999/xhtml","a"),f="download"in e,g=function(c){var d=b.createEvent("MouseEvents");return d.initMouseEvent("click",!0,!1,a,0,0,0,0,0,!1,!1,!1,!1,0,null),c.dispatchEvent(d)},h=a.webkitRequestFileSystem,i=a.requestFileSystem||h||a.mozRequestFileSystem,j=function(b){(a.setImmediate||a.setTimeout)(function(){throw b},0)},k="application/octet-stream",l=0,m=[],n=function(){for(var a=m.length;a--;){var b=m[a];"string"==typeof b?d.revokeObjectURL(b):b.remove()}m.length=0},o=function(a,b,c){b=[].concat(b);for(var d=b.length;d--;){var e=a["on"+b[d]];if("function"==typeof e)try{e.call(a,c||a)}catch(f){j(f)}}},p=function(b,d){var q,r,x,j=this,n=b.type,p=!1,s=function(){var a=c().createObjectURL(b);return m.push(a),a},t=function(){o(j,"writestart progress write writeend".split(" "))},u=function(){(p||!q)&&(q=s(b)),r&&(r.location.href=q),j.readyState=j.DONE,t()},v=function(a){return function(){return j.readyState!==j.DONE?a.apply(this,arguments):void 0}},w={create:!0,exclusive:!1};return j.readyState=j.INIT,d||(d="download"),f&&(q=s(b),e.href=q,e.download=d,g(e))?(j.readyState=j.DONE,t(),void 0):(a.chrome&&n&&n!==k&&(x=b.slice||b.webkitSlice,b=x.call(b,0,b.size,k),p=!0),h&&"download"!==d&&(d+=".download"),r=n===k||h?a:a.open(),i?(l+=b.size,i(a.TEMPORARY,l,v(function(a){a.root.getDirectory("saved",w,v(function(a){var c=function(){a.getFile(d,w,v(function(a){a.createWriter(v(function(c){c.onwriteend=function(b){r.location.href=a.toURL(),m.push(a),j.readyState=j.DONE,o(j,"writeend",b)},c.onerror=function(){var a=c.error;a.code!==a.ABORT_ERR&&u()},"writestart progress write abort".split(" ").forEach(function(a){c["on"+a]=j["on"+a]}),c.write(b),j.abort=function(){c.abort(),j.readyState=j.DONE},j.readyState=j.WRITING}),u)}),u)};a.getFile(d,{create:!1},v(function(a){a.remove(),c()}),v(function(a){a.code===a.NOT_FOUND_ERR?c():u()}))}),u)}),u),void 0):(u(),void 0))},q=p.prototype,r=function(a,b){return new p(a,b)};return q.abort=function(){var a=this;a.readyState=a.DONE,o(a,"abort")},q.readyState=q.INIT=0,q.WRITING=1,q.DONE=2,q.error=q.onwritestart=q.onprogress=q.onwrite=q.onabort=q.onerror=q.onwriteend=null,a.addEventListener("unload",n,!1),r}(self);
kampfer.provide('saveAs');
kampfer.saveAs = saveAs;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
/* mousetrap v1.3 craig.is/killing/mice */
(function(){function s(a,c,b){a.addEventListener?a.addEventListener(c,b,!1):a.attachEvent("on"+c,b)}function y(a){return"keypress"==a.type?String.fromCharCode(a.which):h[a.which]?h[a.which]:z[a.which]?z[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a,c){a=a||{};var b=!1,d;for(d in m)a[d]&&m[d]>c?b=!0:m[d]=0;b||(p=!1)}function A(a,c,b,d,g){var f,e,h=[],j=b.type;if(!l[a])return[];"keyup"==j&&u(a)&&(c=[a]);for(f=0;f<l[a].length;++f)if(e=l[a][f],!(e.seq&&m[e.seq]!=e.level)&&j==e.action&&
("keypress"==j&&!b.metaKey&&!b.ctrlKey||c.sort().join(",")===e.modifiers.sort().join(",")))d&&e.combo==g&&l[a].splice(f,1),h.push(e);return h}function v(a,c,b){if(!k.stopCallback(c,c.target||c.srcElement,b)&&!1===a(c,b))c.preventDefault&&c.preventDefault(),c.stopPropagation&&c.stopPropagation(),c.returnValue=!1,c.cancelBubble=!0}function w(a){"number"!==typeof a.which&&(a.which=a.keyCode);var c=y(a);if(c)if("keyup"==a.type&&x==c)x=!1;else{var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");
a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");var b=A(c,b,a),d,g={},f=0,e=!1;for(d=0;d<b.length;++d)b[d].seq?(e=!0,f=Math.max(f,b[d].level),g[b[d].seq]=1,v(b[d].callback,a,b[d].combo)):!e&&!p&&v(b[d].callback,a,b[d].combo);a.type==p&&!u(c)&&t(g,f)}}function u(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function B(a,c,b){if(!b){if(!q){q={};for(var d in h)95<d&&112>d||h.hasOwnProperty(d)&&(q[h[d]]=d)}b=q[a]?"keydown":"keypress"}"keypress"==b&&c.length&&(b="keydown");return b}function C(a,
c,b,d,g){r[a+":"+b]=c;a=a.replace(/\s+/g," ");var f=a.split(" "),e,h,j=[];if(1<f.length){var k=a,n=b;m[k]=0;n||(n=B(f[0],[]));a=function(){p=n;++m[k];clearTimeout(D);D=setTimeout(t,1E3)};b=function(a){v(c,a,k);"keyup"!==n&&(x=y(a));setTimeout(t,10)};for(d=0;d<f.length;++d)C(f[d],d<f.length-1?a:b,n,k,d)}else{h="+"===a?["+"]:a.split("+");for(f=0;f<h.length;++f)e=h[f],E[e]&&(e=E[e]),b&&("keypress"!=b&&F[e])&&(e=F[e],j.push("shift")),u(e)&&j.push(e);b=B(e,j,b);l[e]||(l[e]=[]);A(e,j,{type:b},!d,a);l[e][d?
"unshift":"push"]({callback:c,modifiers:j,action:b,seq:d,level:g,combo:a})}}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},z={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},F={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6",
"&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},q,l={},r={},m={},D,x=!1,p=!1,g=1;20>g;++g)h[111+g]="f"+g;for(g=0;9>=g;++g)h[g+96]=g;s(document,"keypress",w);s(document,"keydown",w);s(document,"keyup",w);var k={bind:function(a,c,b){a=a instanceof Array?a:[a];for(var d=0;d<a.length;++d)C(a[d],c,b);return this},unbind:function(a,c){return k.bind(a,function(){},c)},trigger:function(a,c){if(r[a+
":"+c])r[a+":"+c]();return this},reset:function(){l={};r={};return this},stopCallback:function(a,c){return-1<(" "+c.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==c.tagName||"SELECT"==c.tagName||"TEXTAREA"==c.tagName||c.contentEditable&&"true"==c.contentEditable}};window.Mousetrap=k;"function"===typeof define&&define.amd&&define(k)})();
kampfer.provide('mousetrap');

View File

@@ -0,0 +1,6 @@
/* Copyright (c) 2010-2012 Marcus Westin */
(function(){function h(){try{return d in b&&b[d]}catch(a){return!1}}function i(){try{return e in b&&b[e]&&b[e][b.location.hostname]}catch(a){return!1}}var a={},b=window,c=b.document,d="localStorage",e="globalStorage",f="__storejs__",g;a.disabled=!1,a.set=function(a,b){},a.get=function(a){},a.remove=function(a){},a.clear=function(){},a.transact=function(b,c,d){var e=a.get(b);d==null&&(d=c,c=null),typeof e=="undefined"&&(e=c||{}),d(e),a.set(b,e)},a.getAll=function(){},a.serialize=function(a){return JSON.stringify(a)},a.deserialize=function(a){if(typeof a!="string")return undefined;try{return JSON.parse(a)}catch(b){return a||undefined}};if(h())g=b[d],a.set=function(b,c){return c===undefined?a.remove(b):(g.setItem(b,a.serialize(c)),c)},a.get=function(b){return a.deserialize(g.getItem(b))},a.remove=function(a){g.removeItem(a)},a.clear=function(){g.clear()},a.getAll=function(){var b={};for(var c=0;c<g.length;++c){var d=g.key(c);b[d]=a.get(d)}return b};else if(i())g=b[e][b.location.hostname],a.set=function(b,c){return c===undefined?a.remove(b):(g[b]=a.serialize(c),c)},a.get=function(b){return a.deserialize(g[b]&&g[b].value)},a.remove=function(a){delete g[a]},a.clear=function(){for(var a in g)delete g[a]},a.getAll=function(){var b={};for(var c=0;c<g.length;++c){var d=g.key(c);b[d]=a.get(d)}return b};else if(c.documentElement.addBehavior){var j,k;try{k=new ActiveXObject("htmlfile"),k.open(),k.write('<script>document.w=window</script><iframe src="/favicon.ico"></frame>'),k.close(),j=k.w.frames[0].document,g=j.createElement("div")}catch(l){g=c.createElement("div"),j=c.body}function m(b){return function(){var c=Array.prototype.slice.call(arguments,0);c.unshift(g),j.appendChild(g),g.addBehavior("#default#userData"),g.load(d);var e=b.apply(a,c);return j.removeChild(g),e}}var n=new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]","g");function o(a){return a.replace(n,"___")}a.set=m(function(b,c,e){return c=o(c),e===undefined?a.remove(c):(b.setAttribute(c,a.serialize(e)),b.save(d),e)}),a.get=m(function(b,c){return c=o(c),a.deserialize(b.getAttribute(c))}),a.remove=m(function(a,b){b=o(b),a.removeAttribute(b),a.save(d)}),a.clear=m(function(a){var b=a.XMLDocument.documentElement.attributes;a.load(d);for(var c=0,e;e=b[c];c++)a.removeAttribute(e.name);a.save(d)}),a.getAll=m(function(b){var c=b.XMLDocument.documentElement.attributes;b.load(d);var e={};for(var f=0,g;g=c[f];++f)e[g]=a.get(g);return e})}try{a.set(f,f),a.get(f)!=f&&(a.disabled=!0),a.remove(f)}catch(l){a.disabled=!0}a.enabled=!a.disabled,typeof module!="undefined"&&typeof module!="function"?module.exports=a:typeof define=="function"&&define.amd?define(a):this.store=a})();
kampfer.provide('store');
kampfer.store = store;

View File

@@ -0,0 +1,5 @@
kampfer.require('events.EventTarget');
kampfer.provide('mindMap.radio');
kampfer.mindMap.radio = new kampfer.events.EventTarget();

View File

@@ -0,0 +1,125 @@
kampfer.require('Dialog');
kampfer.require('mindMap.command');
kampfer.provide('mindMap.RenameMapDialog');
kampfer.mindMap.RenameMapDialog = kampfer.Dialog.extend({
initializer : function(storage, view) {
this._storage = storage;
this._view = view;
},
events : {
click : {
'ok' : 'ok hide',
'close' : 'hide',
'cancel' : 'hide',
map : function(event) {
var element = event.target,
name = element.querySelectorAll('td')[1].innerHTML;
kampfer.dom.addClass(element, 'info');
this.selectMap(name);
}
}
},
_content : '<p class=\"text-info\">There are <span>0</span> maps in your localstorage.<\/p>' +
'<div class=\"app-file-list\">' +
'<table class=\"table table-condensed table-hover table-striped\">' +
'<thead>' +
'<tr>' +
'<th>#<\/th>' +
'<th>map name<\/th>' +
'<th>lastModified<\/th>' +
'<\/tr>' +
'<\/thead>' +
'<tbody><\/tbody>' +
'<\/table>' +
'<\/div>' +
'<div class=\"app-file-name\">' +
'<div class=\"input-prepend\">' +
'<span class=\"add-on\">File name :<\/span>' +
'<input class=\"span4\" id=\"map-name\" type=\"text\" placeholder=\"Please write file name\">' +
'<\/div>' +
'<\/div>',
_buttons : (function() {
var buttons = [
document.createElement('button'),
document.createElement('button')
];
buttons[0].setAttribute('data-action', 'ok');
buttons[0].innerHTML = 'Save';
buttons[1].setAttribute('data-action', 'cancel');
buttons[1].innerHTML = 'Cancel';
return buttons;
})(),
render : function() {
kampfer.mindMap.RenameMapDialog.superClass.render.call(this);
this.setContent(this._content);
this.setTitle('另存为:');
},
updateMapCount : function() {
var mapCount = this._storage.getMapCount();
if(!this._mapCountElement) {
this._mapCountElement = this._element.querySelector('.text-info>span');
}
this._mapCountElement.innerHTML = mapCount;
},
updateMapList : function() {
var mapList = this._storage.getMapList();
if(!mapList) {
return;
}
for(var i = 0, map; (map = mapList[i]); i++) {
this.addMap2List(map, i + 1);
}
},
addMap2List : function(map, index) {
var tr = document.createElement('tr'),
name = map.name,
lastModified = new Date(map.lastModified).toLocaleDateString();
tr.innerHTML = ['<td>', index, '</td><td>', name, '</td><td>', lastModified, '</td'].join('');
tr.setAttribute('data-action', 'map');
if(!this._mapListElment) {
this._mapListElment = this._element.querySelector('tbody');
}
this._mapListElment.appendChild(tr);
},
selectMap : function(name) {
this._element.querySelector('#map-name').value = name;
this._selectedMap = this._storage.getMapData(name);
},
getSelectedMap : function() {
return this._selectedMap;
},
ok : function() {
this.dispatch('ok', this._element.querySelector('#map-name').value);
},
show : function() {
kampfer.OpenMapDialog.superClass.show.call(this);
this.updateMapCount();
this.updateMapList();
},
dispose : function() {
kampfer.OpenMapDialog.superClass.dispose.call(this);
delete this._storage;
delete this._view;
delete this._buttons;
delete this._mapListElment;
delete this._mapCountElement;
}
});

View File

@@ -0,0 +1,42 @@
kampfer.require('Component');
kampfer.require('events');
kampfer.require('Menu');
kampfer.provide('mindMap.ToolBar');
//TODO 构造器使用与menu相同的逻辑
kampfer.mindMap.ToolBar = kampfer.Component.extend({
initializer : function(id) {
var type = kampfer.type(id),
that = this;
if(type === 'string') {
this._element = this._doc.getElementById(id);
this._id = id;
if(!this._element) {
this.render();
}
} else {
return;
}
this.resolve();
},
resolve : function() {
if(this._element) {
var triggers = this._element.querySelectorAll('[role=menu-trigger]');
for(var i = 0, trigger; trigger = triggers[i]; i++) {
var menu = trigger.querySelector('[role=menu]');
this.addMenu(menu, trigger);
}
}
},
addMenu : function(menu, trigger) {
var menu = new kampfer.Menu(menu, trigger);
menu.getElement().id = menu.getId();
this.addChild(menu, true);
}
});

View File

@@ -0,0 +1,104 @@
kampfer.require('Component');
kampfer.require('events');
kampfer.require('Menu');
kampfer.require('dom');
kampfer.provide('mindMap.Window');
//TODO 构造器使用与menu相同的逻辑
kampfer.mindMap.Window = kampfer.Component.extend({
initializer : function(id) {
var type = kampfer.type(id),
that = this, scrollX, scrollY, x, y;
if(type === 'string') {
this._element = this._doc.getElementById(id);
this._id = id;
if(!this._element) {
this.render();
}
} else {
return;
}
this.beDraged = false;
kampfer.events.addListener(this._element, 'mousedown', function(event) {
scrollX = kampfer.dom.scrollLeft(that._element);
scrollY = kampfer.dom.scrollTop(that._element);
x = event.pageX;
y = event.pageY;
if(event.which === 1) {
//不存在map或已经开始拖拽不执行处理逻辑
if( !that.beDraged && kampfer.mindMap.map && event.target.getAttribute('role') === 'map') {
that.beDraged = true;
}
}
});
kampfer.events.addListener(this._element, 'mouseup', function(event) {
if(that.beDraged) {
that.beDraged = false;
return false;
}
});
kampfer.events.addListener(this._element, 'mousemove', function(event) {
if(that.beDraged) {
that.scrollLeft(scrollX + x - event.pageX);
that.scrollTop(scrollY + y - event.pageY);
return false;
}
});
kampfer.events.addListener(this._element, 'contextmenu', function(event) {
var role = event.target.getAttribute('role'),
scrollX = kampfer.mindMap.window.scrollLeft(),
scrollY = kampfer.mindMap.window.scrollTop();
var menu;
if(role === 'content' || role === 'caption' || role === 'node') {
menu = kampfer.mindMap.nodeContextMenu;
} else if(role === 'map') {
menu = kampfer.mindMap.contextMenu;
}
if(menu) {
menu.setPosition(event.pageX + scrollX, event.pageY + scrollY);
menu.show();
}
return false;
});
kampfer.events.addListener(this._element, 'click', function() {
kampfer.mindMap.contextMenu.hide();
kampfer.mindMap.nodeContextMenu.hide();
});
},
scrollLeft : function(offset) {
var offsetX = kampfer.dom.scrollLeft(this._element, offset);
if(typeof offsetX === 'number') {
return offsetX;
}
},
scrollTop : function(offset) {
var offsetY = kampfer.dom.scrollTop(this._element, offset);
if(typeof offsetY === 'number') {
return offsetY;
}
},
beDraged : null,
dispose : function() {
kampfer.mindMap.Window.superClass.dispose.apply(this);
kampfer.events.removeListener(this._element);
}
});

View File

@@ -0,0 +1,74 @@
/**
* map.json
* map, :
* root
* |---child1
* |---child1-1
* |---child1-1-1
* |---child1-2
* |---child2
* |---child3
*
* node:
* node
* |---id
* |---content
* |---offset
* |---parent
* |---children
*
* map
* |---tree
* |---name
* |---lastModified
*/
{
"document" : [
{
"id" : "child1",
"content" : "child1",
"offset" : {"x" : 100, "y" : 200},
"parent" : "map",
"children" : [
{
"id" : "child1-1",
"content" : "child1-1",
"offset" : {"x" : 100, "y" : 200},
"parent" : "child1",
"children" : [
{
"id" : "child1-1-1",
"content" : "child1-1-1",
"offset" : {"x" : 200, "y" : 200},
"parent" : "child1-1",
"children" : null
}
]
},
{
"id" : "child1-2",
"content" : "child1-2",
"offset" : {"x" : 200, "y" : 200},
"parent" : "child1",
"children" : null
}
]
},
{
"id" : "child2",
"content" : "child2",
"offset" : {"x" : 100, "y" : 100},
"parent" : "map",
"children" : null
},
{
"id" : "child3",
"content" : "child3",
"offset" : {"x" : 200, "y" : 100},
"parent" : "map",
"children" : null
}
],
"name" : "untitled",
"lastModified" : 123456789
}

View File

@@ -0,0 +1,9 @@
CACHE MANIFEST
#111
CACHE:
NETWORK:
*
FALLBACK:

View File

@@ -0,0 +1,211 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>test Composition</title>
<!-- 共用文件,不要修改 start -->
<link href="../css/qunit.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../js/base.js"></script>
<script type="text/javascript" src="../js/lib/tools/qunit.js"></script>
<!-- 共用文件,不要修改 end -->
<script type="text/javascript">
/*global ok, console, k, kampfer, test, QUnit*/
kampfer.require('mindMap.Composition');
</script>
</head>
<body>
<!-- 共用文件,不要修改 start -->
<h1 id="qunit-header">QUnit for Composition</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">
test markup, will be hidden
</div>
<!-- 共用文件,不要修改 end -->
<script type="text/javascript">
test('实例化Composition对象', function() {
var obj = new kampfer.mindMap.Composition();
ok(obj, '成功实例化Composition对象');
ok(obj.constructor === kampfer.mindMap.Composition, 'constructor正确');
ok(obj instanceof kampfer.mindMap.Composition, 'instanceof Composition : true');
ok(obj instanceof kampfer.events.EventTarget, 'instanceof EventTarget : true');
ok(obj instanceof kampfer.Class, 'instanceof Class : true');
ok(('_parent' in obj) && !obj._parent, '_parent属性存在,但未初始化');
ok(('_id' in obj) && !obj._id, '_id属性存在,但未初始化');
ok(('_children' in obj) && !obj._children, '_children属性存在,但未初始化');
});
test('Composition.setParent', function() {
var obj = new kampfer.mindMap.Composition();
var p = {name:'parent'};
var parent = new kampfer.mindMap.Composition();
try{
obj.setParent(obj);
}catch(e) {
ok(!obj._parent, '无法将composition对象的parent设为它自己');
}
try{
obj.setParent(p);
}catch(e) {
ok(!obj._parent, 'composition对象的parent不能是非composition对象');
}
obj.setParent(parent);
ok(obj._parent === parent, '可以通过setParent方法设置parent');
ok(obj._parentEventTarget === parent, 'setParent方法会设置_parentEventTarget');
var pp = new kampfer.mindMap.Composition();
try {
obj.setParent(pp);
} catch(e) {
ok(true, 'composition有parent后无法再设置parent');
}
obj.setParent(null);
//不要使用setParent(null)来达到删除parent的目的
ok(obj.getParent() === null, '可以设置parent为null');
});
test('Composition.getParent', function() {
var obj = new kampfer.mindMap.Composition();
var p = new kampfer.mindMap.Composition();
obj.setParent(p);
ok(obj.getParent() === p, '可以通过getParent方法获得_parent');
});
test('Composition.addChlid', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
var o = {};
try{
obj.addChild(o);
} catch(e) {
ok(true, 'addChild方法只接受composition对象作为参数');
}
var hasId = !!c._id;
obj.addChild(c);
var cid = c._id;
ok(!hasId && cid, 'addChild调用child的getId方法');
ok(obj._children[cid] === c, 'addChild设置parent的_children属性');
ok(c._parent === obj, 'addChild设置child的_parent属性');
});
test('Composition.getChild', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
var cid = 'kampfer';
ok(obj.getChild(cid) == null, '');
c.setId(cid);
obj.addChild(c);
ok(obj.getChild(cid) === c, '');
});
test('Composition.eachChild', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
var c1 = new kampfer.mindMap.Composition();
var execed = false;
obj.eachChild(function(child, id) {
execed = true;
});
ok(!execed, 'parent没有child时,callback不执行');
obj.addChild(c);
obj.eachChild(function(child, id) {
if(obj.getChild(id) === child) {
execed = true;
}
});
ok(execed, 'callback接受两个参数第一个是child第二个是id');
obj.addChild(c1);
var execCount1 = 0;
obj.eachChild(function(child, id) {
execCount1++;
});
var execCount2 = 0;
obj.eachChild(function(child, id) {
execCount2++;
if(child === c) {
return false;
}
});
ok(execCount1 === 2 && execCount2 === 1, 'callback返回false会提前终止迭代');
});
test('Composition.removeChlid', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
var c1 = new kampfer.mindMap.Composition();
obj.addChild(c);
obj.removeChild(c._id);
ok( true, 'removeChild接受id字符串作为参数' );
ok( !obj.getChild(c._id), 'removeChild将parent的children[child.id]设置为null' );
ok( c.getParent() === null, 'removeChild将child的parnet设置为null' );
obj.addChild(c);
obj.removeChild(c);
if( !obj.getChild(c._id) && c.getParent() === null ) {
ok( true, 'removeChild也接受composition对象作为参数' );
}
obj.addChild(c);
obj.removeChild('kampfer');
obj.removeChild(c1);
ok(c._id in obj._children, '删除不存在child对parent不造成影响' );
});
//未测试有parent的情况
test('Composition.setId', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
obj.addChild(c);
var oldId = c._id;
c.setId('kampfer');
ok(c._id === 'kampfer', '修改child的id');
ok(obj.getChild('kampfer') === c, '修改parent中保存的child');
ok(!obj.getChild(oldId), 'parent中不再保留旧id');
});
test('Composition.getId', function() {
var obj = new kampfer.mindMap.Composition();
var hasId = !!obj._id;
ok( !hasId && obj.getId(), 'composition没有id的情况下调用getId将生成一个id');
obj = new kampfer.mindMap.Composition();
obj.setId('kampfer');
ok( obj.getId() === 'kampfer', 'composition有id时调用getId将直接返回id' );
});
test('Composition.dispose', function() {
var obj = new kampfer.mindMap.Composition();
var c = new kampfer.mindMap.Composition();
var p = new kampfer.mindMap.Composition();
//obj.setParent(p);
p.addChild(obj);
obj.addChild(c);
//console.log(obj);
var hasParent = !!obj._parent;
var hasChild = obj._children && obj._children[c._id];
obj.dispose();
ok( hasParent && !obj._parent, '_parent被释放');
ok( hasChild && !obj._children, '_children被释放');
console.log(obj);
});
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More