Commit 02cfffd3 authored by techird's avatar techird

Merge branch 'dev' into native-export

Conflicts:
	ui/doc.js
parents f33de2ea 9315bbcd
......@@ -8,6 +8,7 @@
"white": false,
"quotmark": false,
"browser": true,
"boss": true,
"predef" : [
"module",
"require",
......
# KityMinder 更新日志
## v1.3.2
### 功能更新
1. 支持全屏查看模式
2. 添加「视图」选项卡
3. 添加文件移动功能
4. 分享文件允许再次编辑
### 体验优化
1. 脑图加载时打开上次编辑的文件,而不是优先打开草稿箱
2. 修改展开按钮位置
## v1.3.1
### 功能更新
1. 添加了「展开全部节点」和「收起到一级节点」的菜单项
2. 添加了错误信息收集窗口
### BUG 修复
1. 缓存问题导致打开旧文件
2. 保存失败后草稿箱仍删除的问题
### 体验优化
1. 去除 alert,改用通知条来提示信息或错误
## v1.3.0
### 功能更新
......
......@@ -9,6 +9,18 @@ var path = require('path');
*-----------------------------------------------------*/
module.exports = function(grunt) {
// These plugins provide necessary tasks.
/* [Build plugin & task ] ------------------------------------*/
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-autoprefixer');
var banner = '/*!\n' +
' * ====================================================\n' +
' * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
......@@ -36,14 +48,8 @@ module.exports = function(grunt) {
options: {
banner: banner + '(function(window) {\n\n',
footer: '\n\n})(window)',
process: function(src, filepath) {
return ['\n',
'/* ' + filepath + ' */',
src.replace(/^.+$/mg, ' $&'),
'/* ' + filepath + ' end */',
'\n',
].join('\n');
}
sourceMap: true,
sourceMapStyle: 'link'
},
src: sources.filter(function(source) {
return source.pack == '*' || source.pack.split('|').indexOf(pack) !== -1;
......@@ -67,7 +73,8 @@ module.exports = function(grunt) {
uglify: {
minimize: {
options: {
banner: banner
banner: banner,
sourceMap: true
},
files: (function() {
var files = {};
......@@ -90,6 +97,7 @@ module.exports = function(grunt) {
'static/**/*',
'lib/ZeroClipboard.swf',
'lib/inflate.js',
'lib/source-map.min.js',
'index.html',
'edit.html',
'viewshare.html',
......@@ -135,41 +143,40 @@ module.exports = function(grunt) {
watch: {
less: {
files: ['ui/theme/**/*.less'],
tasks: ['less:compile']
tasks: ['less:compile', 'autoprefixer']
}
},
less: {
compile: {
files: {
'ui/theme/default/css/default.all.css': [
'ui/theme/default/css/default.all.temp.css': [
'ui/theme/default/css/import.less'
]
},
options: {
sourceMap: true,
sourceMapFilename: 'ui/theme/default/css/default.all.css.map',
sourceMapFilename: 'ui/theme/default/css/default.all.temp.css.map',
sourceMapBasepath: 'ui/theme/default/css/'
// compress: true,
// cleancss: true
}
}
},
autoprefixer: {
all: {
options: {
map: true
},
src: 'ui/theme/default/css/default.all.temp.css',
dest: 'ui/theme/default/css/default.all.css'
}
}
});
// These plugins provide necessary tasks.
/* [Build plugin & task ] ------------------------------------*/
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-text-replace');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
// Build task(s).
grunt.registerTask('default', ['clean', 'concat', 'uglify', 'less', 'copy', 'replace']);
grunt.registerTask('dev', ['less', 'watch']);
grunt.registerTask('default', ['clean', 'concat', 'uglify', 'less', 'autoprefixer', 'copy', 'replace']);
grunt.registerTask('dev', ['less', 'autoprefixer', 'watch']);
};
\ No newline at end of file
......@@ -12,43 +12,29 @@ KityMinder 基于 SVG 技术实现,支持绝大多数的主流浏览器,包
1. Chrome
2. Firefox
3. Safari
4. IE9+<sup>*</sup>
*: IE9 不支持部分导出功能。
4. Internet Explorer 10 或以上
## 线上版本
产品地址:[http://naotu.baidu.com](http://naotu.baidu.com)
注意:由于历史原因,有三个发布过的公开地址:
1. [~~http://fex-team.baidu.com/kityminder/dist~~](http://fex-team.baidu.com/kityminder/dist)
2. [~~http://kitygraph.github.io/kityminder/dist~~](http://kitygraph.github.io/kityminder/dist)
3. [http://fex.baidu.com/kityminder/dist](http://fex.baidu.com/kityminder/dist)
第 1 个地址已经失效;
第 2 个地址不再维护更新(原因是我们项目地址迁移到了 fex-team);
第 3 个地址是更新频率最高的地址,新功能可以在这里尝鲜;
[产品地址](http://naotu.baidu.com)已经稳定,请大家放心使用。地址变动频繁带来的不便,请谅解。
## 依赖说明
KityMinder 依赖 Kity 库。刚下载的压缩包或者刚从 github 拉下来的代码会有一个空的 Kity 目录。要运行调试,必须加载 Kity 的依赖
KityMinder 依赖 Kity、FIO、FUI 库。需要二次开发 KityMinder,需要先从 Github 上拉代码下来
1. 如果你下载的是 KityMinder 的压缩包,那么需要手动下载 [Kity](http://fex.baidu.com/kityminder/kity/dist/kity.js) 库到 kity/dist/kity.js
```bash
git clone https://github.com/fex-team/kityminder.git
```
2. 如果你是从 github 上拉源代码下来的,那么可以更新一下子模块:
紧接着,需要初始化并更新子模块:
```bash
cd YOUR_KITYMINDER_PATH
git submodule init
git submodule update
```
## 联系我们
问题和建议反馈:[Github Issues](https://github.com/fex-team/kityminder/issues/new)
邮件组: kity@baidu.com
讨论群: 374918234
QQ 讨论群: 374918234
......@@ -20,12 +20,20 @@ if (isset($_REQUEST['content'])) {
if (!$filename) {
$filename = "kikyminder";
}
if (isset($_REQUEST['iehack'])) {
$filename = urlencode($filename);
}
header("Content-type: application/octet-stream; charset=utf8; name=".urlencode($filename));
header("Accept-Length: ".strlen($content));
header("Content-Length: ".strlen($content));
header("Content-Disposition: attachment; filename=".urlencode($filename));
header("Content-Disposition: attachment; filename=".$filename);
header('Content-Description: File Transfer');
if (isset($_REQUEST['stamp'])) {
setcookie($_REQUEST['stamp'], 1, time() + 30);
}
echo $content;
} else {
......
......@@ -15,6 +15,7 @@
{ path: 'lib/jquery.blob.js', pack: 'edit' },
{ path: 'lib/zip.js', pack: 'edit' },
{ path: 'lib/ZeroClipboard.min.js', pack: 'edit' },
{ path: 'lib/qrcode.js', pack: 'edit' },
{ path: 'lib/fui/dev-lib/jhtmls.min.js', pack: 'edit|share|m-share' },
{ path: 'lib/fui/dist/fui.all.js', pack: 'edit|share|m-share' },
{ path: 'lib/fio/src/fio.js', pack: 'index|edit' },
......@@ -122,19 +123,22 @@
{ path: 'ui/memory.js', pack: 'edit|share|m-share' },
{ path: 'ui/fuix.js', pack: 'edit|share|m-share' },
{ path: 'ui/fiox.js', pack: 'edit' },
{ path: 'ui/doc.js', pack: 'edit|share|m-share' },
{ path: 'ui/contextmenu.js', pack: 'edit' },
/* UI 组件 */
{ path: 'ui/widget/commandbutton.js', pack: 'edit|share' },
{ path: 'ui/widget/commandbuttonset.js', pack: 'edit' },
{ path: 'ui/widget/commandinputmenu.js', pack: 'edit' },
{ path: 'ui/widget/commandselectmenu.js', pack: 'edit' },
{ path: 'ui/widget/notice.js', pack: 'edit|share|m-share' },
{ path: 'ui/widget/friendlytimespan.js', pack: 'edit' },
{ path: 'ui/widget/locallist.js', pack: 'edit' },
{ path: 'ui/widget/netdiskfinder.js', pack: 'edit' },
{ path: 'ui/widget/menutab.js', pack: 'edit|share|m-share' },
/* 基本业务 */
{ path: 'ui/doc.js', pack: 'edit|share|m-share' },
{ path: 'ui/contextmenu.js', pack: 'edit|share' },
/* 视野导航 */
{ path: 'ui/nav.js', pack: 'edit|share' },
......@@ -165,11 +169,13 @@
/* UI 菜单 - 帮助 */
{ path: 'ui/menu/help/help.js', pack: 'edit|share'},
{ path: 'ui/menu/help/feedback.js', pack: 'edit|share'},
/* UI Top Bar */
{ path: 'ui/topbar/quickvisit.js', pack: 'edit' },
{ path: 'ui/topbar/quickvisit.js', pack: 'edit|share' },
{ path: 'ui/topbar/history.js', pack: 'edit' },
{ path: 'ui/topbar/user.js', pack: 'edit' },
{ path: 'ui/topbar/feedback.js', pack: 'edit|share' },
{ path: 'ui/topbar/search.js', pack: 'edit|share' },
{ path: 'ui/topbar/switch-view.js', pack: 'm-share' },
{ path: 'ui/topbar/m-logo.js', pack: 'm-share' },
......@@ -198,6 +204,7 @@
{ path: 'ui/ribbon/appearence/color.js', pack: 'edit' },
/* UI Ribbon「视图」面板 */
{ path: 'ui/ribbon/view/fullscreen.js', pack: 'edit' },
{ path: 'ui/ribbon/view/level.js', pack: 'edit' }
];
......
......@@ -2,9 +2,9 @@
<html>
<head>
<meta charset="utf-8">
<meta name="title" content="百度脑图(KityMinder)">
<meta name="title" content="百度脑图(KityMinder) - 控制创意,如此简单">
<meta name="keyword" content="kityminder,脑图,思维导图,kity,svg,minder,百度,fex,前端,在线">
<meta name="description" content="百度脑图,便捷的脑图编辑工具。让您在线上直接创建、保存并分享你的思路。">
<meta name="description" content="百度脑图,便捷的脑图编辑工具 - 控制创意,如此简单。让您在线上直接创建、保存并分享你的思路。免安装 云存储 易分享 体验舒适 功能丰富">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<title>百度脑图 - 便捷的思维编辑工具</title>
......@@ -27,9 +27,21 @@
apiKey: 'wiE55BGOG8BkGnpPs6UNtPbb'
});
var $a = $('p.login a').hide();
function loadingAnimate(on) {
if (on) {
$('hr').addClass('loading');
loadingAnimate.timer = setTimeout(function() {
$('hr').addClass('animated');
}, 660);
} else {
clearTimeout(loadingAnimate.timer);
$('hr').removeClass('loading animated');
}
}
var $a = $('p.login a').hide();
loadingAnimate(true);
fio.user.check().then(function(user) {
if (user) {
......@@ -37,7 +49,7 @@
}
else {
$a.fadeIn(800);
$('hr').removeClass('loading');
loadingAnimate(false);
}
});
......@@ -46,9 +58,23 @@
urlparts.pop();
urlparts = urlparts.join('/');
fio.user.login({
redirectUrl: urlparts + '/edit.html'
redirectUrl: urlparts + '/edit.html',
remember: 7 * 24 * 60 * 60
});
$('hr').addClass('loading');
loadingAnimate(true);
});
function preload(url) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = resolve;
img.onerror = reject;
img.src = url;
});
}
preload('ui/theme/default/images/indexbackground.jpg').then(function() {
$('div.background').addClass('loaded');
});
});
......@@ -62,11 +88,36 @@
margin: 0;
padding: 0;
overflow: hidden;
-webkit-user-select: none;
height: 100%;
font-size: 0;
line-height: 0;
z-index: -2;
}
h1:before {
content: ' ';
body {
background: #99806B;
overflow: auto;
}
::-webkit-selection {
background: #FFEFEF;
color: #4A4F5D;
}
::-moz-selection {
background: #FFEFEF;
color: #4A4F5D;
}
::-ms-selection {
background: #FFEFEF;
color: #4A4F5D;
}
::selection {
background: #FFEFEF;
color: #4A4F5D;
}
div.background {
opacity: 0;
display: block;
background: url(ui/theme/default/images/indexbackground.jpg) no-repeat;
background-size: cover;
......@@ -82,9 +133,15 @@
-o-filter: blur(5px);
filter: url(ui/theme/default/images/blur.svg#blur);
filter: blur(5px);
-webkit-transition: opacity 1.5s ease;
transition: opacity 1.5s ease;
}
div.background.loaded {
opacity: 1;
}
h1:after {
h1:before {
content: ' ';
display: block;
position: absolute;
......@@ -92,7 +149,7 @@
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .75);
background: rgba(0, 0, 0, .5);
z-index: -1;
}
......@@ -106,34 +163,65 @@
h1 {
margin: 0;
margin-top: 200px;
margin-top: 100px;
color: white;
font-size: 50px;
line-height: 1.4em;
}
h1 span {
font-size: 0.6em;
}
p span {
font-size: 12px;
display: block;
margin-top: 30px;
color: rgba(255, 255, 255, .7);
text-shadow: 0 0 1px rgba(0, 0, 0, .5);
}
hr {
height: 0;
border: none;
border-bottom: 1px solid #F98183;
width: 110px;
margin: 40px auto;
transition: transform 0.5s ease;
-webkit-transition: -webkit-transform 0.66s ease;
transition: transform 0.66s ease;
-webkit-backface-visibility: hidden;
}
hr.loading {
-webkit-transform: translate3d(100px, 0, 0);
transform: translate3d(100px, 0, 0);
}
hr.animated {
-webkit-animation: slide 1.33s ease-in-out infinite alternate;
animation: slide 1.33s ease-in-out infinite alternate;
}
@-webkit-keyframes slide {
0% { transform: translate3d(-100px, 0, 0); }
100% { transform: translate3d(100px, 0, 0); }
0% {
-webkit-transform: translate3d(100px, 0, 0);
transform: translate3d(100px, 0, 0);
}
100% {
-webkit-transform: translate3d(-100px, 0, 0);
transform: translate3d(-100px, 0, 0);
}
}
@keyframes slide {
0% { transform: translate3d(-100px, 0, 0); }
100% { transform: translate3d(100px, 0, 0); }
0% {
-webkit-transform: translate3d(100px, 0, 0);
transform: translate3d(100px, 0, 0);
}
100% {
-webkit-transform: translate3d(-100px, 0, 0);
transform: translate3d(-100px, 0, 0);
}
}
p.description {
......@@ -157,10 +245,15 @@
position: relative;
overflow: hidden;
margin-top: 50px;
-webkit-user-select: none;
-moz-user-select: none;
-mz-user-select: none;
user-select: none;
}
p.login a:active {
background: #FF6161;
-webkit-transform: scale(0.95);
transform: scale(0.95);
}
......@@ -175,24 +268,29 @@
bottom: 0;
border-radius: 30px;
transform: scale(0, 1);
-webkit-transform: scale(0, 1);
transition: transform 0.3s ease;
-webkit-transition: -webkit-transform 0.3s ease;
}
p.login a:hover:before {
transform: scale(1, 1);
-webkit-transform: scale(1, 1);
}
</style>
</head>
<body>
<h1>百度脑图 <br/> 便捷的思维编辑工具</h1>
<div class="background"></div>
<h1>百度脑图 <br/> <span>控制创意,如此简单</span></h1>
<hr />
<p class="description">
线上直接创建、保存并分享您的思路<br />
更加高效地工作或学习
免安装 云存储 易分享<br/>
舒适的体验 丰富的功能<br/>
</p>
<p class="login">
<a>立即体验</a>
<a>马上开启</a>
<span>使用百度账号登录</span>
</p>
</body>
......
......@@ -25,7 +25,7 @@
maxImageWidth: 200,
maxImageHeight: 200,
// 自动保存时间间隔(s)
autoSave: 10
// 修改后自动保存时间间隔(单位:秒);设置为 false 不自动保存
autoSave: 2
};
})();
\ No newline at end of file
......@@ -40,15 +40,115 @@ KityMinder.LANG['zh-cn'] = {
'resource': '资源',
'attachment': '附件'
},
'error_message': {
'title': '哎呀,脑图出错了',
'err_load': '加载脑图失败',
'err_save': '保存脑图失败',
'err_network': '网络错误',
'err_doc_resolve': '文档解析失败',
'err_unknown': '发生了奇怪的错误',
'err_localfile_read': '文件读取错误',
'err_download': '文件下载失败',
'err_remove_share': '取消分享失败',
'err_create_share': '分享失败',
'err_mkdir': '目录创建失败',
'err_ls': '读取目录失败',
'err_share_data': '加载分享内容出错',
'err_share_sync_fail': '分享内容同步失败',
'err_move_file': '文件移动失败',
'unknownreason': '可能是外星人篡改了代码...',
'pcs_code': {
3: "不支持此接口",
4: "没有权限执行此操作",
5: "IP未授权",
110: "用户会话已过期,请重新登录",
31001: "数据库查询错误",
31002: "数据库连接错误",
31003: "数据库返回空结果",
31021: "网络错误",
31022: "暂时无法连接服务器",
31023: "输入参数错误",
31024: "app id为空",
31025: "后端存储错误",
31041: "用户的cookie不是合法的百度cookie",
31042: "用户未登陆",
31043: "用户未激活",
31044: "用户未授权",
31045: "用户不存在",
31046: "用户已经存在",
31061: "文件已经存在",
31062: "文件名非法",
31063: "文件父目录不存在",
31064: "无权访问此文件",
31065: "目录已满",
31066: "文件不存在",
31067: "文件处理出错",
31068: "文件创建失败",
31069: "文件拷贝失败",
31070: "文件删除失败",
31071: "不能读取文件元信息",
31072: "文件移动失败",
31073: "文件重命名失败",
31079: "未找到文件MD5,请使用上传API上传整个文件。",
31081: "superfile创建失败",
31082: "superfile 块列表为空",
31083: "superfile 更新失败",
31101: "tag系统内部错误",
31102: "tag参数错误",
31103: "tag系统错误",
31110: "未授权设置此目录配额",
31111: "配额管理只支持两级目录",
31112: "超出配额",
31113: "配额不能超出目录祖先的配额",
31114: "配额不能比子目录配额小",
31141: "请求缩略图服务失败",
31201: "签名错误",
31202: "文件不存在",
31203: "设置acl失败",
31204: "请求acl验证失败",
31205: "获取acl失败",
31206: "acl不存在",
31207: "bucket已存在",
31208: "用户请求错误",
31209: "服务器错误",
31210: "服务器不支持",
31211: "禁止访问",
31212: "服务不可用",
31213: "重试出错",
31214: "上传文件data失败",
31215: "上传文件meta失败",
31216: "下载文件data失败",
31217: "下载文件meta失败",
31218: "容量超出限额",
31219: "请求数超出限额",
31220: "流量超出限额",
31298: "服务器返回值KEY非法",
31299: "服务器返回值KEY不存在"
}
},
'ui': {
'load_share_for_edit': '正在加载分享的文件...',
'share_sync_success': '分享内容已同步',
'fullscreen_exit_hint': '按 Esc 或 F11 退出全屏',
'error_detail': '详细信息',
'copy_and_feedback': '复制并反馈',
'move_file_confirm': '确定把 "{0}" 移动到 "{1}" 吗?',
'command': {
'appendsiblingnode': '新建兄弟节点',
'appendchildnode': '新建子节点',
'appendsiblingnode': '插入同级主题',
'appendchildnode': '插入下级主题',
'removenode': '删除',
'editnode': '编辑',
'arrangeup': '上移',
'arrangedown': '下移',
'resetlayout': '整理布局'
'resetlayout': '整理布局',
'expandtoleaf': '展开全部节点',
'collapsetolevel1': '收起到一级节点',
'fullscreen': '全屏'
},
'back': '返回',
......@@ -65,7 +165,9 @@ KityMinder.LANG['zh-cn'] = {
'quickvisit': {
'new': '新建 (Ctrl + Alt + N)',
'save': '保存 (Ctrl + S)',
'share': '分享 (Ctrl + Alt + S)'
'share': '分享 (Ctrl + Alt + S)',
'feedback': '反馈问题(F1)',
'editshare': '编辑'
},
'menu': {
......@@ -78,6 +180,7 @@ KityMinder.LANG['zh-cn'] = {
'sharetab': '分享',
'preferencetab': '设置',
'helptab': '帮助',
'feedbacktab': '反馈',
'recenttab': '最近使用',
'netdisktab': '百度云存储',
'localtab': '本地文件',
......@@ -93,7 +196,8 @@ KityMinder.LANG['zh-cn'] = {
'shareheader': '分享我的脑图',
'downloadheader': '导出到指定格式',
'preferenceheader': '偏好设置',
'helpheader': '帮助'
'helpheader': '帮助',
'feedbackheader': '反馈'
},
'mydocument': '我的文档',
......@@ -103,8 +207,6 @@ KityMinder.LANG['zh-cn'] = {
'dropfile': '或将文件拖至此处',
'unsupportedfile': '不支持的文件格式',
'untitleddoc': '未命名文档',
'errorloading': '加载失败:{0}',
'unknownreason': '可能是外星人篡改了代码...',
'overrideconfirm': '{0} 已存在,确认覆盖吗?',
'checklogin': '检查登录状态中...',
'loggingin': '正在登录...',
......@@ -120,7 +222,7 @@ KityMinder.LANG['zh-cn'] = {
'email_share': '邮件邀请',
'url_share': '脑图 URL 地址:',
'sns_share': '社交网络分享:',
'sns_share_text': '“{0}” - 我用「百度脑图」制作的思维导图,快看看吧!(地址:{1})',
'sns_share_text': '“{0}” - 我用百度脑图制作的思维导图,快看看吧!(地址:{1})',
'none_share_description': '不分享当前脑图',
'public_share_description': '创建任何人可见的分享',
'share_button_text': '创建',
......@@ -149,6 +251,7 @@ KityMinder.LANG['zh-cn'] = {
'fileformat': '保存格式',
'save': '保存',
'mkdir': '新建目录',
'recycle': '回收站',
'newdir': '未命名目录',
'bold': '加粗',
......@@ -161,8 +264,8 @@ KityMinder.LANG['zh-cn'] = {
'saveto': '另存为',
'hand': '允许拖拽',
'camera': '定位根节点',
'zoom-in': '放大',
'zoom-out': '缩小',
'zoom-in': '放大(Ctrl+)',
'zoom-out': '缩小(Ctrl-)',
'markers': '标签',
'resource': '资源',
'help': '帮助',
......@@ -174,8 +277,8 @@ KityMinder.LANG['zh-cn'] = {
'clearstyle': '清除样式',
'copystyle': '复制样式',
'pastestyle': '粘贴样式',
'appendsiblingnode': '下一主题',
'appendchildnode': '儿子主题',
'appendsiblingnode': '同级主题',
'appendchildnode': '下级主题',
'arrangeup': '前调',
'arrangedown': '后调',
'editnode': '编辑',
......@@ -209,12 +312,20 @@ KityMinder.LANG['zh-cn'] = {
'redirect': '您正在打开连接 {0},百度脑图不能保证连接的安全性,是否要继续?',
'navigator': '导航器',
'unsavedcontent': '当前文件还没有保存到网盘:\n\n{0}\n\n确定要继续操作么?(未保存的数据会缓存在草稿箱)',
'unsavedcontent': '当前文件还没有保存到网盘:\n\n{0}\n\n虽然未保存的数据会缓存在草稿箱,但是清除浏览器缓存会导致草稿箱清除。',
'shortcuts': '快捷键',
'contact': '联系我们',
'contact': '联系与反馈',
'email': '邮件组',
'qq_group': 'QQ 群'
'qq_group': 'QQ 群',
'github_issue': 'Github',
'baidu_tieba': '贴吧',
'clipboardunsupported': '您的浏览器不支持剪贴板,请使用快捷键复制',
'load_success': '<b>{0}</b> 加载成功',
'save_success': '<b>{0}</b> 已保存于 {1}',
'autosave_success': '<b>{0}</b> 已自动保存于 {1}'
},
'popupcolor': {
'clearColor': '清空颜色',
......
This diff is collapsed.
No preview for this file type
Copyright (c) 2010-2011 Gabe Lerner (gabelerner@gmail.com) - http://code.google.com/p/canvg/
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com>
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it
*/
function RGBColor(color_string)
{
this.ok = false;
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1,6);
}
color_string = color_string.replace(/ /g,'');
color_string = color_string.toLowerCase();
// before getting into regexps, try simple matches
// and overwrite the input
var simple_colors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred : 'cd5c5c',
indigo : '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
for (var key in simple_colors) {
if (color_string == key) {
color_string = simple_colors[key];
}
}
// emd of simple type-in colors
// array of color definition objects
var color_defs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits){
return [
parseInt(bits[1]),
parseInt(bits[2]),
parseInt(bits[3])
];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process: function (bits){
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process: function (bits){
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
// search through the definitions to find a match
for (var i = 0; i < color_defs.length; i++) {
var re = color_defs[i].re;
var processor = color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
// some getters
this.toRGB = function () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}
this.toHex = function () {
var r = this.r.toString(16);
var g = this.g.toString(16);
var b = this.b.toString(16);
if (r.length == 1) r = '0' + r;
if (g.length == 1) g = '0' + g;
if (b.length == 1) b = '0' + b;
return '#' + r + g + b;
}
// help
this.getHelpXML = function () {
var examples = new Array();
// add regexps
for (var i = 0; i < color_defs.length; i++) {
var example = color_defs[i].example;
for (var j = 0; j < example.length; j++) {
examples[examples.length] = example[j];
}
}
// add type-in colors
for (var sc in simple_colors) {
examples[examples.length] = sc;
}
var xml = document.createElement('ul');
xml.setAttribute('id', 'rgbcolor-examples');
for (var i = 0; i < examples.length; i++) {
try {
var list_item = document.createElement('li');
var list_color = new RGBColor(examples[i]);
var example_div = document.createElement('div');
example_div.style.cssText =
'margin: 3px; '
+ 'border: 1px solid black; '
+ 'background:' + list_color.toHex() + '; '
+ 'color:' + list_color.toHex()
;
example_div.appendChild(document.createTextNode('test'));
var list_item_value = document.createTextNode(
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
);
list_item.appendChild(example_div);
list_item.appendChild(list_item_value);
xml.appendChild(list_item);
} catch(e){}
}
return xml;
}
}
Subproject commit a830f3ce3dc62a8f4cf64611045f51453a9095ac
Subproject commit 43cc299309c7ec3a1c0c91cb890ba9b0907a1053
Subproject commit 2100743a23276853658906608e093d1227739084
Subproject commit 5abfcd8d5ece0bcece486dec435288ec7bcd281d
......@@ -269,7 +269,8 @@ define("promise/polyfill",
return isFunction(resolve);
}());
if (!es6PromiseSupport || ~window.location.href.indexOf('rsvpromise')) {
// !es6PromiseSupport || ~window.location.href.indexOf('rsvpromise')
if (true) {
local.Promise = RSVPPromise;
}
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -723,7 +723,6 @@
entriesCallback(dataView);
}
}catch(e){
console.log(e);
onerror(ERR_READ);
}
......
......@@ -2,7 +2,7 @@
"name": "kityminder",
"title": "kityminder",
"description": "Kity Minder",
"version": "1.3.0",
"version": "1.3.1",
"homepage": "https://github.com/fex-team/kityminder",
"author": {
"name": "f-cube @ FEX",
......@@ -30,13 +30,14 @@
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-uglify": "~0.2.6",
"grunt-contrib-concat": "~0.5.0",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-text-replace": "~0.3.9",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-less": "~0.11.3",
"grunt-contrib-clean": "~0.6.0"
"grunt-contrib-clean": "~0.6.0",
"grunt-autoprefixer": "~1.0.1"
}
}
\ No newline at end of file
......@@ -24,13 +24,13 @@ KityMinder.registerConnectProvider('under', function(node, parent, connection, w
var p1, p2, p3, mx;
if (side == 'right') {
p1 = new kity.Point(pBox.right + 10, startY);
p2 = new kity.Point(box.left, underY);
p3 = new kity.Point(box.right + 10, underY);
p1 = new kity.Point(pBox.right, startY);
p2 = new kity.Point(box.left - 10, underY);
p3 = new kity.Point(box.right, underY);
} else {
p1 = new kity.Point(pBox.left - 10, startY);
p2 = new kity.Point(box.right, underY);
p3 = new kity.Point(box.left - 10, underY);
p1 = new kity.Point(pBox.left, startY);
p2 = new kity.Point(box.right + 10, underY);
p3 = new kity.Point(box.left, underY);
}
mx = (p1.x + p2.x) / 2;
......
......@@ -13,7 +13,12 @@ Utils.extend(KityMinder, {
/* 脑图数据升级 */
function c_120_130(json) {
traverse(json, function(node) {
var data = node.data;
delete data.layout_bottom_offset;
delete data.layout_default_offset;
delete data.layout_filetree_offset;
});
}
/**
......@@ -57,6 +62,8 @@ Utils.extend(KityMinder, {
case '1.1.3':
c_113_120(json);
case '1.2.0':
case '1.2.1':
c_120_130(json);
}
return json;
......
......@@ -20,7 +20,9 @@ var MinderEvent = kity.createClass('MindEvent', {
while (!findShape.minderNode && findShape.container) {
findShape = findShape.container;
}
return findShape.minderNode || null;
var node = findShape.minderNode;
if (node && findShape.getOpacity() < 1) return null;
return node || null;
},
stopPropagation: function() {
......@@ -78,17 +80,11 @@ kity.extendClass(Minder, {
},
// TODO: mousemove lazy bind
_bindPaperEvents: function() {
this._paper.on('click dblclick keydown keyup keypress paste mousedown contextmenu mouseup mousemove mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
this._paper.on('click dblclick mousedown contextmenu mouseup mousemove mouseover mousewheel DOMMouseScroll touchstart touchmove touchend dragenter dragleave drop', this._firePharse.bind(this));
if (window) {
window.addEventListener('resize', this._firePharse.bind(this));
window.addEventListener('blur', this._firePharse.bind(this));
}
this._renderTarget.onfocus = function() {
console.log('focus');
};
this._renderTarget.onblur = function() {
console.log('blur');
};
},
_bindKeyboardEvents: function() {
if ((navigator.userAgent.indexOf('iPhone') == -1) && (navigator.userAgent.indexOf('iPod') == -1) && (navigator.userAgent.indexOf('iPad') == -1)) {
......@@ -157,8 +153,8 @@ kity.extendClass(Minder, {
callbacks[i].call(this, e);
if (this.getStatus() != lastStatus || e.shouldStopPropagationImmediately()) {
/* this.getStatus() != lastStatus ||*/
if (e.shouldStopPropagationImmediately()) {
break;
}
}
......
......@@ -9,9 +9,17 @@ var keymap = KityMinder.keymap = (function(origin) {
var aKeyCode = 65;
var aCharCode = 'a'.charCodeAt(0);
// letters
'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
ret[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
});
// numbers
var n = 9;
do {
ret[n.toString()] = n + 48;
} while(--n);
return ret;
})({
'Backspace': 8,
......@@ -32,6 +40,7 @@ var keymap = KityMinder.keymap = (function(origin) {
'End': 35,
'Home': 36,
'Insert': 45,
'Left': 37,
'Up': 38,
......@@ -44,7 +53,6 @@ var keymap = KityMinder.keymap = (function(origin) {
39: 1,
40: 1
},
'Insert': 45,
'Del': 46,
......@@ -52,10 +60,20 @@ var keymap = KityMinder.keymap = (function(origin) {
'Cmd': 91,
'CmdFF': 224,
'F1': 112,
'F2': 113,
'F3': 114,
'F4': 115,
'F5': 116,
'F6': 117,
'F7': 118,
'F8': 119,
'F9': 120,
'F10': 121,
'F11': 122,
'F12': 123,
'`': 192,
'=': 187,
'-': 189,
......
......@@ -3,7 +3,7 @@ var KityMinder = window.KM = window.KityMinder = function() {
instanceId = 0,
uuidMap = {};
return {
version: '1.3.0',
version: '1.3.1',
uuid: function(name) {
name = name || 'unknown';
uuidMap[name] = uuidMap[name] || 0;
......
......@@ -243,7 +243,7 @@ kity.extendClass(Minder, {
// layout all children first
// 剪枝:收起的节点无需计算
if (node.isExpanded()) {
if (node.isExpanded() || true) {
node.children.forEach(function(child) {
layoutNode(child);
});
......@@ -296,7 +296,7 @@ kity.extendClass(Minder, {
}
// 节点复杂度大于 100,关闭动画
if (complex > 300) duration = 0;
if (complex > 200) duration = 0;
function applyMatrix(node, matrix) {
node.setGlobalLayoutTransform(matrix);
......@@ -330,14 +330,14 @@ kity.extendClass(Minder, {
.start(node, duration, 'ease')
.on('finish', function() {
//可能性能低的时候会丢帧,手动添加一帧
kity.Timeline.requestFrame(function() {
setTimeout(function() {
applyMatrix(node, matrix);
me.fire('layoutfinish', {
node: node,
matrix: matrix
});
consume();
});
}, 150);
});
}
......@@ -561,7 +561,9 @@ var ResetLayoutCommand = kity.createClass('ResetLayoutCommand', {
});
});
minder.layout(300);
}
},
enableReadOnly: true
});
KityMinder.registerModule('LayoutModule', {
......
......@@ -46,6 +46,8 @@ kity.extendClass(Minder, {
}
this._modules[name] = moduleDeals;
if (!moduleDeals) continue;
if (moduleDeals.init) {
moduleDeals.init.call(me, this._options);
}
......
......@@ -20,14 +20,14 @@ kity.extendClass(Minder, {
me.bkqueryCommandValue = me.queryCommandValue;
me.queryCommandState = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
if (cmd && cmd.enableReadOnly) {
return me.bkqueryCommandState.apply(me, arguments);
}
return -1;
};
me.queryCommandValue = function(type) {
var cmd = this._getCommand(type);
if (cmd && cmd.enableReadOnly === false) {
if (cmd && cmd.enableReadOnly) {
return me.bkqueryCommandValue.apply(me, arguments);
}
return null;
......@@ -48,7 +48,7 @@ kity.extendClass(Minder, {
delete me.bkqueryCommandValue;
}
this.rollbackStatus();
this.setStatus('normal');
me._interactChange();
}
......
......@@ -22,7 +22,9 @@ kity.extendClass(Minder, {
var sf = ~window.location.href.indexOf('status');
var tf = ~window.location.href.indexOf('trace');
return function(status) {
// 在 readonly 模式下,只有 force 为 true 才能切换回来
return function(status, force) {
if (this._status == 'readonly' && !force) return this;
if (status != this._status) {
this._rollbackStatus = this._status;
this._status = status;
......
......@@ -17,7 +17,7 @@ kity.extendClass(Minder, (function() {
},
getTemplate: function() {
return this._template || null;
return this._template || 'default';
},
setTemplate: function(name) {
......@@ -25,7 +25,7 @@ kity.extendClass(Minder, (function() {
},
getTemplateSupport: function(method) {
var supports = KityMinder._templates[this._template];
var supports = KityMinder._templates[this.getTemplate()];
return supports && supports[method];
},
......
......@@ -57,6 +57,9 @@ kity.extendClass(Minder, {
setTheme: function(name) {
this._theme = name || null;
this.getRenderTarget().style.background = this.getStyle('background');
this.fire('themechange', {
theme: name
});
},
/**
......
......@@ -79,10 +79,6 @@ layouts.forEach(function(name) {
doLayout: function(parent, children) {
if (!children.length) {
return false;
}
var pbox = parent.getContentBox();
if (axis == 'x') {
......@@ -93,6 +89,10 @@ layouts.forEach(function(name) {
parent.setLayoutVectorOut(new kity.Vector(0, dir));
}
if (!children.length) {
return false;
}
children.forEach(function(child) {
var cbox = child.getContentBox();
child.setLayoutTransform(new kity.Matrix());
......
......@@ -4,9 +4,14 @@ KityMinder.registerLayout('mind', kity.createClass({
doLayout: function(node, children) {
var layout = this;
var half = Math.ceil(children.length / 2);
var right = children.slice(0, half);
var left = children.slice(half);
var half = Math.ceil(node.children.length / 2);
var right = [];
var left = [];
children.forEach(function(child) {
if (child.getIndex() < half) right.push(child);
else left.push(child);
});
var leftLayout = KityMinder.getLayoutInstance('left');
var rightLayout = KityMinder.getLayoutInstance('right');
......
......@@ -38,6 +38,8 @@ KityMinder.registerModule( "ClipboardModule", function () {
execute: function(km) {
var ancestors = km.getSelectedAncestors();
if (ancestors.length === 0) return;
sendToClipboard(ancestors);
km.select(MinderNode.getCommonAncestor(ancestors), true);
......
......@@ -16,9 +16,13 @@ KityMinder.registerModule('TextEditModule', function() {
//当前是否有选区存在
var selectionReadyShow = false;
var mousedownNode,mouseupTimer,mousedownTimer;
var lastMinderNode;
function inputStatusReady(node){
if (node && km.isSingleSelect() && node.isSelected()) {
node.getTextGroup().setStyle('cursor','default');
var color = node.getStyle('text-selection-color');
......@@ -66,6 +70,7 @@ KityMinder.registerModule('TextEditModule', function() {
'normal.beforemousedown textedit.beforemousedown inputready.beforemousedown': function(e) {
//右键直接退出
if (e.isRightMB()) {
if (!e.getTargetNode()) this.setStatus('normal');
return;
}
......@@ -91,9 +96,13 @@ KityMinder.registerModule('TextEditModule', function() {
if(node){
if (this.isSingleSelect() && node.isSelected()) {
lastMinderNode = node;
mousedownNode = node;
var textGroup = node.getTextGroup();
textGroup.setStyle('cursor', 'default');
sel.collapse(true);
sel.setColor(node.getStyle('text-selection-color'));
......@@ -103,17 +112,24 @@ KityMinder.registerModule('TextEditModule', function() {
.setRange(range)
.setReady();
if(selectionReadyShow){
textGroup.setStyle('cursor', 'text');
sel.setShowStatus();
setTimeout(function() {
clearTimeout(mousedownTimer);
mousedownTimer = setTimeout(function() {
if(dblclickEvent){
dblclickEvent = false;
return;
}
sel.collapse(true)
.updatePosition(receiver.getOffsetByIndex())
.setShow();
}, 200);
textGroup.setStyle('cursor','text');
},200);
km.setStatus('textedit');
}
......@@ -127,6 +143,12 @@ KityMinder.registerModule('TextEditModule', function() {
//当点击空白处时,光标需要消失
receiver.clear();
if(lastMinderNode){
lastMinderNode.getTextGroup().setStyle('cursor','default');
}
},
'inputready.keyup':function(){
if(sel.isHide()){
......@@ -158,6 +180,7 @@ KityMinder.registerModule('TextEditModule', function() {
var node = e.getTargetNode();
mousedownNode = null;
if (node && !selectionReadyShow && receiver.isReady()) {
......@@ -169,8 +192,8 @@ KityMinder.registerModule('TextEditModule', function() {
if(browser.ipad){
receiver.focus();
}
setTimeout(function() {
clearTimeout(mouseupTimer);
mouseupTimer = setTimeout(function() {
if(dblclickEvent){
dblclickEvent = false;
return;
......@@ -178,6 +201,7 @@ KityMinder.registerModule('TextEditModule', function() {
sel.collapse(true)
.updatePosition(receiver.getOffsetByIndex())
.setShow();
node.getTextGroup().setStyle('cursor','text');
}, 200);
......@@ -193,8 +217,6 @@ KityMinder.registerModule('TextEditModule', function() {
if(!sel.collapsed){
receiver.updateContainerRangeBySel();
}
}
......@@ -208,11 +230,13 @@ KityMinder.registerModule('TextEditModule', function() {
}
//ipad下不做框选
if (mouseDownStatus && receiver.isReady() && selectionReadyShow) {
var node = e.getTargetNode();
e.stopPropagationImmediately();
if(node){
var offset = e.getPosition(node.getRenderContainer());
if(mousedownNode){
var offset = e.getPosition( mousedownNode.getRenderContainer());
receiver
.updateSelectionByMousePosition(offset)
......@@ -234,10 +258,10 @@ KityMinder.registerModule('TextEditModule', function() {
'normal.dblclick textedit.dblclick inputready.dblclick': function(e) {
var node = e.getTargetNode();
dblclickEvent = true;
if(node){
//跟mouseup的timeout有冲突,这里做标记处理
dblclickEvent = true;
inputStatusReady(node);
......
......@@ -53,7 +53,7 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
this._keyup(e);
}
},
_setTextToContainer : function(keyCode){
_setTextToContainer : function(keyCode,iskeyUp){
var me = this;
//同步节点
me.minderNode = me.re.minderNode;
......@@ -65,7 +65,7 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
}
if(keymap.controlKeys[keyCode]){
if(keymap.controlKeys[keyCode] && !iskeyUp ){
return;
}
//当第一次输入内容时进行保存
......@@ -95,17 +95,23 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
me.inputTextTimer = setTimeout(function(){
me.km.layout(300);
},250);
},300);
}
me.re.updateTextOffsetData()
.updateRange()
.updateSelectionByRange();
me.selection
.updateOffsetByTextData(me.re.textData)
.updatePosition()
.setHoldShow();
.updatePosition();
//当然inputready状态时,如果输入文字,节点内文本会被先选中然后再消失,体验不好
if(me.km.getStatus() != 'inputready'){
me.selection.setHoldShow();
}
me.timer = setTimeout(function() {
......@@ -134,12 +140,13 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
switch (keyCode) {
case keymap.Enter:
if(e.originEvent.shiftKey){
if(e.originEvent.shiftKey && me.selection.isShow()){
me._handlerEnterkey();
e.preventDefault();
return false;
};
case keymap.Tab:
case keymap.Insert:
if(this.selection.isShow()){
this.re.clear();
this.km.setStatus('inputready');
......@@ -159,6 +166,7 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
case keymap.Del:
case keymap['/']:
case keymap.F2:
case keymap.Insert:
if(this.selection.isHide()){
this.km.setStatus('normal');
return;
......@@ -186,7 +194,6 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
//修正在cvs方式下_keyup会把节点文字选中
this.isShortcutCopyKey = true;
this.km.setStatus('normal');
return;
}
......@@ -228,11 +235,12 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
this.isShortcutCopyKey = false;
//针对不能连续删除做处理
if(keymap.Del == keyCode || keymap.Backspace == keyCode)
//if(keymap.Del == keyCode || keymap.Backspace == keyCode)
// me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode);
},
_beforeKeyup:function(e){
var me = this;
var orgEvt = e.originEvent;
var keyCode = orgEvt.keyCode;
......@@ -240,6 +248,7 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
switch (keyCode) {
case keymap.Enter:
case keymap.Tab:
case keymap.Insert:
case keymap.F2:
if(browser.ipad){
if(this.selection.isShow()){
......@@ -255,7 +264,7 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
}
if (keymap.Enter == keyCode && (this.isTypeText || browser.mac && browser.gecko)) {
me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode,true);
}
if (this.re.keydownNode === this.re.minderNode) {
this.km.rollbackStatus();
......@@ -273,19 +282,20 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
}
}
me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode,true);
return;
}
if (this.isTypeText) {
me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode,true);
return;
}
if (browser.mac && browser.gecko){
me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode,true);
return;
}
me._setTextToContainer(keyCode);
me._setTextToContainer(keyCode,true);
return true;
},
......@@ -296,7 +306,6 @@ Minder.keyboarder = kity.createClass('keyboarder', function(){
if(this.km.getStatus() == 'normal' && node && this.selection.isHide()){
if(this.isShortcutCopyKey){
console.log(this.km.getStatus())
return;
}
......
......@@ -7,7 +7,12 @@ Minder.Range = kity.createClass('Range',function(){
if(node.nodeType == 1){
//默认不会出现得不到子节点的情况
node = node.childNodes[offset];
if(node.nodeType == 3){
if(!node && rng.startContainer && rng.startContainer.nodeName == 'DIV' ) {
rng.startContainer.innerHTML = '<p></p>';
offset = 0;
}else if(node.nodeType == 3){
offset = 0;
}
}
......
......@@ -220,7 +220,7 @@ Minder.Receiver = kity.createClass('Receiver', {
this.selection.setHeight((this.minderNode.getData('font-size') || this.minderNode.getStyle('font-size')) * 1);
return this;
},
updateSelectionByMousePosition: function(offset,dir) {
updateSelectionByMousePosition: function(offset) {
var me = this;
var result = 0;
......@@ -240,7 +240,6 @@ Minder.Receiver = kity.createClass('Receiver', {
result += i;
if (offset.x - v.x > v.width / 2) {
result += 1;
}
......@@ -257,6 +256,13 @@ Minder.Receiver = kity.createClass('Receiver', {
return false;
}else{
if(first.y > offset.y && l === 0){
result = 0;
return false;
}else if(l == me.textData.length - 1 && first.y + lineHeight < offset.y){
result += arr.length + 1;
return false;
}
result += arr.length + (arr.length == 1 && arr[0].width === 0 ? 0 : 1);
return;
}
......
//模拟光标
Minder.Selection = kity.createClass( 'Selection', {
base: kity.Group,
base: kity.Path,
constructor: function ( height, color, width ) {
this.callBase();
this.height = height || 20;
......@@ -15,7 +15,7 @@ Minder.Selection = kity.createClass( 'Selection', {
this.setStyle('cursor','text');
this._show = false;
this.offset = [];
this.setTranslate(-0.5, -1.5);
},
setMinderNode : function(node){
this.minderNode = node;
......@@ -45,7 +45,8 @@ Minder.Selection = kity.createClass( 'Selection', {
if(i === 0 || cIndex === startOffset){
tmpOffset.x = o.x;
tmpOffset.y = o.y;
tmpOffset.width = i === 0 && offset && offset.x <= o.x && cIndex != startOffset ? 0 : o.width;
tmpOffset.width = o.width;
//i === 0 && offset && offset.x <= o.x && cIndex != startOffset ? 0 :
}else if(cIndex < endOffset){
tmpOffset.width += o.width;
}else if(cIndex === endOffset){
......@@ -54,7 +55,6 @@ Minder.Selection = kity.createClass( 'Selection', {
}
cIndex++;
});
if(tmpOffset.x !== undefined) {
arrOffset.push(tmpOffset);
......@@ -73,21 +73,31 @@ Minder.Selection = kity.createClass( 'Selection', {
}
this._show = true;
},
updatePosition:function(offset){
updatePosition: function(offset){
var me = this;
this.clear();
offset = offset || this.offset;
if(this.collapsed){
var r = Math.round;
var rect = new kity.Rect().fill(null).stroke(null).setWidth(2).setHeight(this.height);
rect.setPosition(Math.round(offset.x) - 0.5,Math.round(offset.y) - 1.5);
this.addShape(rect);
}else{
utils.each(offset,function(i,v){
var rect = new kity.Rect().fill(null).stroke(null).setWidth(v.width).setHeight(me.height);
rect.setPosition(Math.round(v.x) - 0.5,Math.round(v.y) - 1.5);
me.addShape(rect);
});
var rect = function (x, y, w, h) {
return ['M', r(x), r(y),
'h', r(w),
'v', r(h),
'h', -r(w),
'v', -r(h),
'z'];
};
offset = offset !== undefined ? offset : this.offset;
if(this.collapsed){
if (isNaN(offset.x) || isNaN(offset.y)) {
if (console) console.warn('editor.selection.js 不正确的偏移位置');
return this;
}
this.setPathData(rect(offset.x, offset.y, this.width, this.height));
} else {
this.setPathData(offset.reduce(function (prev, current) {
return prev.concat(rect(current.x, current.y, current.width, me.height));
}, []));
}
this._show = true;
return this;
......
......@@ -76,6 +76,10 @@ KityMinder.registerModule('Expand', function() {
if (!changed) return;
node.renderTree().getMinder().layout(100);
/* 如何加展开效果:
var vo = node.getVertexOut();
if (state == STATE_EXPAND) {
......@@ -99,6 +103,7 @@ KityMinder.registerModule('Expand', function() {
});
}
*/
}
// 将展开的操作和状态读取接口拓展到 MinderNode 上
......@@ -146,7 +151,7 @@ KityMinder.registerModule('Expand', function() {
});
},
queryState: function(km) {
return 0;
return !km.getSelectedNode() ? 0 : -1;
}
});
var CollapseNodeCommand = kity.createClass('CollapseNodeCommand', {
......@@ -158,7 +163,7 @@ KityMinder.registerModule('Expand', function() {
});
},
queryState: function(km) {
return 0;
return !km.getSelectedNode() ? 0 : -1;
}
});
var Expander = kity.createClass('Expander', {
......@@ -166,9 +171,9 @@ KityMinder.registerModule('Expand', function() {
constructor: function(node) {
this.callBase();
this.radius = 5;
this.radius = 6;
this.outline = new kity.Circle(this.radius).stroke('gray').fill('white');
this.sign = new kity.Path().stroke('black');
this.sign = new kity.Path().stroke('gray');
this.addShapes([this.outline, this.sign]);
this.initEvent(node);
this.setId(KityMinder.uuid('node_expander'));
......@@ -228,16 +233,16 @@ KityMinder.registerModule('Expand', function() {
expander.setState(visible && node.children.length ? node.getData(EXPAND_STATE_DATA) : 'hide');
var vector = node.getLayoutVectorOut().normalize(expander.radius + node.getStyle('stroke-width'));
var position = node.getVertexOut().offset(vector);
var vector = node.getLayoutVectorIn().normalize(expander.radius + node.getStyle('stroke-width'));
var position = node.getVertexIn().offset(vector.reverse());
this.expander.setTranslate(position);
}
});
return {
commands: {
'ExpandNode': ExpandNodeCommand,
'CollapseNode': CollapseNodeCommand
'expandtoleaf': ExpandNodeCommand,
'collapsetolevel1': CollapseNodeCommand
},
events: {
'layoutapply': function(e) {
......@@ -271,6 +276,17 @@ KityMinder.registerModule('Expand', function() {
},
renderers: {
outside: ExpanderRenderer
},
contextmenu: [{
command: 'expandtoleaf'
}, {
command: 'collapsetolevel1'
}, {
divider: true
}],
commandShortcutKeys: {
'expandtoleaf': 'Alt+`',
'collapsetolevel1': 'Alt+1'
}
};
});
\ No newline at end of file
......@@ -5,10 +5,11 @@ KityMinder.registerModule("hyperlink", function() {
"hyperlink": kity.createClass("hyperlink", {
base: Command,
execute: function(km, url) {
execute: function(km, url, title) {
var nodes = km.getSelectedNodes();
utils.each(nodes, function(i, n) {
n.setData('hyperlink', url);
n.setData('hyperlinkTitle', title);
n.render();
});
km.layout();
......@@ -29,7 +30,10 @@ KityMinder.registerModule("hyperlink", function() {
},
queryValue: function(km) {
var node = km.getSelectedNode();
return node.getData('hyperlink');
return {
url: node.getData('hyperlink'),
title: node.getData('hyperlinkTitle')
};
}
}),
"unhyperlink": kity.createClass("hyperlink", {
......@@ -80,7 +84,6 @@ KityMinder.registerModule("hyperlink", function() {
link.setTarget('_blank');
link.setStyle('cursor', 'pointer');
link.on('mouseover', function() {
outline.fill('rgba(255, 255, 200, .8)');
}).on('mouseout', function() {
......@@ -90,7 +93,6 @@ KityMinder.registerModule("hyperlink", function() {
},
shouldRender: function(node) {
return node.getData('hyperlink');
},
......@@ -98,7 +100,16 @@ KityMinder.registerModule("hyperlink", function() {
var href = node.getData('hyperlink');
link.setHref(href);
link.setAttr('xlink:title', href);
var title = node.getData('hyperlinkTitle');
if (title) {
title = [title, '(', href, ')'].join('');
} else {
title = href;
}
link.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title);
var spaceRight = node.getStyle('space-right');
link.setTranslate(box.right + spaceRight + 2, -5);
......
......@@ -32,7 +32,7 @@ KityMinder.registerModule('image', function() {
var ImageCommand = kity.createClass('ImageCommand', {
base: Command,
execute: function(km, url) {
execute: function(km, url, title) {
var nodes = km.getSelectedNodes();
loadImageSize(url, function(width, height) {
......@@ -43,6 +43,7 @@ KityMinder.registerModule('image', function() {
km.getOptions('maxImageWidth'),
km.getOptions('maxImageHeight'));
n.setData('image', url);
n.setData('imageTitle', title);
n.setData('imageSize', size);
n.render();
});
......@@ -67,7 +68,10 @@ KityMinder.registerModule('image', function() {
},
queryValue: function(km) {
var node = km.getSelectedNode();
return node.getData('image');
return {
url: node.getData('image'),
title: node.getData('imageTitle')
};
}
});
......@@ -114,11 +118,16 @@ KityMinder.registerModule('image', function() {
update: function(image, node, box) {
var url = node.getData('image');
var title = node.getData('imageTitle');
var size = node.getData('imageSize');
var spaceTop = node.getStyle('space-top');
if (!size) return;
if (title) {
image.node.setAttributeNS('http://www.w3.org/1999/xlink', 'title', title);
}
var x = box.cx - size.width / 2;
var y = box.y - size.height - spaceTop;
......
......@@ -142,7 +142,9 @@ KityMinder.registerModule('KeyboardModule', function() {
queryState: function(km) {
return km.getSelectedNode() ? 0 : -1;
}
},
enableReadOnly: true
});
// 稀释用
......@@ -159,7 +161,7 @@ KityMinder.registerModule('KeyboardModule', function() {
var root = this.getRoot();
buildPositionNetwork(root);
},
'normal.keydown': function(e) {
'normal.keydown readonly.keydown': function(e) {
var minder = this;
['left', 'right', 'up', 'down'].forEach(function(key) {
if (e.isShortcutKey(key)) {
......
......@@ -106,7 +106,7 @@ KityMinder.registerModule('NodeModule', function() {
'appendsiblingnode': 'normal::Enter',
'appendchildnode': 'normal::Insert|Tab',
'editnode': 'normal::F2',
'removenode': 'normal::Delete|Backspace'
'removenode': 'normal::Del|Backspace'
}
};
});
\ No newline at end of file
......@@ -20,7 +20,7 @@ KityMinder.registerModule('Select', function() {
return {
selectStart: function(e) {
// 只接受左键
if (e.originEvent.button) return;
if (e.originEvent.button || e.originEvent.altKey) return;
// 清理不正确状态
if (startPosition) {
......@@ -107,7 +107,7 @@ KityMinder.registerModule('Select', function() {
});
},
'events': {
'normal.mousedown textedit.mousedown inputready.mousedown': function(e) {
'mousedown': function(e) {
var downNode = e.getTargetNode();
......@@ -140,8 +140,8 @@ KityMinder.registerModule('Select', function() {
lastDownPosition = e.getPosition(this.getRenderContainer());
}
},
'normal.mousemove textedit.mousemove inputready.mousemove': marqueeActivator.selectMove,
'normal.mouseup textedit.mouseup inputready.mouseup': function(e) {
'mousemove': marqueeActivator.selectMove,
'mouseup': function(e) {
var upNode = e.getTargetNode();
// 如果 mouseup 发生在 lastDownNode 外,是无需理会的
......@@ -158,10 +158,7 @@ KityMinder.registerModule('Select', function() {
//全选操作
'normal.keydown inputready.keydown':function(e){
var keyEvent = e.originEvent;
if ( (keyEvent.ctrlKey || keyEvent.metaKey) && keymap.a == keyEvent.keyCode){
if ( e.isShortcutKey('ctrl+a') ){
var selectedNodes = [];
this.getRoot().traverse(function(node){
......
......@@ -38,15 +38,18 @@ var TextRenderer = KityMinder.TextRenderer = kity.createClass('TextRenderer', {
this.setTextStyle(node, textGroup);
for (var i = 0, text, textShape;
(text = textArr[i], textShape = textGroup.getItem(i),
text !== undefined || textShape !== undefined); i++) {
var textLength = textArr.length;
var textGroupLength = textGroup.getItems().length;
if (text === undefined && textShape) {
if(textLength < textGroupLength){
for( var i = textLength,ci;ci = textGroup.getItem(i);){
textGroup.removeItem(i);
} else {
if (text !== undefined && !textShape) {
textShape = new kity.Text()
}
}else if(textLength > textGroupLength){
var length = textLength - textGroupLength;
for(var i = 0;i < length;i++){
var textShape = new kity.Text()
.setAttr('text-rendering', 'inherit');
if (kity.Browser.ie) {
textShape.setVerticalAlign('top');
......@@ -55,12 +58,14 @@ var TextRenderer = KityMinder.TextRenderer = kity.createClass('TextRenderer', {
}
textGroup.addItem(textShape);
}
textShape.setContent(text);
}
for (var i = 0, text, textShape;
(text = textArr[i], textShape = textGroup.getItem(i)); i++) {
textShape.setContent(text);
}
}
this.setTextStyle(node, textGroup);
return function() {
......
......@@ -100,14 +100,14 @@ var ViewDragger = kity.createClass("ViewDragger", {
e.originEvent.preventDefault(); // 阻止中键拉动
}
// 点击未选中的根节点临时开启
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2) {
if (e.getTargetNode() == this.getRoot() || e.originEvent.button == 2 || e.originEvent.altKey) {
lastPosition = e.getPosition();
isTempDrag = true;
}
})
.on('normal.mousemove normal.touchmove ' +
'readonly.touchmove readonly.mousemove ' +
'readonly.mousemove readonly.touchmove ' +
'inputready.mousemove inputready.touchmove', function(e) {
if (e.type == 'touchmove') {
e.preventDefault(); // 阻止浏览器的后退事件
......@@ -115,7 +115,7 @@ var ViewDragger = kity.createClass("ViewDragger", {
if (!isTempDrag) return;
var offset = kity.Vector.fromPoints(lastPosition, e.getPosition());
if (offset.length() > 10) {
this.setStatus('hand');
this.setStatus('hand', true);
var paper = dragger._minder.getPaper();
paper.setStyle('cursor', '-webkit-grabbing');
}
......@@ -163,7 +163,7 @@ KityMinder.registerModule('View', function() {
execute: function(minder) {
if (minder.getStatus() != 'hand') {
minder.setStatus('hand');
minder.setStatus('hand', true);
} else {
minder.rollbackStatus();
}
......@@ -173,7 +173,7 @@ KityMinder.registerModule('View', function() {
queryState: function(minder) {
return minder.getStatus() == 'hand' ? 1 : 0;
},
enableReadOnly: false
enableReadOnly: true
});
var CameraCommand = kity.createClass('CameraCommand', {
......@@ -190,7 +190,7 @@ KityMinder.registerModule('View', function() {
dragger.move(new kity.Point(dx, dy), duration);
this.setContentChanged(false);
},
enableReadOnly: false
enableReadOnly: true
});
var MoveCommand = kity.createClass('MoveCommand', {
......@@ -213,7 +213,9 @@ KityMinder.registerModule('View', function() {
dragger.move(new kity.Point(-size.width / 2, 0), duration);
break;
}
}
},
enableReadOnly: true
});
return {
......@@ -226,23 +228,11 @@ KityMinder.registerModule('View', function() {
'move': MoveCommand
},
events: {
keyup: function(e) {
if (this.getStatus() == 'hand' && e.getKeyCode() == 18) {
this.execCommand('hand');
e.preventDefault();
}
},
keydown: function(e) {
var minder = this;
if (this.getStatus() != 'hand' && e.getKeyCode() == 18) {
this.execCommand('hand');
e.preventDefault();
} else if (this.getStatus() == 'hand') {
this.execCommand('hand');
}
['up', 'down', 'left', 'right'].forEach(function(name) {
if (e.isShortcutKey('ctrl+' + name)) {
if (e.isShortcutKey('ctrl+' + name) && minder.getStatus() != 'textedit') {
minder.removeAllSelectedNodes();
minder.execCommand('move', name, 100);
e.preventDefault();
......@@ -300,7 +290,7 @@ KityMinder.registerModule('View', function() {
new kity.Point((a.width - b.width) / 2 | 0, (a.height - b.height) / 2 | 0));
this._lastClientSize = a;
},
selectionchange: function() {
'selectionchange layoutallfinish': function(e) {
var selected = this.getSelectedNode();
if (!selected) return;
......
......@@ -44,8 +44,9 @@ KityMinder.registerModule('Zoom', function() {
if (minder.getRoot().getComplex() > 200) {
minder._zoomValue = value;
return minder.zoom(value);
}
minder.zoom(value);
minder.fire('viewchange');
} else {
var animator = new kity.Animator({
beginValue: minder._zoomValue,
finishValue: value,
......@@ -57,12 +58,13 @@ KityMinder.registerModule('Zoom', function() {
if (timeline) {
timeline.pause();
}
timeline = animator.start(minder, 300, 'easeInOutSine', function() {});
timeline = animator.start(minder, 300, 'easeInOutSine');
timeline.on('finish', function() {
minder.fire('viewchange');
minder.fire('zoom', { zoom: value });
});
}
minder.fire('zoom', { zoom: value });
}
var ZoomCommand = kity.createClass('Zoom', {
base: Command,
......@@ -88,7 +90,7 @@ KityMinder.registerModule('Zoom', function() {
}
return 0;
},
enableReadOnly: false
enableReadOnly: true
});
var ZoomOutCommand = kity.createClass('ZoomOutCommand', {
......@@ -107,7 +109,7 @@ KityMinder.registerModule('Zoom', function() {
}
return 0;
},
enableReadOnly: false
enableReadOnly: true
});
return {
......
......@@ -13,6 +13,7 @@ if (!kity.Browser.ie) {
image.onerror = function(err) {
reject(err);
};
image.crossOrigin = '';
image.src = url;
});
}
......@@ -53,19 +54,25 @@ if (!kity.Browser.ie) {
svgXml = $('<div></div>').append($svg).html();
// Dummy IE
svgXml = svgXml.replace(' xmlns="http://www.w3.org/2000/svg" xmlns:NS1="" NS1:ns1:xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:NS2="" NS2:xmlns:ns1=""', '');
// svg 含有 &nbsp; 符号导出报错 Entity 'nbsp' not defined
svgXml = svgXml.replace(/&nbsp;/g, '&#xa0;');
blob = new Blob([svgXml], {
type: 'image/svg+xml;charset=utf-8'
type: 'image/svg+xml'
});
svgUrl = DomURL.createObjectURL(blob);
//svgUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgXml);
return {
width: width,
height: height,
dataUrl: svgUrl
dataUrl: svgUrl,
xml: svgXml
};
}
......@@ -109,12 +116,28 @@ if (!kity.Browser.ie) {
}
function drawSVG() {
if (typeof(window.canvg) != 'undefined') {
return new Promise(function(resolve) {
window.canvg(canvas, svgInfo.xml, {
ignoreMouse: true,
ignoreAnimation: true,
ignoreDimensions: true,
ignoreClear: true,
offsetX: padding,
offsetY: padding,
renderCallback: function() {
resolve(generateDataUrl(canvas));
}
});
});
} else {
return loadImage(svgDataUrl).then(function(svgImage) {
drawImage(ctx, svgImage, padding, padding);
DomURL.revokeObjectURL(svgDataUrl);
return generateDataUrl(canvas);
});
}
}
if (bgUrl) {
......
......@@ -22,7 +22,7 @@ KityMinder.registerTheme('classic', {
'main-shadow': 'rgba(0, 0, 0, .25)',
'sub-color': 'white',
'sub-background': 'none',
'sub-background': 'transparent',
'sub-stroke': 'none',
'sub-font-size': 12,
'sub-padding': [5, 10],
......
......@@ -27,7 +27,7 @@
'main-space': 5,
'sub-color': 'black',
'sub-background': 'none',
'sub-background': 'transparent',
'sub-stroke': 'none',
'sub-font-size': 12,
'sub-padding': compat ? [3, 5] : [5, 10],
......
......@@ -23,9 +23,10 @@
<div class="share-body">
<h3>$lang.url_share</h3>
<p>
<input id="share-url" type="url" value="http://naotu.baidu.com/?shareId=kcev3dd" />
<input id="share-url" class="fui-widget fui-selectable" type="url" readonly value="http://naotu.baidu.com/?shareId=kcev3dd" />
<button id="copy-share-url" data-clipboard-target="share-url" type="button">$lang.copy</button>
</p>
<p class="share-qr-code"></p>
<h3>$lang.sns_share</h3>
<p id="share-platform" class="bdsharebuttonbox">
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
......
<h2 class="contact">$lang.contact</h2>
<p>
百度脑图当前版本: v<a class="km-version" target="_blank" href="https://github.com/fex-team/kityminder/tree/master/CHANGELOG.md"></a>
</p>
<p>
欢迎给我们反馈问题,以下是我们的反馈渠道。
</p>
<ul class="contact-content">
<li class="email">
<label>$lang.email</label>
<a href="mailto:kity@baidu.com?subject=脑图使用反馈">kity@baidu.com</a>
</li>
<li class="qq">
<label>$lang.qq_group</label>
<a>374918234</a>
</li>
<li class="tieba">
<label>$lang.baidu_tieba</label>
<a target="_blank" href="http://tieba.baidu.com/f?kw=%B0%D9%B6%C8%C4%D4%CD%BC">百度脑图</a></li>
<li class="github">
<label>$lang.github_issue</label>
<a target="_blank" href="https://github.com/fex-team/kityminder/issues">Issues</a>
</li>
</ul>
\ No newline at end of file
<h2 class="shortcut">$lang.shortcuts</h2>
<div class="shortcut-content"></div>
\ No newline at end of file
<h2 class="contact">$lang.contact</h2>
<ul class="contact-content">
<li>$lang.email: <a href="mailto:kity@baidu.com">kity@baidu.com</a></li>
<li>$lang.qq_group: <a>KityMinder (374918234)</a></li>
</ul>
\ No newline at end of file
......@@ -18,9 +18,9 @@
## 视野控制
`Space`: 切换编辑/抓手模式
`滚轮`: 移动视野
`右键拖动`: 拖动视野
`Alt` + `拖动` or `右键拖动`: 拖动视野
`滚轮` or `触摸板`: 移动视野
`Ctrl` + `Up`, `Down`, `Left`, `Right`: 视野导航
`空白处双击`, `Ctrl + Enter`: 居中根节点
`Ctrl` + `+`, `-`: 放大/缩小视野
......
......@@ -18,6 +18,15 @@ KityMinder.registerUI('contextmenu', function(minder) {
.addClass('km-context-menu fui-popup-menu')
.appendTo('#content-wrapper');
var downPosition;
function distance(p1, p2) {
var dx = p1[0] - p2[0];
var dy = p1[1] - p2[1];
var ds = Math.sqrt(dx * dx + dy * dy);
return ds;
}
$menu.delegate('li', 'mousedown', function(e, info) {
var item = $(e.target).closest('li').data('menu');
if (item.command) {
......@@ -31,15 +40,23 @@ KityMinder.registerUI('contextmenu', function(minder) {
$('#content-wrapper').on('mousedown', function(e) {
$menu.hide();
if (e.button == 2) {
downPosition = [e.pageX, e.pageY];
} else {
downPosition = null;
}
});
minder.on('mouseup', function(e) {
//e.preventDefault();
if (minder.getStatus() == 'hand' || !e.isRightMB()) return;
if (!e.isRightMB()) return;
e = e.originEvent;
var d = distance(downPosition, [e.pageX, e.pageY]);
if (isNaN(d) || d > 5) return;
$menu.empty();
var ctxmenu = minder.getContextMenu();
......
......@@ -12,6 +12,7 @@ KityMinder.registerUI('doc', function(minder) {
var ret = minder.getUI('eve').setup({});
var current = { saved: true };
var loading = false;
var notice = minder.getUI('widget/notice');
/**
* 加载文档
......@@ -53,10 +54,11 @@ KityMinder.registerUI('doc', function(minder) {
})['catch'](function(e) {
current = restore;
alert('加载文件失败:' + doc.title);
console.error((new Error()).stack);
notice.error('err_doc_resolve', e);
}).then(function(doc) {
loading = false;
if (doc)
notice.info( minder.getLang('ui.load_success', doc.title ) );
return doc;
});
}
......@@ -74,8 +76,9 @@ KityMinder.registerUI('doc', function(minder) {
return current;
}
function checkSaved() {
function checkSaved(noConfirm) {
if (!fio.user.current()) return true;
if (noConfirm) return current.saved;
return current.saved || window.confirm(minder.getLang('ui.unsavedcontent', '* ' + current.title));
}
......
......@@ -17,45 +17,76 @@ KityMinder.registerUI('menu/default', function(minder) {
var $share = minder.getUI('menu/share/share');
var $draft = minder.getUI('menu/open/draft');
setMenuDefaults();
// $menu.show();
// $menu.$tabs.select(1);
// $open.$tabs.select(1);
// return;
loadLandingFile();
function setMenuDefaults() {
// 主菜单默认选中「打开」
$menu.$tabs.select(1);
// 打开菜单默认选中「本地文件」
$open.$tabs.select(2);
if ($draft.hasDraft()) {
// 草稿箱有草稿,默认选中「草稿箱」,并打开最近编辑的文件
$open.$tabs.select(3);
$draft.openLast();
} else {
// 没有草稿,但用户登陆了
// 保存菜单默认选中「导出到本地」
$save.$tabs.select(1);
// 如果用户登陆了,选中「百度云存储」
fio.user.check().then(function(user) {
if (user) {
// 有最近文件选中「最近文件」
if ($recent.hasRecent()) {
$open.$tabs.select(0);
$recent.loadLast();
}
// 否则选中网盘目录
else {
$open.$tabs.select(1);
}
$save.$tabs.select(0);
}
});
$share.$menu.$tabs.select(0); // 当前脑图
}
// 保存菜单默认选中「导出到本地」
$save.$tabs.select(1);
function loadLandingFile() {
var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
var match = pattern.exec(window.location) || pattern.exec(document.referrer);
// 如果用户登陆了,选中「百度云存储」
if (match) {
return $share.loadShareFile();
}
// 检查登录状态
fio.user.check().then(function(user) {
var draft = $draft.last();
var recent = $recent.last();
// 登录
if (user) {
$save.$tabs.select(0);
if (recent) {
if (draft) {
if (recent.time > draft.time) openRecent();
else openDraft();
} else {
openRecent();
}
} else {
if (draft) openDraft();
else $open.$tabs.select(1); // locale netdisk
}
} else {
if (draft) openDraft();
else $open.$tabs.select(2); // locale local
}
});
$share.$tabs.select(0); // 当前脑图
// $menu.show();
// $menu.$tabs.select(4);
function openDraft() {
$open.$tabs.select(3);
$draft.openLast();
}
function openRecent() {
$open.$tabs.select(0);
$recent.loadLast();
}
});
}
});
});
\ No newline at end of file
/**
* @fileOverview
*
* 帮助面板
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerUI('menu/help/feedback', function (minder) {
var $menu = minder.getUI('menu/menu');
var $panel = $($menu.createSub('feedback'));
var $feedback = $('<div id="feedback-panel">')
.appendTo($panel)
.addClass('loading');
$.pajax({
url: 'static/pages/feedback.html',
dataType: 'text'
}).then(render);
function render(template) {
/* global jhtmls: true */
var renderer = jhtmls.render(template);
$feedback.html(renderer({
lang: minder.getLang('ui'),
minder: minder
}));
$feedback.on('click contextmenu keydown', function(e) {
e.stopPropagation();
});
$feedback.removeClass('loading');
$feedback.find('.km-version').text(KityMinder.version);
}
});
\ No newline at end of file
......@@ -37,7 +37,40 @@ KityMinder.registerUI('menu/help/help', function (minder) {
}));
$help.find('.shortcut-content').html(convert(operation));
if (kity.Browser.mac) {
$help.addClass('mac');
}
$help.removeClass('loading');
$help.find('.km-version').text(KityMinder.version);
// 彩蛋:点很多次按钮的蛋疼
/*9szjzrzdznztz6z1z28z1wzhzbz9z4z2mz23z27zcz1xz27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z23zfz20z8z26z27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z1uz1uztztz1uz29z2nz3zsz5ztz2mzfz2nz2nzez7z1wzczhz2iz28zjzrzdznztz6z1z20z2lz2kz9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z2azhzjz1zmz19z14zqz2mz2lz2pzczjz6zsziz1ez17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2nz2eziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz2nz1yz9zvzmz1yz2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z1uz1uztztz1uz29z2nz3zsz5ztz2mzfz0zez7z1wzczhz2iz28zjzrzdznztz6z1z20z2lz2kz9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z2dz2nz27zbz9zjz1ez19zbz1z11z1iz2mzozpziz1ez17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2nz2eziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz3ez17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz25zezsz2jztztzgz22z23z2z2zazrz17z17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz1vz1vztztz3iz6z2wz1ez17z0z0z0z0z0z0z0z0z0z0z0z2gznzjz2cz23z23ztztzgzbz1ez17z0z0z0z0z0z0z0z0z0z0z0z1vz26z2oz5z6zrz1tz23z1nz1fz1hz3kz3lz3lz25zezsz2aziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2hzvz1z5z9z27z23z1nz37z0z1vz1hz3kz1zsz0ztz2fzrzaz1z3zfz7zbz1z27z9z1vz26z2oz5z6zrz1tz23z1nz1fz1hz3kz3lz3lz8z26z1xzvzvz1vz1mz1fz1xzsz33z3kzqzqz1uz1nz1fz1xzsz33z3bz0ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z1wzcz1ztzsz3z9z25z1vz3z8z29z23z22ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z1wzcz1ztzsz3z9z25z1vz3z8z29z24z25ziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z1xz1xzvzvz3az14z6zrz7z9z23z22zkztz2z1bz18z9zjz1ez19zbz1z25z29zhz0zszlz2bz20zrzpz0z1tzcz1vz25z9zqzqz1vz26z1wzczhz2iz28zjzrzdznztz6z1z20z26z27z9z2lz38z17z0z0z0z0z0z0z0z0z0z0z0z0z0z0z0z2cznzhz1z7zsz28z1xz24z2kzrz1pz14z6zrz7z9z29zrz6zsziz1ez17z0z0z0z0z0z0z0z0z0z0z0z2nz2ez7z1xz5z6z7z20zfz2nz2nzeziz1ez17z0z0z0z0z0z0z0z2n*/
function decrypt(a) {
a = a.split('z').map(function(s) {
return parseInt(s, 35);
});
var key = 0x131;
var b = [];
var i = 0;
b.push(a[i] ^ key);
while(a[++i] !== undefined) b.push(a[i] ^ b[i-1]);
return String.fromCharCode.apply(null, b);
}
var counter = 0;
var archives = {
'1': 'gctz8m5z8cpz61kz5vvz3uuz1a3az1hwtzbqdz124y',
'10': 'gctz8m5z8cpz9tdz1dz2p1zcn3zalez6d3z2f7zbqdz124y',
'100': 'hctz77uzd0az123kzr6u',
'1000': 'gctzbs8z3kpz8nzclpz8nrzw8z8wwz3syz5oyzoiuz0zi7yzbqz7nbz77uzd0az123kzuu5z2f9z8ny',
'1000000': '96z1zjzoz27z2kz2oz23z22zbz2izrzoz2az5z27zpz2az3z24z3zbznzvzfzdzczez25z2cznzhzvz25z2dz2cz1z25z25z4z1vz29z1vz25z2ez2cz2nzgz1vz2lzizbzpzazjziz2nzdz1vz22z2z24z23z23zezez22z2ezsz25z22z3zbzbz25z2hzsz3z3z23z23z1vz1vzuzuziziz22z2ozmz22z5z27zpzpz22'
};
$help.delegate('.shortcut-key', 'click', function() {
var msg = archives[++counter];
if (msg) {
window.alert(decrypt(msg));
if (counter > 1000000) console.log(msg);
}
});
}
function convert(markdown) {
......@@ -67,7 +100,7 @@ KityMinder.registerUI('menu/help/help', function (minder) {
var description = match[2];
html += '<div class="shortcut-group"><span class="shortcut">';
html += declare.replace(/\`(.+?)\`/g, function(match, key) {
return '<span class="shortcut-key ' + key.toLowerCase() + '">' + key + '</span>';
return '<span class="shortcut-key ' + key.toLowerCase() + '" title="' + key + '">' + key + '</span>';
});
html += '</span>';
html += '<span class="description">' + description + '</span>';
......
......@@ -47,6 +47,7 @@ KityMinder.registerUI('menu/menu', function(minder) {
}
function toggle() {
if ($('#content-wrapper').hasClass('fullscreen')) return;
(isVisible() ? hide : show)();
}
......@@ -71,10 +72,7 @@ KityMinder.registerUI('menu/menu', function(minder) {
$button.on('click', toggle);
$(window).keydown(function(e) {
// ESC Pressed
if (e.keyCode == 27) toggle();
});
minder.addShortcut('esc', toggle);
// expose
ret.show = show;
......
......@@ -150,6 +150,9 @@ KityMinder.registerUI('menu/open/draft', function(minder) {
},
openLast: function() {
$ul.find('.draft-list-item').eq(0).click();
},
last: function() {
return draftList.get(0) || null;
}
};
});
\ No newline at end of file
......@@ -12,6 +12,7 @@ KityMinder.registerUI('menu/open/local', function(minder) {
var $menu = minder.getUI('menu/menu');
var $open = minder.getUI('menu/open/open');
var $doc = minder.getUI('doc');
var notice = minder.getUI('widget/notice');
/* extension => protocol */
var supports = {};
......@@ -64,16 +65,20 @@ KityMinder.registerUI('menu/open/local', function(minder) {
}).click();
});
$('#content-wrapper').on('dragover', function(e) {
var cwrapper = $('#content-wrapper')[0];
cwrapper.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
}).on('drop', function(e) {
if (!$doc.checkSave()) return;
e = e.originalEvent;
}, false);
cwrapper.addEventListener('drop', function(e) {
if (e.dataTransfer.files.length) {
e.preventDefault();
if (!$doc.checkSaved()) return;
read(e.dataTransfer.files[0]);
$menu.hide();
e.preventDefault();
});
}
}, false);
function read(domfile) {
if (!domfile) return;
......@@ -81,8 +86,13 @@ KityMinder.registerUI('menu/open/local', function(minder) {
var info = new fio.file.anlysisPath(domfile.name);
var protocol = supports[info.extension];
var dataPromise = new Promise(function(resolve, reject) {
if (!protocol || !protocol.decode) {
notice.warn(minder.getLang('ui.unsupportedfile'));
return Promise.reject();
}
function loadFile(file, protocol) {
return new Promise(function(resolve, reject) {
var reader;
if (protocol.dataType == 'blob') {
......@@ -98,13 +108,15 @@ KityMinder.registerUI('menu/open/local', function(minder) {
reader.onerror = reject;
reader.readAsText(domfile, 'utf-8');
}
});
}
$(minder.getRenderTarget()).addClass('loading');
return dataPromise.then(function(data) {
function loadFileError() {
var notice = minder.getUI('widget/notice');
notice.error('err_localfile_read');
}
function loadDoc(data) {
var doc = {
content: data.content,
protocol: protocol.name,
......@@ -113,12 +125,11 @@ KityMinder.registerUI('menu/open/local', function(minder) {
};
return $doc.load(doc);
}
})['catch'](function(error) {
window.alert(minder.getLang('ui.errorloading', error.message || minder.getLang('ui.unknownreason')));
$(minder.getRenderTarget()).addClass('loading');
}).then(function() {
return loadFile(domfile, protocol).then(loadDoc, loadFileError).then(function() {
$(minder.getRenderTarget()).removeClass('loading');
......
......@@ -15,6 +15,7 @@ KityMinder.registerUI('menu/open/netdisk', function(minder) {
var $eve = minder.getUI('eve');
var $doc = minder.getUI('doc');
var ret = $eve.setup({});
var notice = minder.getUI('widget/notice');
/* 网盘面板 */
var $panel = $($open.createSub('netdisk'));
......@@ -40,20 +41,25 @@ KityMinder.registerUI('menu/open/netdisk', function(minder) {
return open(file.path);
});
function open(path) {
function open(path, errorHandler) {
$menu.hide();
$(minder.getRenderTarget()).addClass('loading');
var info = fio.file.anlysisPath(path);
var protocol = supports[info.extension];
function read() {
return fio.file.read({
path: path,
dataType: protocol.dataType
}).then(function(file) {
});
}
function load(file) {
var doc = {
protocol: supports[file.extension].name,
......@@ -65,12 +71,13 @@ KityMinder.registerUI('menu/open/netdisk', function(minder) {
};
return $doc.load(doc);
}
})['catch'](function(error) {
window.alert(minder.getLang('ui.errorloading', error.message || minder.getLang('unknownreason')));
function error(e) {
return errorHandler && errorHandler(e) || notice.error('err_load', e);
}
}).then(function() {
return read().then(load)['catch'](error).then(function() {
$(minder.getRenderTarget()).removeClass('loading');
......
......@@ -114,6 +114,9 @@ KityMinder.registerUI('menu/open/recent', function(minder) {
},
loadLast: function() {
$ul.find('.recent-file-item').eq(0).click();
},
last: function() {
return recentList.get(0) || null;
}
};
......
......@@ -40,7 +40,7 @@ KityMinder.registerUI('menu/save/download', function(minder) {
$list.delegate('li', 'click', function(e) {
var protocol = $(e.target).data('protocol');
doExport(protocol);
if (!$panel.hasClass('loading')) doExport(protocol);
});
function doExport(protocol) {
......@@ -67,14 +67,36 @@ KityMinder.registerUI('menu/save/download', function(minder) {
return null;
}).then(function() {
})['catch'](function exportError(e) {
var notice = minder.getUI('widget/notice');
return notice.error('err_download', e);
})
.then(function done(tick) {
$panel.removeClass('loading');
$menu.hide();
});
}
function doDownload(url, filename, type) {
var stamp = +new Date() * 1e5 + Math.floor(Math.random() * (1e5 - 1));
stamp = stamp.toString(36);
var ret = new Promise(function(resolve, reject) {
var ticker = 0;
var MAX_TICK = 30;
var interval = 1000;
function check() {
if (document.cookie.indexOf(stamp + '=1') != -1) return resolve([stamp, ticker]);
if (++ticker > MAX_TICK) {
resolve([stamp, ticker]);
}
setTimeout(check, interval);
}
setTimeout(check, interval);
});
var content = url.split(',')[1];
var $form = $('<form></form>').attr({
......@@ -101,9 +123,22 @@ KityMinder.registerUI('menu/save/download', function(minder) {
value: filename
}).appendTo($form);
$('<input name="iehack" value="&#9760;" />').appendTo($form);
if (kity.Browser.ie) {
$('<input name="iehack" value="1" />').appendTo($form);
}
$('<input name="stamp" />').val(stamp).appendTo($form);
var netdisk = minder.getUI('menu/save/netdisk');
if (netdisk) {
netdisk.mute = true;
setTimeout(function() {
netdisk.mute = false;
}, 1000);
}
$form.appendTo('body').submit().remove();
return ret;
}
function buildDataUrl(mineType, data) {
......
......@@ -13,6 +13,7 @@ KityMinder.registerUI('menu/save/netdisk', function(minder) {
var $eve = minder.getUI('eve');
var $doc = minder.getUI('doc');
var ret = $eve.setup({});
var notice = minder.getUI('widget/notice');
/* extension => protocol */
var supports = {};
......@@ -39,6 +40,7 @@ KityMinder.registerUI('menu/save/netdisk', function(minder) {
/* 文件名 */
var $filename = $('<input>')
.addClass('fui-widget fui-selectable')
.attr('type', 'text')
.attr('placeholder', minder.getLang('ui.filename'))
.attr('title', minder.getLang('ui.filename'))
......@@ -81,20 +83,26 @@ KityMinder.registerUI('menu/save/netdisk', function(minder) {
ret.quickSave = quickSave;
window.onbeforeunload = function() {
var noask = window.location.href.indexOf('noask') > 0;
if (!$doc.checkSaved() && !noask)
var noask = ret.mute || window.location.href.indexOf('noask') > 0;
if (!$doc.checkSaved(true) && !noask)
return minder.getLang('ui.unsavedcontent', '* ' + $doc.current().title);
};
var autoSaveDuration = minder.getOptions('autoSave') || 10;
var autoSaveDuration = minder.getOptions('autoSave');
if (autoSaveDuration !== false) {
autoSaveDuration = isNaN(autoSaveDuration) ? 3000 : (autoSaveDuration * 1000);
autoSave();
}
setTimeout(autoSave, autoSaveDuration * 1000);
var autoSaveTimer = 0;
function autoSave() {
saveCurrent().then(function() {
setTimeout(autoSave, autoSaveDuration * 1000);
});
function lazySave() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(saveCurrent, autoSaveDuration);
}
$doc.on('docchange', lazySave);
}
// 快速保存
......@@ -112,11 +120,11 @@ KityMinder.registerUI('menu/save/netdisk', function(minder) {
function saveCurrent() {
var doc = $doc.current();
if (doc.source != 'netdisk' || doc.saved) return Promise.resolve();
if (doc.source != 'netdisk' || doc.saved ) return Promise.resolve();
var $title = minder.getUI('topbar/title').$title;
$filename.val(doc.title);
return doSave(doc.path, doc.protocol, doc, $title);
return doSave(doc.path, doc.protocol, doc, $title, 'leaveTheMenu');
}
function getSaveContext() {
......@@ -153,42 +161,53 @@ KityMinder.registerUI('menu/save/netdisk', function(minder) {
}
}
var saving = false;
var saving = 0;
function doSave(path, protocol, doc, $mask) {
function doSave(path, protocol, doc, $mask, leaveTheMenu, msg) {
// if (saving) return;
if (saving) return;
saving = true;
if ($mask) $mask.addClass('loading');
return minder.exportData(protocol).then(function(data) {
function upload(data) {
return fio.file.write({
path: path,
content: data,
ondup: fio.file.DUP_OVERWRITE
});
}
}).then(function() {
function finish(file) {
if ($mask) $mask.removeClass('loading');
if (!file.modifyTime) throw new Error('File Save Error');
if (!leaveTheMenu) {
$menu.hide();
}
doc.path = path;
doc.title = $filename.val();
doc.path = file.path;
doc.title = file.filename;
doc.source = 'netdisk';
doc.protocol = protocol;
$doc.save(doc);
setTimeout($finder.list, 500);
notice.info(msg || minder.getLang('ui.save_success', doc.title, file.modifyTime.toLocaleTimeString()));
setTimeout(function() {
$finder.list($finder.pwd(), true);
}, 1499);
}
})['catch'](function(e) {
window.alert('保存文件失败:' + (e.message || minder.getLang('ui.unknownreason')));
function error(e) {
notice.error('err_save', e);
}
}).then(function(e) {
return minder.exportData(protocol).then(upload).then(finish, error).then(function() {
if ($mask) $mask.removeClass('loading');
saving = false;
});
}
......
......@@ -12,6 +12,7 @@ KityMinder.registerUI('menu/share/share', function(minder) {
var $create_menu = $($share_menu.createSub('createshare'));
var $manage_menu = $($share_menu.createSub('manageshare'));
var $doc = minder.getUI('doc');
var notice = minder.getUI('widget/notice');
var BACKEND_URL = 'http://naotu.baidu.com/share.php';
......@@ -20,7 +21,11 @@ KityMinder.registerUI('menu/share/share', function(minder) {
renderCreatePanel().then(bindCreatePanelEvent);
renderManagePanel();
var shareListLoaded = loadShareList().then(bindManageActions);
var shareListLoaded = loadShareList();
shareListLoaded.then(renderShareList);
shareListLoaded.then(bindManageActions);
minder.on('uiready', function() {
minder.getUI('topbar/user').requireLogin($manage_menu);
......@@ -44,7 +49,8 @@ KityMinder.registerUI('menu/share/share', function(minder) {
if (shared) {
fio.user.check().then(function(user) {
$.pajax(BACKEND_URL, {
$.pajax({
url: BACKEND_URL,
type: 'POST',
data: {
action: 'update',
......@@ -52,10 +58,93 @@ KityMinder.registerUI('menu/share/share', function(minder) {
id: shared.id || shared.shareMinder.id,
record: doc.json
}
}).then(function() {
notice.info(minder.getLang('ui.share_sync_success', doc.title));
})['catch'](function(e) {
notice.error('err_share_sync_failed', e);
});
});
}
});
function loadShareFile() {
var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
var match = pattern.exec(window.location) || pattern.exec(document.referrer);
if (!match) return Promise.resolve(null);
var shareId = match[1];
$(minder.getRenderTarget()).addClass('loading');
shareListLoaded.then(function(list) {
for (var i = 0; i < list.length; i++) {
var id = list[i].id || list[i].shareMinder.id;
if (id == shareId && list[i].path) {
return loadOriginFile(list[i]);
}
}
return loadShare(shareId);
});
}
function loadOriginFile(share) {
var $netdisk = minder.getUI('menu/open/netdisk');
notice.info(minder.getLang('ui.load_share_for_edit', share.title));
return $netdisk.open(share.path, function() {
// 网盘加载失败
return loadShare(share);
});
}
function loadShare(shareId) {
function renderShareData(data) {
if (data.error) {
notice.error('err_share_data', data.error);
return;
}
var content = data.shareMinder.data;
return $doc.load({
source: 'share',
content: content,
protocol: 'json',
saved: true,
ownerId: data.uid,
ownerName: data.uname
});
}
var $container = $(minder.getRenderTarget()).addClass('loading');
return $.pajax({
url: 'http://naotu.baidu.com/share.php',
data: {
action: 'find',
id: shareId
},
dataType: 'json'
}).then(renderShareData)['catch'](function(e) {
notice.error('err_share_data', e);
}).then(function() {
$container.removeClass('loading');
});
}
function getShareByPath(path) {
if (!path || !shareList) return null;
......@@ -74,14 +163,14 @@ KityMinder.registerUI('menu/share/share', function(minder) {
function renderCreatePanel() {
// render template
return $.pajax('static/pages/createshare.html').then(function(html) {
return $.pajax({ url: 'static/pages/createshare.html' }).then(function(html) {
/* global jhtmls: true */
var render = jhtmls.render(html);
$create_menu.html(render({
lang: minder.getLang('ui'),
minder: minder
}));
zeroCopy();
setTimeout(zeroCopy, 10);
return $create_menu;
});
}
......@@ -100,6 +189,19 @@ KityMinder.registerUI('menu/share/share', function(minder) {
};
actions[e.target.value]();
});
$panel.delegate('input#share-url', 'dblclick', function() {
this.select();
});
$panel.delegate('#copy-share-url', 'click', function() {
if (kity.Browser.safari && kity.Browser.safari < 8) {
var input = $('#share-url');
input.focus();
input.select();
window.alert(minder.getLang('ui.clipboardunsupported'));
}
});
}
function bindManageActions() {
......@@ -138,9 +240,7 @@ KityMinder.registerUI('menu/share/share', function(minder) {
return;
case $target.hasClass('edit-action'):
var $netdisk = minder.getUI('menu/open/netdisk');
$netdisk.open(share.path);
loadOriginFile(share);
return;
}
});
......@@ -159,9 +259,8 @@ KityMinder.registerUI('menu/share/share', function(minder) {
dataType: 'json'
})['catch'](function(e) {
window.alert(minder.getLang('remove_share_failed', e.message));
var notice = minder.getUI('widget/notice');
notice.error('err_remove_share', e);
});
});
}
......@@ -192,7 +291,7 @@ KityMinder.registerUI('menu/share/share', function(minder) {
function uuid() {
// 最多使用 1e7,否则 IE toString() 会出来指数表示法
var timeLead = 1e7;
var timeLead = 1e6;
return ((+new Date() * timeLead) + (Math.random() * --timeLead)).toString(36);
}
......@@ -236,7 +335,8 @@ KityMinder.registerUI('menu/share/share', function(minder) {
})['catch'](function(e) {
window.alert(minder.getLang('create_share_failed', e.message));
var notice = minder.getUI('widget/notice');
notice.error('err_create_share', e);
});
})
......@@ -275,8 +375,18 @@ KityMinder.registerUI('menu/share/share', function(minder) {
$('#share-url', $sbody).val(shareUrl)[0].select();
var shareConfig = window._bd_share_config.common,
resetShare = window._bd_share_main.init;
// qr code
var $qrcontainer = $sbody.find('.share-qr-code').empty();
new window.QRCode($qrcontainer[0], {
text: shareUrl,
width: 128,
height: 128,
correctLevel : window.QRCode.CorrectLevel.M
});
var shareConfig = window._bd_share_config && window._bd_share_config.common,
resetShare = window._bd_share_main && window._bd_share_main.init;
if (shareConfig && resetShare) {
shareConfig.bdTitle = shareConfig.bdText = minder.getMinderTitle();
......@@ -293,7 +403,7 @@ KityMinder.registerUI('menu/share/share', function(minder) {
return fio.user.check().then(function(user) {
if (!user) return;
$.pajax(BACKEND_URL, {
return $.pajax(BACKEND_URL, {
type: 'GET',
......@@ -306,9 +416,9 @@ KityMinder.registerUI('menu/share/share', function(minder) {
}).then(function(result) {
return (shareList = result.list || null);
return (shareList = result.list || []);
}).then(renderShareList);
});
});
}
......@@ -371,7 +481,6 @@ KityMinder.registerUI('menu/share/share', function(minder) {
function clearShareList() {
shareList = [];
}
function shareRedirect() {
......@@ -386,18 +495,18 @@ KityMinder.registerUI('menu/share/share', function(minder) {
function zeroCopy() {
/* global ZeroClipboard:true */
ZeroClipboard.setDefaults({
moviePath: 'lib/ZeroClipboard.swf'
});
var $copy_url_btn = $('#copy-share-url', $create_menu);
if (window.ZeroClipboard) {
var clip = new window.ZeroClipboard($copy_url_btn, {
ZeroClipboard.config({
swfPath: 'lib/ZeroClipboard.swf',
hoverClass: 'hover',
activeClass: 'active'
});
clip.on('dataRequested', function(client, args) {
var clip = new window.ZeroClipboard($copy_url_btn);
clip.on('ready', function () {
clip.on('aftercopy', function() {
$copy_url_btn.text(minder.getLang('ui.copied')).attr('disabled', 'disabled');
setTimeout(function() {
$copy_url_btn
......@@ -405,8 +514,12 @@ KityMinder.registerUI('menu/share/share', function(minder) {
.removeAttr('disabled');
}, 3000);
});
});
}
}
return $share_menu;
return {
$menu: $share_menu,
loadShareFile: loadShareFile
};
});
\ No newline at end of file
......@@ -10,10 +10,25 @@ KityMinder.registerUI('menu/share/view', function (minder) {
var $menu = minder.getUI('menu/menu');
var $save = minder.getUI('menu/save/save');
var $doc = minder.getUI('doc');
var notice = minder.getUI('widget/notice');
var shareId;
$menu.$tabs.select(0);
$save.$tabs.select(0);
minder.on('uiready', function() {
var $quickvisit = minder.getUI('topbar/quickvisit');
var $edit = $quickvisit.add('editshare', 'right');
$edit.on('click', function() {
if (shareId) window.open('edit.html?shareId=' + shareId);
});
$quickvisit.$new.remove();
$quickvisit.$save.remove();
$quickvisit.$share.remove();
});
function loadShareDoc() {
var pattern = /(?:shareId|share_id)=(\w+)([&#]|$)/;
......@@ -21,14 +36,12 @@ KityMinder.registerUI('menu/share/view', function (minder) {
if (!match) return Promise.resolve(null);
var shareId = match[1];
shareId = match[1];
function renderShareData(data) {
if (data.error) {
window.alert(data.error);
window.location.href = 'index.html';
return;
return notice.error('err_share_data', data.error);
}
var content = data.shareMinder.data;
......@@ -44,13 +57,15 @@ KityMinder.registerUI('menu/share/view', function (minder) {
}).then(function(doc) {
var $title = minder.getUI('topbar/title');
$title.setTitle('[分享的] ' + $title.getTitle());
$title.setTitle('[分享的] ' + $title.getTitle() + ' (只读)');
});
}
var $container = $(minder.getRenderTarget()).addClass('loading');
return $.pajax({
url: 'http://naotu.baidu.com/share.php', //'http://naotu.baidu.com/mongo.php',
url: 'http://naotu.baidu.com/share.php',
data: {
action: 'find',
......@@ -61,13 +76,13 @@ KityMinder.registerUI('menu/share/view', function (minder) {
}).then(renderShareData)['catch'](function(e) {
window.alert('请求分享文件失败,请重试!');
notice.error('err_share_data', e);
}).then(function() {
$(minder.getRenderTarget()).removeClass('loading');
minder.execCommand('hand');
minder.disable();
minder.execCommand('hand', true);
$container.removeClass('loading');
});
}
......
......@@ -15,7 +15,7 @@ KityMinder.registerUI('nav', function(minder) {
var $commandbutton = minder.getUI('widget/commandbutton');
var $zoomIn = $commandbutton.generate('zoom-in').appendTo($navBar[0]);
var $zoomPan = createZoomPan().appendTo($navBar);
var $zoomPan = createZoomPan($navBar);
var $zoomOut = $commandbutton.generate('zoom-out').appendTo($navBar[0]);
var $previewNavigator = createViewNavigator();
......@@ -27,31 +27,36 @@ KityMinder.registerUI('nav', function(minder) {
var $previewTrigger = createPreviewTrigger($previewNavigator).appendTo($navBar);
function createZoomPan() {
var $pan = $('<div>').addClass('zoom-pan');
function createZoomPan($parent) {
var $pan = $('<div>').addClass('zoom-pan').appendTo($parent);
var zoomStack = minder.getOptions('zoom');
var minValue = zoomStack[0];
var maxValue = zoomStack[zoomStack.length - 1];
var valueRange = maxValue - minValue;
var totalHeight = $pan.height();
function getHeight(value) {
return (100 - (value - minValue) / valueRange * 100) + '%';
return (1 - (value - minValue) / valueRange) * totalHeight;
}
var $origin = $('<div>')
.addClass('origin')
.appendTo($pan)
.css('top', getHeight(100));
.css('y', getHeight(100));
var $indicator = $('<div>')
.addClass('indicator')
.appendTo($pan)
.css('top', getHeight(100));
.css('y', getHeight(100));
minder.on('zoom', function(e) {
function indicate(value) {
$indicator.animate({
'top': getHeight(e.zoom)
}, 100);
'y': getHeight(value)
}, 200);
}
minder.on('zoom', function(e) {
indicate(e.zoom);
});
$origin.click(function() {
......@@ -86,6 +91,7 @@ KityMinder.registerUI('nav', function(minder) {
$previewNavigator.show = function() {
$.fn.show.call(this);
bind();
updateContentView();
updateVisibleView();
};
......
......@@ -39,5 +39,9 @@ KityMinder.registerUI('ribbon/appearence/theme', function(minder) {
$tabs.appearence.appendWidget($themePanel);
$themePanel.appendWidget($themeSelect);
minder.on('themechange', function(e) {
$('#content-wrapper').css('background', minder.getStyle('background'));
});
return $themePanel;
});
\ No newline at end of file
......@@ -28,32 +28,36 @@ KityMinder.registerUI('image', function(minder) {
var $imageDialog = new FUI.Dialog({
width: 500,
height: 400,
prompt: true,
caption: minder.getLang('ui.image')
}).appendTo(document.getElementById('content-wrapper'));
$imageDialog.on('ok', function() {
minder.execCommand('image', $url.val());
});
$imageDialog.on('open', function() {
$url.val(minder.queryCommandValue('image'));
$preview.attr('src', '');
error(false);
});
var $dialogBody = $($imageDialog.getBodyElement());
$dialogBody.html([
'<p><label>图片地址:</label><input type="url" class="image-url" /></p>',
'<p><label>提示文本:</label><input type="text" class="image-title /"></p>',
'<p><label>图片地址:</label><input type="url" class="image-url fui-widget fui-selectable" /></p>',
'<p><label>提示文本:</label><input type="text" class="image-title fui-widget fui-selectable" /></p>',
'<img class="image-preview" src="" style="max-height: 200px;" />'
].join(''));
var $url = $dialogBody.find('.image-url');
var $title = $dialogBody.find('.image-title');
var $preview = $dialogBody.find('.image-preview');
var $ok = $imageDialog.getButton(0);
var $errorMsg = $('<span class="validate-error"></span>');
$imageDialog.on('ok', function() {
minder.execCommand('image', $url.val(), $title.val());
});
$imageDialog.on('open', function() {
var image = minder.queryCommandValue('image');
$url.val(image.url);
$title.val(image.title);
$preview.attr('src', image.url || '');
error(false);
});
function error(value) {
if (value) {
$url.addClass('validate-error');
......
......@@ -9,6 +9,8 @@
KityMinder.registerUI('ribbon/idea/link', function(minder) {
var R_URL = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?/;
var $attachment = minder.getUI('ribbon/idea/attachment');
var $linkButtonMenu = new FUI.ButtonMenu({
......@@ -28,17 +30,19 @@ KityMinder.registerUI('ribbon/idea/link', function(minder) {
var $linkDialog = new FUI.Dialog({
width: 600,
height: 200,
prompt: true,
caption: minder.getLang('ui.link')
}).appendTo(document.getElementById('content-wrapper'));
var $dialogBody = $($linkDialog.getBodyElement());
$dialogBody.html([
'<p><label>连接地址:</label><input type="url" class="link-href" /></p>',
'<p><label>提示文本:</label><input type="text" class="link-title /"></p>'
'<p><label>连接地址:</label><input type="url" class="link-href fui-widget fui-selectable" /></p>',
'<p><label>提示文本:</label><input type="text" class="link-title fui-widget fui-selectable" /></p>'
].join(''));
var $href = $dialogBody.find('.link-href');
var $title = $dialogBody.find('.link-title');
var $ok = $linkDialog.getButton(0);
var $errorMsg = $('<span class="validate-error"></span>');
......@@ -58,7 +62,7 @@ KityMinder.registerUI('ribbon/idea/link', function(minder) {
$href.on('input', function() {
var url = $href.val();
error(!/^https?\:\/\/(\w+\.)+\w+/.test(url));
error(!R_URL.test(url));
});
$linkButtonMenu.on('buttonclick', function() {
......@@ -71,11 +75,13 @@ KityMinder.registerUI('ribbon/idea/link', function(minder) {
});
$linkDialog.on('ok', function() {
minder.execCommand('hyperlink', $href.val());
minder.execCommand('hyperlink', $href.val(), $title.val() || '');
});
$linkDialog.on('open', function() {
$href.val(minder.queryCommandValue('hyperlink'));
var value = minder.queryCommandValue('hyperlink');
$href.val(value.url);
$title.val(value.title);
error(false);
});
......
......@@ -19,6 +19,8 @@ KityMinder.registerUI('ribbon/idea/resource', function(minder) {
var $addInput = new FUI.Input().appendTo($resourcePanel);
$addInput.getElement().type = 'text';
var $addButton = new FUI.Button({
label: '添加'
}).appendTo($resourcePanel);
......@@ -31,8 +33,9 @@ KityMinder.registerUI('ribbon/idea/resource', function(minder) {
function addResource() {
var resource = $addInput.getValue();
var origin = minder.queryCommandValue('resource');
if (resource) {
origin.push(resource);
if (/\S/.test(resource)) {
if (!~origin.indexOf(resource)) origin.push(resource);
origin.sort();
minder.execCommand('resource', origin);
}
$addInput.setValue(null);
......@@ -68,6 +71,23 @@ KityMinder.registerUI('ribbon/idea/resource', function(minder) {
var resource = minder.queryCommandValue('resource');
var used = minder.getUsedResource();
used.sort();
switch (minder.queryCommandState('resource')) {
case 0:
$addInput.enable();
$addButton.enable();
$resourceDrop.enable();
$ul.find('input[type=checkbox]').removeAttr('disabled');
break;
case -1:
$addInput.disable();
$addButton.disable();
$resourceDrop.disable();
$ul.find('input[type=checkbox]').attr('disabled', true);
break;
}
if (!changed(resource, used)) return;
var delta = used.length - $ul.children().length;
......@@ -91,20 +111,6 @@ KityMinder.registerUI('ribbon/idea/resource', function(minder) {
backgroundColor: ~resource.indexOf(name) ? color : color.dec('a', 0.85).toRGBA()
});
});
switch (minder.queryCommandState('resource')) {
case 0:
$addInput.enable();
$addButton.enable();
$resourceDrop.enable();
$ul.find('input[type=checkbox]').removeProp('disabled');
break;
case -1:
$addInput.disable();
$addButton.disable();
$resourceDrop.disable();
$ul.find('input[type=checkbox]').prop('disabled', 'disabled');
}
}
minder.on('interactchange', update);
......
......@@ -11,7 +11,7 @@ KityMinder.registerUI('ribbon/tabs', function(minder) {
var memory = minder.getUI('memory');
var $tab = new FUI.Tabs({
buttons: ['idea', 'appearence'/*, 'view'*/].map(function(key) {
buttons: ['idea', 'appearence', 'view'].map(function(key) {
return minder.getLang('ui.tabs.' + key);
})
});
......@@ -28,6 +28,7 @@ KityMinder.registerUI('ribbon/tabs', function(minder) {
// 隐藏效果
var lastIndex = 0;
var muteRemember = false;
$tab.on('tabsselect', function(e, info) {
if (info.index == lastIndex) {
$container.toggleClass('collapsed');
......@@ -36,8 +37,10 @@ KityMinder.registerUI('ribbon/tabs', function(minder) {
$container.removeClass('collapsed');
$header.removeClass('collapsed');
}
if (!muteRemember) {
memory.set('ribbon-tab-collapsed', $container.hasClass('collapsed'));
memory.set('ribbon-tab-index', info.index);
}
lastIndex = info.index;
});
......@@ -48,7 +51,9 @@ KityMinder.registerUI('ribbon/tabs', function(minder) {
var rememberIndex = memory.get('ribbon-tab-index');
var rememberCollapse = memory.get('ribbon-tab-collapsed');
muteRemember = true;
$tab.select(rememberIndex || 0);
muteRemember = false;
if (rememberCollapse) {
$container.addClass('collapsed');
......
/**
* @fileOverview
*
* 全屏无打扰模式
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerUI('ribbon/view/fullscreen', function(minder) {
var $commandbutton = minder.getUI('widget/commandbutton');
var $tabs = minder.getUI('ribbon/tabs');
var notice = minder.getUI('widget/notice');
var $fullscreenPanel = new FUI.LabelPanel({
label: minder.getLang('panels.level'),
column: true
}).appendTo($tabs.view);
var $fullscreenButton = $commandbutton
.generate('fullscreen', fullscreen)
.addClass('large')
.appendTo($fullscreenPanel);
function fullscreen() {
if ($('#content-wrapper').toggleClass('fullscreen').hasClass('fullscreen')) {
notice.info(minder.getLang('ui.fullscreen_exit_hint'), false, 4000);
}
}
minder.addShortcut('F11', fullscreen);
minder.addShortcut('Esc', function () {
if ($('#content-wrapper').hasClass('fullscreen')) {
$('#content-wrapper').removeClass('fullscreen');
}
});
return $fullscreenButton;
});
/**
* @fileOverview
*
*
* 切换展开层次
*
* @author: techird
* @copyright: Baidu FEX, 2014
*/
KityMinder.registerUI('ribbon/view/level', function(minder) {
var $commandbutton = minder.getUI('widget/commandbutton');
var $tabs = minder.getUI('ribbon/tabs');
var $levelPanel = new FUI.LabelPanel({
label: minder.getLang('panels.level'),
column: true
}).appendTo($tabs.view);
['expandtoleaf', 'collapsetolevel1'].forEach(function(cmd) {
$commandbutton.generate(cmd).appendTo($levelPanel);
});
});
/**
* 页面下方 “关于” 面板的样式
*/
.fullscreen #about #km-cat {
transform: translate(0, 0);
transition: transform 0.7s 0.2s ease;
}
#about {
position: absolute;
bottom: 0;
......@@ -18,8 +23,8 @@
border-bottom: 5px solid #393F4F;
overflow: visible;
.transition(all ease .3s 0.3s);
.transform(translate(100%));
transition: all ease .3s 0.3s;
transform: translate(100%);
a {
color: #eee;
}
......@@ -28,8 +33,8 @@
position: absolute;
left: 15px;
top: 5px;
.transition(all ease 1.3s 0.3s);
.transform(translate(-60px, 0));
transition: all ease 1.3s 0.3s;
transform: translate(-60px, 0);
cursor: pointer;
}
......@@ -38,7 +43,7 @@
}
&:hover, &:hover #km-cat {
.transform(translate(0));
transform: translate(0);
}
#km-version.new-version{
......@@ -57,7 +62,7 @@
border-radius: 4px;
text-shadow: none;
box-shadow: -1px 1px 3px rgba(0,0,0,0.3);
.transform(scale(.6))
transform: scale(.6);
}
}
}
......
#help-panel {
#help-panel, #feedback-panel {
.dock(50px, 0, 0, 0);
overflow-y: auto;
......@@ -35,14 +35,53 @@
.contact-content {
list-style: none;
margin-left: 50px;
padding-left: 0;
li {
padding: 5px 0;
display: block;
float: left;
padding: 0;
width: 150px;
height: 150px;
margin: 20px;
text-align: center;
position: relative;
a {
-webkit-user-select: initial;
cursor: text;
color: @theme-color;
&[href] {
cursor: pointer;
}
}
&:before {
transition: all .3s ease;
opacity: 0.6;
content: ' ';
display: block;
width: 150px;
height: 150px;
background: white url(../images/feedback.png) no-repeat;
}
&:hover:before {
transform: translate3d(0, -5px, 0);
opacity: 1;
}
&.email:before {
background-position: -150px 0;
}
&.github:before {
background-position: -300px 0;
}
&.tieba:before {
background-position: -450px 0;
}
}
}
......
......@@ -21,4 +21,7 @@
.italic& { .sprite(13); }
.arrangeup& { .sprite(14); }
.arrangedown& { .sprite(15); }
.expandtoleaf& { background-position: 0 -995px; }
.collapsetolevel1& { background-position: 0 -1015px;}
.fullscreen& { background-position: 0 -1035px;}
}
\ No newline at end of file
This diff is collapsed.
......@@ -31,7 +31,7 @@
font-size: 16px;
color: #CCC;
margin: 150px auto;
.transition(all .1s ease);
transition: all .1s ease;
span {
display: block;
......@@ -41,7 +41,7 @@
&.accept {
border-color: lighten(@tab-active, 40%);
.transform(scale(1.2));
transform: scale(1.2);
}
&.deny {
border-color: #eee;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment