├── hotbox
├── .jscsrc
├── .gitignore
├── snap.png
├── src
│ ├── expose.js
│ ├── keymap.js
│ ├── key.js
│ └── keycontrol.js
├── .jshintrc
├── bower.json
├── test
│ ├── spec
│ │ └── .jshintrc
│ └── SpecRunner.html
├── package.json
├── hotbox.css.map
├── README.md
└── demo.html
├── kityminder-core
├── .gitmodules
├── icon.ico
├── .gitignore
├── CHANGELOG.md
├── src
│ ├── expose-kityminder.js
│ ├── core
│ │ ├── kity.js
│ │ ├── _boxv.js
│ │ ├── option.js
│ │ ├── minder.js
│ │ ├── animate.js
│ │ ├── focus.js
│ │ ├── status.js
│ │ ├── utils.js
│ │ ├── keyreceiver.js
│ │ ├── paper.js
│ │ ├── compatibility.js
│ │ ├── keymap.js
│ │ ├── template.js
│ │ └── readonly.js
│ ├── template
│ │ ├── structure.js
│ │ ├── right.js
│ │ ├── filetree.js
│ │ ├── tianpan.js
│ │ ├── default.js
│ │ └── fish-bone.js
│ ├── protocol
│ │ └── json.js
│ ├── connect
│ │ ├── fish-bone-master.js
│ │ ├── l.js
│ │ ├── bezier.js
│ │ ├── under.js
│ │ ├── arc.js
│ │ ├── poly.js
│ │ └── arc_tp.js
│ ├── theme
│ │ ├── wire.js
│ │ ├── fresh.js
│ │ ├── fish.js
│ │ ├── snow.js
│ │ └── default.js
│ ├── layout
│ │ ├── mind.js
│ │ ├── fish-bone-master.js
│ │ ├── fish-bone-slave.js
│ │ ├── tianpan.js
│ │ └── filetree.js
│ └── module
│ │ └── layout.js
├── .jshintrc
├── .jsbeautifyrc
├── LICENSE
├── package.json
├── README.md
├── example.html
├── .jscsrc
├── dev.html
└── import.js
├── babel.config.js
├── packages
└── VueTestcaseMinderEditor
│ ├── src
│ ├── script
│ │ ├── lang.js
│ │ ├── hotbox.js
│ │ ├── minder.js
│ │ ├── expose-editor.js
│ │ ├── tool
│ │ │ ├── format.js
│ │ │ ├── innertext.js
│ │ │ ├── debug.js
│ │ │ ├── keymap.js
│ │ │ └── key.js
│ │ ├── protocol
│ │ │ ├── json.js
│ │ │ ├── svg.js
│ │ │ ├── xmind.js
│ │ │ ├── freemind.js
│ │ │ └── plain.js
│ │ ├── runtime
│ │ │ ├── container.js
│ │ │ ├── minder.js
│ │ │ ├── result.js
│ │ │ ├── progress.js
│ │ │ ├── hotbox.js
│ │ │ ├── priority.js
│ │ │ ├── exports.js
│ │ │ ├── clipboard-mimetype.js
│ │ │ ├── node.js
│ │ │ ├── receiver.js
│ │ │ └── fsm.js
│ │ └── editor.js
│ ├── assets
│ │ └── logo.png
│ ├── static
│ │ ├── caseMind
│ │ │ ├── ban.png
│ │ │ ├── bug.png
│ │ │ ├── icons.png
│ │ │ ├── jump.png
│ │ │ ├── mold.png
│ │ │ ├── noPass.png
│ │ │ ├── note.png
│ │ │ ├── pass.png
│ │ │ ├── plan.png
│ │ │ ├── calendar.png
│ │ │ ├── location.png
│ │ │ ├── icon-undo.png
│ │ │ ├── iconpriority.png
│ │ │ └── iconprogress.png
│ │ └── minder
│ │ │ ├── icons.png
│ │ │ ├── logo.png
│ │ │ ├── mold.png
│ │ │ ├── iconpriority.png
│ │ │ └── iconprogress.png
│ ├── components
│ │ ├── footer.vue
│ │ ├── menu
│ │ │ ├── view
│ │ │ │ ├── viewMenu.vue
│ │ │ │ ├── arrange.vue
│ │ │ │ ├── styleOperation.vue
│ │ │ │ └── mold.vue
│ │ │ └── edit
│ │ │ │ ├── moveBox.vue
│ │ │ │ ├── search
│ │ │ │ ├── search.vue
│ │ │ │ └── searchLabelBox.vue
│ │ │ │ ├── editDel.vue
│ │ │ │ ├── expand.vue
│ │ │ │ ├── progressBox.vue
│ │ │ │ ├── sequenceBox.vue
│ │ │ │ ├── insertBox.vue
│ │ │ │ ├── editMenu.vue
│ │ │ │ ├── backAndRight.vue
│ │ │ │ └── noteBox.vue
│ │ ├── main
│ │ │ └── mainEditor.vue
│ │ └── header.vue
│ ├── store
│ │ ├── index.js
│ │ ├── state.js
│ │ ├── getters.js
│ │ ├── mutations.js
│ │ └── actions.js
│ └── style
│ │ ├── mixin.scss
│ │ ├── dropdown-list.scss
│ │ ├── navigator.scss
│ │ └── editor.scss
│ ├── index.js
│ ├── main.js
│ └── App.vue
├── docs
└── preview.png
├── public
├── favicon.ico
└── index.html
├── .browserlistrc
├── .editorconfig
├── .gitignore
├── examples
├── main.js
└── App.vue
├── vue.config.js
└── package.json
/hotbox/.jscsrc:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kityminder-core/.gitmodules:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/hotbox/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components/
2 | dist/
3 | node_modules/
4 | .idea/
5 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/hotbox/snap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/hotbox/snap.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/lang.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 |
3 | });
--------------------------------------------------------------------------------
/docs/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/docs/preview.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/kityminder-core/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/kityminder-core/icon.ico
--------------------------------------------------------------------------------
/.browserlistrc:
--------------------------------------------------------------------------------
1 | {
2 | "browserslist": [
3 | "> 1%",
4 | "last 2 versions",
5 | "not dead",
6 | "not ie <= 8"
7 | ]
8 | }
--------------------------------------------------------------------------------
/hotbox/src/expose.js:
--------------------------------------------------------------------------------
1 | define('expose', function(require, exports, module) {
2 | module.exports = window.HotBox = require('./hotbox');
3 | });
--------------------------------------------------------------------------------
/kityminder-core/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 | *.sublime-project
4 | *.sublime-workspace
5 | node_modules/
6 | _drafts/
7 | bower_components
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/hotbox.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | return module.exports = window.HotBox;
3 | });
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/kityminder-core/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # KityMinder-Core 更新日志
3 |
4 | ## v1.4.0
5 |
6 | 完成从[原仓库](https://github.com/fex-team/kityminder)的代码迁移。处于兼容性考虑,版本号直接从 1.4.0 开始。
7 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/minder.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | return module.exports = window.kityminder.Minder;
3 | });
4 |
--------------------------------------------------------------------------------
/kityminder-core/src/expose-kityminder.js:
--------------------------------------------------------------------------------
1 | define('expose-kityminder', function(require, exports, module) {
2 | module.exports = window.kityminder = require('./kityminder');
3 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/assets/logo.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/ban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/ban.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/bug.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/minder/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/minder/icons.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/minder/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/minder/logo.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/minder/mold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/minder/mold.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/icons.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/jump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/jump.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/mold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/mold.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/noPass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/noPass.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/note.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/pass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/pass.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/plan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/plan.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/expose-editor.js:
--------------------------------------------------------------------------------
1 | define('expose-editor', function(require, exports, module) {
2 | return module.exports = kityminder.Editor = require('./editor');
3 | });
4 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/calendar.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/location.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/icon-undo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/icon-undo.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/minder/iconpriority.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/minder/iconpriority.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/minder/iconprogress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/minder/iconprogress.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/iconpriority.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/iconpriority.png
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/static/caseMind/iconprogress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chenhengjie123/vue-testcase-minder-editor/HEAD/packages/VueTestcaseMinderEditor/src/static/caseMind/iconprogress.png
--------------------------------------------------------------------------------
/kityminder-core/src/core/kity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * Kity 引入
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | module.exports = window.kity;
11 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/index.js:
--------------------------------------------------------------------------------
1 | import VueTestcaseMinderEditor from './src/VueTestcaseMinderEditor.vue'
2 |
3 | VueTestcaseMinderEditor.install = function (Vue) {
4 | Vue.component(VueTestcaseMinderEditor.name, VueTestcaseMinderEditor)
5 | }
6 |
7 | export default VueTestcaseMinderEditor
8 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/tool/format.js:
--------------------------------------------------------------------------------
1 | function format(template, args) {
2 | if (typeof(args) != 'object') {
3 | args = [].slice.call(arguments, 1);
4 | }
5 | return String(template).replace(/\{(\w+)\}/ig, function (match, $key) {
6 | return args[$key] || $key;
7 | });
8 | }
9 | export {format}
10 |
--------------------------------------------------------------------------------
/kityminder-core/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef" : true,
3 | "unused" : false,
4 | "strict" : false,
5 | "curly" : false,
6 | "newcap" : true,
7 | "trailing" : true,
8 | "white": false,
9 | "quotmark": false,
10 | "browser": true,
11 | "boss": true,
12 | "predef" : [
13 | "define"
14 | ]
15 | }
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/store/index.js:
--------------------------------------------------------------------------------
1 |
2 | import * as getters from './getters'
3 | import {
4 | actions
5 | } from './actions'
6 | import {
7 | mutations
8 | } from './mutations'
9 | import {
10 | state
11 | } from './state'
12 |
13 | export default {
14 | namespaced: true,
15 | state,
16 | getters,
17 | actions,
18 | mutations
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | /lib
5 |
6 | # npm pack file
7 | lizhife-vue-testcase-minder-editor-*.tgz
8 |
9 |
10 | # local env files
11 | .env.local
12 | .env.*.local
13 |
14 | # Log files
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 | pnpm-debug.log*
19 |
20 | # Editor directories and files
21 | .idea
22 | .vscode
23 | *.suo
24 | *.ntvs*
25 | *.njsproj
26 | *.sln
27 | *.sw?
28 |
--------------------------------------------------------------------------------
/hotbox/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef" : true,
3 | "unused" : false,
4 | "strict" : false,
5 | "curly" : false,
6 | "newcap" : true,
7 | "trailing" : true,
8 | "white": false,
9 | "quotmark": false,
10 | "browser": true,
11 | "boss": true,
12 | "loopfunc": true,
13 | "predef" : [
14 | "module",
15 | "require",
16 | "console",
17 | "define"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/hotbox/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hotbox",
3 | "version": "1.0.15",
4 | "main": [
5 | "hotbox.js",
6 | "hotbox.css"
7 | ],
8 | "keywords": [
9 | "hotbox",
10 | "html5",
11 | "javascript",
12 | "ui"
13 | ],
14 | "ignore": [
15 | ".gitignore",
16 | ".jscsrc",
17 | ".jshintrc",
18 | "Gruntfile.js",
19 | "package.json"
20 | ],
21 | "dependencies": {
22 | "seajs": "~2.3.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/hotbox/test/spec/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef" : true,
3 | "unused" : false,
4 | "strict" : false,
5 | "curly" : false,
6 | "newcap" : true,
7 | "trailing" : true,
8 | "white": false,
9 | "quotmark": false,
10 | "browser": true,
11 | "boss": true,
12 | "loopfunc": true,
13 | "predef" : [
14 | "module",
15 | "require",
16 | "define",
17 | "describe",
18 | "it",
19 | "expect"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/style/mixin.scss:
--------------------------------------------------------------------------------
1 | $btn-hover-color: #eee;
2 | .vue-testcase-minder-editor-container {
3 | user-select: none;
4 | height: 360px;
5 | }
6 |
7 | *[disabled] {
8 | opacity: 0.5;
9 | }
10 |
11 | @mixin block {
12 | width: 100%;
13 | height: 100%;
14 | }
15 |
16 | @mixin button {
17 | background: transparent;
18 | border: none;
19 | outline: none;
20 | }
21 |
22 | @mixin flexcenter {
23 | display: flex;
24 | justify-content: center;
25 | align-items: center;
26 | }
27 |
--------------------------------------------------------------------------------
/kityminder-core/src/template/structure.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 组织结构图模板
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('structure', {
13 |
14 | getLayout: function(node) {
15 | return node.getData('layout') || 'bottom';
16 | },
17 |
18 | getConnect: function(node) {
19 | return 'poly';
20 | }
21 | });
22 | });
--------------------------------------------------------------------------------
/kityminder-core/src/protocol/json.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var data = require('../core/data');
3 |
4 | data.registerProtocol('json', module.exports = {
5 | fileDescription: 'KityMinder 格式',
6 | fileExtension: '.km',
7 | dataType: 'text',
8 | mineType: 'application/json',
9 |
10 | encode: function(json) {
11 | return JSON.stringify(json);
12 | },
13 |
14 | decode: function(local) {
15 | return JSON.parse(local);
16 | }
17 | });
18 | });
--------------------------------------------------------------------------------
/kityminder-core/.jsbeautifyrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent_size": 4,
3 | "indent_char": " ",
4 | "indent_level": 0,
5 | "indent_with_tabs": false,
6 | "preserve_newlines": true,
7 | "max_preserve_newlines": 10,
8 | "jslint_happy": false,
9 | "space_in_paren": false,
10 | "brace_style": "collapse",
11 | "keep_array_indentation": false,
12 | "keep_function_indentation": false,
13 | "space_before_conditional": false,
14 | "break_chained_methods": false,
15 | "eval_code": false,
16 | "unescape_strings": false,
17 | "wrap_line_length": 0
18 | }
--------------------------------------------------------------------------------
/kityminder-core/src/template/right.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 往右布局结构模板
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('right', {
13 |
14 | getLayout: function(node) {
15 | return node.getData('layout') || 'right';
16 | },
17 |
18 | getConnect: function(node) {
19 | if (node.getLevel() == 1) return 'arc';
20 | return 'bezier';
21 | }
22 | });
23 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/protocol/json.js:
--------------------------------------------------------------------------------
1 | function exportJson(minder) {
2 | var minds = minder.exportJson();
3 | try {
4 | const link = document.createElement('a');
5 | const blob = new Blob(["\ufeff" + JSON.stringify(minds)], {
6 | type: 'text/json'
7 | });
8 | link.href = window.URL.createObjectURL(blob);
9 | link.download = `${minds.root.data.text}.json`;
10 | document.body.appendChild(link);
11 | link.click();
12 | document.body.removeChild(link);
13 | } catch (err) {
14 | alert(err);
15 | }
16 | }
17 |
18 | export {
19 | exportJson
20 | }
21 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/container.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | function ContainerRuntime() {
3 | var container;
4 |
5 | if (typeof (this.selector) == 'string') {
6 | container = document.querySelector(this.selector);
7 | } else {
8 | container = this.selector;
9 | }
10 |
11 | if (!container) throw new Error('Invalid selector: ' + this.selector);
12 |
13 | // 这个类名用于给编辑器添加样式
14 | container.classList.add('km-editor');
15 |
16 | // 暴露容器给其他运行时使用
17 | this.container = container;
18 | }
19 |
20 | return module.exports = ContainerRuntime;
21 | });
22 |
--------------------------------------------------------------------------------
/examples/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import App from './App'
5 |
6 | import '../lib/VueTestcaseMinderEditor.css'
7 | import VueTestcaseMinderEditor from '../lib/VueTestcaseMinderEditor.umd.min.js'
8 |
9 | Vue.use(VueTestcaseMinderEditor)
10 | console.log('using VueTestcaseMinderEditor', VueTestcaseMinderEditor)
11 |
12 | Vue.use(Vuex)
13 | const store = new Vuex.Store({
14 | modules: {
15 | caseEditorStore: VueTestcaseMinderEditor.caseEditorStore
16 | }
17 | })
18 |
19 | new Vue({
20 | el: '#app',
21 | store,
22 | render: h => h(App),
23 | components: {
24 | App
25 | }
26 | }).$mount('#app')
27 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import App from './App'
5 |
6 | // import '../lib/VueTestcaseMinderEditor.css'
7 | import VueTestcaseMinderEditor from './src/VueTestcaseMinderEditor.vue'
8 |
9 | // Vue.use(VueTestcaseMinderEditor)
10 | // console.log('using VueTestcaseMinderEditor', VueTestcaseMinderEditor)
11 |
12 | Vue.use(Vuex)
13 | const store = new Vuex.Store({
14 | modules: {
15 | caseEditorStore: VueTestcaseMinderEditor.caseEditorStore
16 | }
17 | })
18 |
19 | new Vue({
20 | el: '#app',
21 | store,
22 | render: h => h(App),
23 | components: {
24 | App
25 | }
26 | }).$mount('#app')
27 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/view/viewMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
31 |
--------------------------------------------------------------------------------
/kityminder-core/src/template/filetree.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 文件夹模板
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('filetree', {
13 |
14 | getLayout: function(node) {
15 | if (node.getData('layout')) return node.getData('layout');
16 | if (node.isRoot()) return 'bottom';
17 |
18 | return 'filetree-down';
19 | },
20 |
21 | getConnect: function(node) {
22 | if (node.getLevel() == 1) {
23 | return 'poly';
24 | }
25 | return 'l';
26 | }
27 | });
28 | });
--------------------------------------------------------------------------------
/kityminder-core/src/template/tianpan.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 天盘模板
5 | *
6 | * @author: along
7 | * @copyright: bpd729@163.com, 2015
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('tianpan', {
13 | getLayout: function (node) {
14 | if (node.getData('layout')) return node.getData('layout');
15 | var level = node.getLevel();
16 |
17 | // 根节点
18 | if (level === 0) {
19 | return 'tianpan';
20 | }
21 |
22 | return node.parent.getLayout();
23 | },
24 |
25 | getConnect: function (node) {
26 | return 'arc_tp';
27 | }
28 | });
29 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/minder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 脑图示例运行时
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function (require, exports, module) {
10 | var Minder = require('../minder');
11 |
12 | function MinderRuntime() {
13 |
14 | // 不使用 kityminder 的按键处理,由 ReceiverRuntime 统一处理
15 | var minder = new Minder({
16 | enableKeyReceiver: false,
17 | enableAnimation: true
18 | });
19 |
20 | // 渲染,初始化
21 | minder.renderTo(this.selector);
22 | minder.setTheme(null);
23 | minder.select(minder.getRoot(), true);
24 | minder.execCommand('text', '中心主题');
25 |
26 | // 导出给其它 Runtime 使用
27 | this.minder = minder;
28 | }
29 |
30 | return module.exports = MinderRuntime;
31 | });
32 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | publicPath: './',
3 | pages: {
4 | index: {
5 | entry: 'examples/main.js', // 走示例项目,需要 npm run lib 后才能使用
6 | // entry: 'packages/VueTestcaseMinderEditor/main.js', // 走主工程项目,可直接 npm run serve 使用。方便调试时查看源码堆栈
7 | template: 'public/index.html',
8 | filename: 'index.html'
9 | }
10 | },
11 | chainWebpack: config => {
12 | config.module
13 | .rule('js')
14 | .include
15 | .add(require('path').join(__dirname, '..', 'packages'))
16 | .end()
17 | .use('babel')
18 | .loader('babel-loader')
19 | .tap(options => {
20 | return options
21 | })
22 | },
23 | lintOnSave: false,
24 | configureWebpack: {
25 | // provide the app's title in webpack's name field, so that
26 | // it can be accessed in index.html to inject the correct title.
27 | devtool: 'source-map'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/fish-bone-master.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 鱼骨头主干连线
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | connect.register('fish-bone-master', function(node, parent, connection) {
15 |
16 | var pout = parent.getLayoutVertexOut(),
17 | pin = node.getLayoutVertexIn();
18 |
19 | var abs = Math.abs;
20 |
21 | var dy = abs(pout.y - pin.y),
22 | dx = abs(pout.x - pin.x);
23 |
24 | var pathData = [];
25 |
26 | pathData.push('M', pout.x, pout.y);
27 | pathData.push('h', dx - dy);
28 | pathData.push('L', pin.x, pin.y);
29 |
30 | connection.setMarker(null);
31 | connection.setPathData(pathData);
32 | });
33 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/view/arrange.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
31 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/l.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * "L" 连线
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | connect.register('l', function(node, parent, connection) {
15 |
16 | var po = parent.getLayoutVertexOut();
17 | var pi = node.getLayoutVertexIn();
18 | var vo = parent.getLayoutVectorOut();
19 |
20 | var pathData = [];
21 | var r = Math.round,
22 | abs = Math.abs;
23 |
24 | pathData.push('M', po.round());
25 | if (abs(vo.x) > abs(vo.y)) {
26 | pathData.push('H', r(pi.x));
27 | } else {
28 | pathData.push('V', pi.y);
29 | }
30 | pathData.push('L', pi);
31 |
32 | connection.setPathData(pathData);
33 | });
34 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/_boxv.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 调试工具:为 kity.Box 提供一个可视化的渲染
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('./kity');
12 | var Minder = require('./minder');
13 |
14 | if (location.href.indexOf('boxv') != -1) {
15 |
16 | var vrect;
17 |
18 | Object.defineProperty(kity.Box.prototype, 'visualization', {
19 | get: function() {
20 | if (!vrect) return null;
21 | return vrect.setBox(this);
22 | }
23 | });
24 |
25 | Minder.registerInitHook(function() {
26 | this.on('paperrender', function() {
27 | vrect = new kity.Rect();
28 | vrect.fill('rgba(200, 200, 200, .5)');
29 | vrect.stroke('orange');
30 | this.getRenderContainer().addShape(vrect);
31 | });
32 | });
33 | }
34 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/tool/innertext.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | if ((!('innerText' in document.createElement('a'))) && ('getSelection' in window)) {
3 | HTMLElement.prototype.__defineGetter__('innerText', function () {
4 | var selection = window.getSelection(),
5 | ranges = [],
6 | str, i;
7 |
8 | for (i = 0; i < selection.rangeCount; i++) {
9 | ranges[i] = selection.getRangeAt(i);
10 | }
11 |
12 | selection.removeAllRanges();
13 | selection.selectAllChildren(this);
14 | str = selection.toString();
15 | selection.removeAllRanges();
16 | for (i = 0; i < ranges.length; i++) {
17 | selection.addRange(ranges[i]);
18 | }
19 | return str;
20 | });
21 | HTMLElement.prototype.__defineSetter__('innerText', function (text) {
22 | this.innerHTML = (text || '').replace(//g, '>').replace(/\n/g, '
');
23 | });
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/kityminder-core/src/template/default.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 默认模板 - 脑图模板
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('default', {
13 |
14 | getLayout: function(node) {
15 |
16 | if (node.getData('layout')) return node.getData('layout');
17 |
18 | var level = node.getLevel();
19 |
20 | // 根节点
21 | if (level === 0) {
22 | return 'mind';
23 | }
24 |
25 | // 一级节点
26 | if (level === 1) {
27 | return node.getLayoutPointPreview().x > 0 ? 'right': 'left';
28 | }
29 |
30 | return node.parent.getLayout();
31 | },
32 |
33 | getConnect: function(node) {
34 | if (node.getLevel() == 1) return 'arc';
35 | return 'under';
36 | }
37 | });
38 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/store/state.js:
--------------------------------------------------------------------------------
1 | export const state = {
2 | count: 2,
3 | minder: {},
4 | editor: {},
5 | working: {
6 | editing: false,
7 | saving: false,
8 | draging: false
9 | },
10 | callbackQueue: [],
11 | config: {
12 | // 右侧面板最小宽度
13 | ctrlPanelMin: 250,
14 |
15 | // 右侧面板宽度
16 | ctrlPanelWidth: parseInt(window.localStorage.__dev_minder_ctrlPanelWidth) || 250,
17 |
18 | // 分割线宽度
19 | dividerWidth: 3,
20 |
21 | // 默认语言
22 | defaultLang: 'zh-cn',
23 |
24 | // 放大缩小比例
25 | zoom: [
26 | 10,
27 | 20,
28 | 30,
29 | 50,
30 | 80,
31 | 100,
32 | 120,
33 | 150,
34 | 200
35 | ],
36 |
37 | // 允许编辑优先级
38 | allowEditPriority: true,
39 |
40 | // 允许编辑标签
41 | allowEditLabel: true,
42 |
43 | // 允许编辑测试结果
44 | allowEditResult: true,
45 |
46 | // 允许编辑节点
47 | allowEditNode: true,
48 |
49 | // 是否全屏
50 | isFullScreen: false
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/kityminder-core/src/theme/wire.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var theme = require('../core/theme');
3 |
4 | theme.register('wire', {
5 | 'background': 'black',
6 |
7 | 'color': '#999',
8 | 'stroke': 'none',
9 | 'padding': 10,
10 | 'margin': 20,
11 | 'font-size': 14,
12 |
13 | 'connect-color': '#999',
14 | 'connect-width': 1,
15 |
16 | 'selected-background': '#999',
17 | 'selected-color': 'black',
18 |
19 | 'marquee-background': 'rgba(255,255,255,.3)',
20 | 'marquee-stroke': 'white',
21 |
22 | 'drop-hint-color': 'yellow',
23 | 'sub-drop-hint-width': 2,
24 | 'main-drop-hint-width': 4,
25 | 'root-drop-hint-width': 4,
26 |
27 | 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
28 | 'order-hint-path-color': '#0f0',
29 | 'order-hint-path-width': 1,
30 |
31 | 'text-selection-color': 'rgb(27,171,255)',
32 | 'line-height':1.5
33 | });
34 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/option.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 提供脑图选项支持
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var kity = require('./kity');
11 | var utils = require('./utils');
12 | var Minder = require('./minder');
13 |
14 | Minder.registerInitHook(function(options) {
15 | this._defaultOptions = {};
16 | });
17 |
18 | kity.extendClass(Minder, {
19 | setDefaultOptions: function(options) {
20 | utils.extend(this._defaultOptions, options);
21 | return this;
22 | },
23 | getOption: function(key) {
24 | if (key) {
25 | return key in this._options ? this._options[key] : this._defaultOptions[key];
26 | } else {
27 | return utils.extend({}, this._defaultOptions, this._options);
28 | }
29 | },
30 | setOption: function(key, value) {
31 | this._options[key] = value;
32 | }
33 | });
34 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/minder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * KityMinder 类,暴露在 window 上的唯一变量
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var kity = require('./kity');
11 | var utils = require('./utils');
12 |
13 | var _initHooks = [];
14 |
15 | var Minder = kity.createClass('Minder', {
16 | constructor: function(options) {
17 | this._options = utils.extend({}, options);
18 |
19 | var initHooks = _initHooks.slice();
20 |
21 | var initHook;
22 | while (initHooks.length) {
23 | initHook = initHooks.shift();
24 | if (typeof(initHook) == 'function') {
25 | initHook.call(this, this._options);
26 | }
27 | }
28 |
29 | this.fire('finishInitHook');
30 | }
31 | });
32 |
33 | Minder.version = '1.4.43';
34 |
35 | Minder.registerInitHook = function(hook) {
36 | _initHooks.push(hook);
37 | };
38 |
39 | module.exports = Minder;
40 | });
41 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/store/getters.js:
--------------------------------------------------------------------------------
1 | export const count = state => {
2 | return state.count;
3 | }
4 |
5 | export const working = state => {
6 | return {
7 | saving: state.working.saving,
8 | draging: state.working.draging,
9 | editing: state.working.editing
10 | }
11 | }
12 |
13 | export const config = state => {
14 | return {
15 | ctrlPanelMin: state.config.ctrlPanelMin,
16 | ctrlPanelWidth: state.config.ctrlPanelWidth,
17 | dividerWidth: state.config.dividerWidth,
18 | defaultLang: state.config.defaultLang,
19 | zoom: state.config.zoom,
20 | allowEditPriority: state.config.allowEditPriority,
21 | allowEditLabel: state.config.allowEditLabel,
22 | allowEditResult: state.config.allowEditResult,
23 | allowEditNode: state.config.allowEditNode,
24 | isFullScreen: state.config.isFullScreen
25 | }
26 | }
27 |
28 | export const getMinder = state => {
29 | return state.minder
30 | }
31 |
32 | export const getEditor = state => {
33 | return state.editor
34 | }
35 |
36 | export const getAllowEditResult = state => {
37 | return state.allowEditResult
38 | }
39 |
--------------------------------------------------------------------------------
/kityminder-core/src/template/fish-bone.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 默认模板 - 鱼骨头模板
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var template = require('../core/template');
11 |
12 | template.register('fish-bone', {
13 |
14 | getLayout: function(node) {
15 |
16 | if (node.getData('layout')) return node.getData('layout');
17 |
18 | var level = node.getLevel();
19 |
20 | // 根节点
21 | if (level === 0) {
22 | return 'fish-bone-master';
23 | }
24 |
25 | // 一级节点
26 | if (level === 1) {
27 | return 'fish-bone-slave';
28 | }
29 |
30 | return node.getLayoutPointPreview().y > 0 ? 'filetree-up': 'filetree-down';
31 | },
32 |
33 | getConnect: function(node) {
34 | switch (node.getLevel()) {
35 | case 1: return 'fish-bone-master';
36 | case 2: return 'line';
37 | default: return 'l';
38 | }
39 | }
40 | });
41 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | export const mutations = {
2 |
3 | changeDrag(state, bool) {
4 | state.working.draging = bool;
5 | },
6 |
7 | setMinder(state, data) {
8 | state.minder = data
9 | },
10 |
11 | setEditor(state, data) {
12 | state.editor = data
13 | },
14 |
15 | changeSave(state, bool) {
16 | state.working.saving = bool;
17 | },
18 |
19 | changeCount(state) {
20 | state.count++;
21 | },
22 |
23 | increment(state) {
24 | state.count++
25 | },
26 |
27 | decrement(state) {
28 | state.count--
29 | },
30 |
31 | registerEvent(state, callback) {
32 | state.callbackQueue.push(callback);
33 | },
34 |
35 | setConfig(state, data) {
36 | var supported = Object.keys(state.config);
37 |
38 | for (var key in data) {
39 | if (data.hasOwnProperty(key) && supported.indexOf(key) !== -1) {
40 | state.config[key] = data[key];
41 | } else {
42 | console.error('Unsupported config key: ', key, ', please choose in :', supported.join(', '));
43 | return false;
44 | }
45 | }
46 | return true;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/hotbox/test/SpecRunner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Jasmine Spec Runner v2.1.3
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/tool/debug.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var format = require('./format');
3 |
4 | function noop() {}
5 |
6 | function stringHash(str) {
7 | var hash = 0;
8 | for (var i = 0; i < str.length; i++) {
9 | hash += str.charCodeAt(i);
10 | }
11 | return hash;
12 | }
13 |
14 | function Debug(flag) {
15 | var debugMode = this.flaged = window.location.search.indexOf(flag) != -1;
16 |
17 | if (debugMode) {
18 | var h = stringHash(flag) % 360;
19 |
20 | var flagStyle = format(
21 | 'background: hsl({0}, 50%, 80%); ' +
22 | 'color: hsl({0}, 100%, 30%); ' +
23 | 'padding: 2px 3px; ' +
24 | 'margin: 1px 3px 0 0;' +
25 | 'border-radius: 2px;', h);
26 |
27 | var textStyle = 'background: none; color: black;';
28 | this.log = function () {
29 | var output = format.apply(null, arguments);
30 | console.log(format('%c{0}%c{1}', flag, output), flagStyle, textStyle);
31 | };
32 | } else {
33 | this.log = noop;
34 | }
35 | }
36 |
37 | return module.exports = Debug;
38 | });
39 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/result.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 |
3 | function ResultRuntime() {
4 | var minder = this.minder;
5 | var hotbox = this.hotbox;
6 | var main = hotbox.state("main");
7 | var resultButtonMapper = {
8 | '0': {
9 | label: '移除结果',
10 | key: 'Alt + D'
11 | },
12 | '9': {
13 | label: '成功',
14 | key: 'Alt + G'
15 | },
16 | '1': {
17 | label: '失败',
18 | key: 'Alt + F'
19 | },
20 | '5': {
21 | label: '阻塞',
22 | key: 'Alt + B'
23 | },
24 | '4': {
25 | label: '不执行',
26 | key: 'Alt + S'
27 | }
28 | }
29 |
30 | // 直接加到 main 中,会导致无法显示,但可以保证快捷键可以直接在界面使用
31 | "09154".replace(/./g, function(p) {
32 | main.button({
33 | position: "buttom",
34 | label: resultButtonMapper[p].label,
35 | key: resultButtonMapper[p].key,
36 | action: function() {
37 | minder.execCommand("result", Number(p));
38 | }
39 | });
40 | });
41 | }
42 |
43 | return module.exports = ResultRuntime;
44 | });
45 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/bezier.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 提供折线相连的方法
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | connect.register('bezier', function(node, parent, connection) {
15 |
16 | // 连线起点和终点
17 | var po = parent.getLayoutVertexOut(),
18 | pi = node.getLayoutVertexIn();
19 |
20 | // 连线矢量和方向
21 | var v = parent.getLayoutVectorOut().normalize();
22 |
23 | var r = Math.round;
24 | var abs = Math.abs;
25 |
26 | var pathData = [];
27 | pathData.push('M', r(po.x), r(po.y));
28 |
29 | if (abs(v.x) > abs(v.y)) {
30 | // x - direction
31 | var hx = (pi.x + po.x) / 2;
32 | pathData.push('C', hx, po.y, hx, pi.y, pi.x, pi.y);
33 | } else {
34 | // y - direction
35 | var hy = (pi.y + po.y) / 2;
36 | pathData.push('C', po.x, hy, pi.x, hy, pi.x, pi.y);
37 | }
38 |
39 | connection.setMarker(null);
40 | connection.setPathData(pathData);
41 | });
42 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/progress.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 |
3 | function ProgressRuntime() {
4 | var minder = this.minder;
5 | var hotbox = this.hotbox;
6 |
7 | var main = hotbox.state('main');
8 |
9 | main.button({
10 | position: 'top',
11 | label: '进度',
12 | key: 'G',
13 | next: 'progress',
14 | enable: function () {
15 | return minder.queryCommandState('progress') != -1;
16 | }
17 | });
18 |
19 | var progress = hotbox.state('progress');
20 | '012345678'.replace(/./g, function (p) {
21 | progress.button({
22 | position: 'ring',
23 | label: 'G' + p,
24 | key: p,
25 | action: function () {
26 | minder.execCommand('Progress', parseInt(p) + 1);
27 | }
28 | });
29 | });
30 |
31 | progress.button({
32 | position: 'center',
33 | label: '移除',
34 | key: 'Del',
35 | action: function () {
36 | minder.execCommand('Progress', 0);
37 | }
38 | });
39 |
40 | progress.button({
41 | position: 'top',
42 | label: '返回',
43 | key: 'esc',
44 | next: 'back'
45 | });
46 | }
47 |
48 | return module.exports = ProgressRuntime;
49 |
50 | });
51 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/moveBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
13 |
14 |
45 |
--------------------------------------------------------------------------------
/kityminder-core/src/core/animate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 动画控制
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var Minder = require('./minder');
11 |
12 | var animateDefaultOptions = {
13 | enableAnimation: true,
14 | layoutAnimationDuration: 300,
15 | viewAnimationDuration: 100,
16 | zoomAnimationDuration: 300
17 | };
18 | var resoredAnimationOptions = {};
19 |
20 | Minder.registerInitHook(function() {
21 | this.setDefaultOptions(animateDefaultOptions);
22 | if (!this.getOption('enableAnimation')) {
23 | this.disableAnimation();
24 | }
25 | });
26 |
27 | Minder.prototype.enableAnimation = function() {
28 | for (var name in animateDefaultOptions) {
29 | if (animateDefaultOptions.hasOwnProperty(name)) {
30 | this.setOption(resoredAnimationOptions[name]);
31 | }
32 | }
33 | };
34 |
35 | Minder.prototype.disableAnimation = function() {
36 | for (var name in animateDefaultOptions) {
37 | if (animateDefaultOptions.hasOwnProperty(name)) {
38 | resoredAnimationOptions[name] = this.getOption(name);
39 | this.setOption(name, 0);
40 | }
41 | }
42 | };
43 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/editor.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var runtimes = [];
3 |
4 | function assemble(runtime) {
5 | runtimes.push(runtime);
6 | }
7 |
8 | function KMEditor(selector) {
9 | this.selector = selector;
10 | for (var i = 0; i < runtimes.length; i++) {
11 | if (typeof runtimes[i] == 'function') {
12 | runtimes[i].call(this, this);
13 | }
14 | }
15 | }
16 |
17 | KMEditor.assemble = assemble;
18 |
19 | assemble(require('./runtime/container'));
20 | assemble(require('./runtime/fsm'));
21 | assemble(require('./runtime/minder'));
22 | assemble(require('./runtime/receiver'));
23 | assemble(require('./runtime/hotbox'));
24 | assemble(require('./runtime/input'));
25 | assemble(require('./runtime/clipboard-mimetype'));
26 | assemble(require('./runtime/clipboard'));
27 | assemble(require('./runtime/drag'));
28 | assemble(require('./runtime/node'));
29 | assemble(require('./runtime/history'));
30 | assemble(require('./runtime/jumping'));
31 | assemble(require('./runtime/priority'));
32 | // 为兼容原有滴滴用例,用例结果复用了 progress 这个 key 所以不能出原版 progress 的 hotbox 按钮
33 | // assemble(require('./runtime/progress'));
34 | // 禁用导出功能
35 | // assemble(require('./runtime/exports'));
36 | assemble(require('./runtime/result'));
37 |
38 | return module.exports = KMEditor;
39 | });
40 |
--------------------------------------------------------------------------------
/hotbox/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hotbox",
3 | "title": "Hot Box UI",
4 | "description": "Efficiency And Flexible Editor UI",
5 | "version": "1.0.15",
6 | "homepage": "https://github.com/fex-team/hotbox",
7 | "author": {
8 | "name": "Baidu FEX",
9 | "url": "https://github.com/fex-team"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/fex-team/hotbox.git"
14 | },
15 | "keywords": [
16 | "ui",
17 | "hotbox",
18 | "efficiency",
19 | "flexible",
20 | "javascript",
21 | "library"
22 | ],
23 | "bugs": {
24 | "url": "https://github.com/fex-team/hotbox/issues"
25 | },
26 | "main": "src/mog.js",
27 | "licenses": [
28 | {
29 | "type": "BSD",
30 | "url": "https://github.com/fex-team/hotbox/blob/dev/LICENSE"
31 | }
32 | ],
33 | "dependencies": {},
34 | "devDependencies": {
35 | "grunt": "^0.4.5",
36 | "grunt-autoprefixer": "^2.0.0",
37 | "grunt-contrib-concat": "^0.5.0",
38 | "grunt-contrib-less": "^0.12.0",
39 | "grunt-contrib-uglify": "~0.4.0",
40 | "grunt-contrib-watch": "^0.6.1",
41 | "grunt-module-dependence": "~0.2.0",
42 | "grunt-replace": "^0.8.0",
43 | "less": "~2.1.1",
44 | "watch": "~0.13.0"
45 | },
46 | "scripts": {
47 | "watch-less": "watch \"lessc --source-map less/hotbox.less hotbox.css\" \"less\""
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/kityminder-core/src/core/focus.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('./kity');
3 | var Minder = require('./minder');
4 |
5 | Minder.registerInitHook(function() {
6 | this.on('beforemousedown', function(e) {
7 | this.focus();
8 | e.preventDefault();
9 | });
10 | this.on('paperrender', function() {
11 | this.focus();
12 | });
13 | });
14 |
15 | kity.extendClass(Minder, {
16 | focus: function() {
17 | if (!this.isFocused()) {
18 | var renderTarget = this._renderTarget;
19 | renderTarget.classList.add('focus');
20 | this.renderNodeBatch(this.getSelectedNodes());
21 | }
22 | this.fire('focus');
23 | return this;
24 | },
25 |
26 | blur: function() {
27 | if (this.isFocused()) {
28 | var renderTarget = this._renderTarget;
29 | renderTarget.classList.remove('focus');
30 | this.renderNodeBatch(this.getSelectedNodes());
31 | }
32 | this.fire('blur');
33 | return this;
34 | },
35 |
36 | isFocused: function() {
37 | var renderTarget = this._renderTarget;
38 | return renderTarget && renderTarget.classList.contains('focus');
39 | }
40 | });
41 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/hotbox.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var Hotbox = require('../hotbox');
3 |
4 | function HotboxRuntime() {
5 | var fsm = this.fsm;
6 | var minder = this.minder;
7 | var receiver = this.receiver;
8 | var container = this.container;
9 |
10 | var hotbox = new Hotbox(container);
11 |
12 | hotbox.setParentFSM(fsm);
13 |
14 | fsm.when('normal -> hotbox', function (exit, enter, reason) {
15 | var node = minder.getSelectedNode();
16 | var position;
17 | if (node) {
18 | var box = node.getRenderBox();
19 | position = {
20 | x: box.cx,
21 | y: box.cy
22 | };
23 | }
24 | hotbox.active('main', position);
25 | });
26 |
27 | fsm.when('normal -> normal', function (exit, enter, reason, e) {
28 | if (reason == 'shortcut-handle') {
29 | var handleResult = hotbox.dispatch(e);
30 | if (handleResult) {
31 | e.preventDefault();
32 | } else {
33 | minder.dispatchKeyEvent(e);
34 | }
35 | }
36 | });
37 |
38 | fsm.when('modal -> normal', function (exit, enter, reason, e) {
39 | if (reason == 'import-text-finish') {
40 | receiver.element.focus();
41 | }
42 | });
43 |
44 | this.hotbox = hotbox;
45 | }
46 |
47 | return module.exports = HotboxRuntime;
48 | });
49 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/under.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 下划线连线
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | connect.register('under', function(node, parent, connection, width, color) {
15 |
16 | var box = node.getLayoutBox(),
17 | pBox = parent.getLayoutBox();
18 |
19 | var start, end, vector;
20 | var abs = Math.abs;
21 | var pathData = [];
22 | var side = box.x > pBox.x ? 'right' : 'left';
23 |
24 |
25 | var radius = node.getStyle('connect-radius');
26 | var underY = box.bottom + 3;
27 | var startY = parent.getType() == 'sub' ? pBox.bottom + 3 : pBox.cy;
28 | var p1, p2, p3, mx;
29 |
30 | if (side == 'right') {
31 | p1 = new kity.Point(pBox.right, startY);
32 | p2 = new kity.Point(box.left - 10, underY);
33 | p3 = new kity.Point(box.right, underY);
34 | } else {
35 | p1 = new kity.Point(pBox.left, startY);
36 | p2 = new kity.Point(box.right + 10, underY);
37 | p3 = new kity.Point(box.left, underY);
38 | }
39 |
40 | mx = (p1.x + p2.x) / 2;
41 |
42 | pathData.push('M', p1);
43 | pathData.push('C', mx, p1.y, mx, p2.y, p2);
44 | pathData.push('L', p3);
45 |
46 | connection.setMarker(null);
47 |
48 | connection.setPathData(pathData);
49 | });
50 | });
--------------------------------------------------------------------------------
/kityminder-core/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, FEX, Baidu.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of the KityMinder nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/search/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {main.openSearchBox()}">
6 |
7 |
8 |
9 | 搜索
10 |
11 |
12 | 关键字搜索
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
57 |
58 |
60 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/priority.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 |
3 | function PriorityRuntime() {
4 | var minder = this.minder;
5 | var hotbox = this.hotbox;
6 |
7 | var main = hotbox.state('main');
8 |
9 | main.button({
10 | position: 'top',
11 | label: '用例级别',
12 | key: 'P',
13 | next: 'priority',
14 | enable: function () {
15 | return minder.queryCommandState('priority') != -1;
16 | }
17 | });
18 |
19 | /* var priority = hotbox.state('priority');
20 | '123456789'.replace(/./g, function (p) {
21 | priority.button({
22 | position: 'ring',
23 | label: 'P' + p,
24 | key: p,
25 | action: function () {
26 | minder.execCommand('Priority', p);
27 | }
28 | });
29 | });*/
30 | var priority = hotbox.state('priority');
31 | '012'.replace(/./g, function (p) {
32 | priority.button({
33 | position: 'ring',
34 | label: 'P' + p,
35 | key: p,
36 | action: function () {
37 | minder.execCommand('Priority', Number(p) + 1);
38 | }
39 | });
40 | });
41 |
42 | priority.button({
43 | position: 'top',
44 | label: '移除',
45 | key: 'Del',
46 | action: function () {
47 | minder.execCommand('Priority', 0);
48 | }
49 | });
50 |
51 | priority.button({
52 | position: 'top',
53 | label: '返回',
54 | key: 'esc',
55 | next: 'back'
56 | });
57 | }
58 | return module.exports = PriorityRuntime;
59 | });
60 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/editDel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
13 |
14 |
52 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/tool/keymap.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var keymap = {
3 |
4 | 'Shift': 16,
5 | 'Control': 17,
6 | 'Alt': 18,
7 | 'CapsLock': 20,
8 |
9 | 'BackSpace': 8,
10 | 'Tab': 9,
11 | 'Enter': 13,
12 | 'Esc': 27,
13 | 'Space': 32,
14 |
15 | 'PageUp': 33,
16 | 'PageDown': 34,
17 | 'End': 35,
18 | 'Home': 36,
19 |
20 | 'Insert': 45,
21 |
22 | 'Left': 37,
23 | 'Up': 38,
24 | 'Right': 39,
25 | 'Down': 40,
26 |
27 | 'Direction': {
28 | 37: 1,
29 | 38: 1,
30 | 39: 1,
31 | 40: 1
32 | },
33 |
34 | 'Del': 46,
35 |
36 | 'NumLock': 144,
37 |
38 | 'Cmd': 91,
39 | 'CmdFF': 224,
40 | 'F1': 112,
41 | 'F2': 113,
42 | 'F3': 114,
43 | 'F4': 115,
44 | 'F5': 116,
45 | 'F6': 117,
46 | 'F7': 118,
47 | 'F8': 119,
48 | 'F9': 120,
49 | 'F10': 121,
50 | 'F11': 122,
51 | 'F12': 123,
52 |
53 | '`': 192,
54 | '=': 187,
55 | '-': 189,
56 |
57 | '/': 191,
58 | '.': 190
59 | };
60 |
61 | for (var key in keymap) {
62 | if (keymap.hasOwnProperty(key)) {
63 | keymap[key.toLowerCase()] = keymap[key];
64 | }
65 | }
66 | var aKeyCode = 65;
67 | var aCharCode = 'a'.charCodeAt(0);
68 |
69 | 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function (letter) {
70 | keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
71 | });
72 |
73 | var n = 9;
74 | do {
75 | keymap[n.toString()] = n + 48;
76 | } while (--n);
77 |
78 | module.exports = keymap;
79 | });
80 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/arc.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 圆弧连线
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | var connectMarker = new kity.Marker().pipe(function() {
15 | var r = 7;
16 | var dot = new kity.Circle(r - 1);
17 | this.addShape(dot);
18 | this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
19 | this.dot = dot;
20 | this.node.setAttribute('markerUnits', 'userSpaceOnUse');
21 | });
22 |
23 | connect.register('arc', function(node, parent, connection, width, color) {
24 |
25 | var box = node.getLayoutBox(),
26 | pBox = parent.getLayoutBox();
27 |
28 | var start, end, vector;
29 | var abs = Math.abs;
30 | var pathData = [];
31 | var side = box.x > pBox.x ? 'right' : 'left';
32 |
33 | node.getMinder().getPaper().addResource(connectMarker);
34 |
35 | start = new kity.Point(pBox.cx, pBox.cy);
36 | end = side == 'left' ?
37 | new kity.Point(box.right + 2, box.cy) :
38 | new kity.Point(box.left - 2, box.cy);
39 |
40 | vector = kity.Vector.fromPoints(start, end);
41 | pathData.push('M', start);
42 | pathData.push('A', abs(vector.x), abs(vector.y), 0, 0, (vector.x * vector.y > 0 ? 0 : 1), end);
43 |
44 | connection.setMarker(connectMarker);
45 | connectMarker.dot.fill(color);
46 |
47 | connection.setPathData(pathData);
48 | });
49 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/style/dropdown-list.scss:
--------------------------------------------------------------------------------
1 | .link-dropdown-list,
2 | .img-dropdown-list,
3 | .remark-dropdown-list,
4 | .selection-dropdown-list,
5 | .expand-dropdown-list {
6 | font-size: 12px;
7 | }
8 |
9 | .mold-dropdown-list {
10 | width: 126px;
11 | //height: 170px;
12 | height: auto;
13 | font-size: 12px;
14 | .mold-icons {
15 | background-image: url("../static/minder/mold.png");
16 | background-repeat: no-repeat;
17 | }
18 | .dropdown-item {
19 | display: inline-block;
20 | width: 50px;
21 | //width: 30px;
22 | height: 40px;
23 | padding: 0;
24 | margin: 5px;
25 | }
26 | @for $i from 1 through 6 {
27 | .mold-#{$i} {
28 | background-position: (1-$i) * 50px 0;
29 | }
30 | }
31 | }
32 |
33 | .theme-dropdown-list {
34 | width: 120px;
35 | font-size: 12px;
36 | .mold-icons {
37 | background-repeat: no-repeat;
38 | }
39 | .dropdown-item {
40 | display: inline-block;
41 | width: 100px;
42 | height: 30px;
43 | padding: 0;
44 | margin: 5px;
45 | }
46 | }
47 |
48 | .expand-dropdown-list {
49 | .dropdown-item {
50 | line-height: 25px;
51 | }
52 | }
53 |
54 | .selection-dropdown-list {
55 | .dropdown-item {
56 | line-height: 25px;
57 | }
58 | }
59 |
60 | .theme-group {
61 | background-color: pink;
62 | padding: 0 10px;
63 | }
64 |
65 | //.el-dropdown-menu {
66 | // padding: 10px !important;
67 | // margin: 10px !important;
68 | // //left: 40px !important;
69 | //}
70 | //
71 | //.el-dropdown-menu__item {
72 | // padding: 5px 0 5px 20px !important;
73 | // height: 35px !important;
74 | // line-height: 35px !important;
75 | // margin: 0 !important;
76 | //}
77 |
--------------------------------------------------------------------------------
/kityminder-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kityminder-core",
3 | "title": "Kity Minder Core",
4 | "description": "KityMinder Core Implement",
5 | "version": "1.4.50",
6 | "homepage": "https://github.com/fex-team/kityminder-core",
7 | "author": {
8 | "name": "Baidu FEX",
9 | "url": "http://fex.baidu.com"
10 | },
11 | "main": "dist/kityminder.core.js",
12 | "license": "BSD-3-Clause",
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/fex-team/kityminder-core.git"
16 | },
17 | "keywords": [
18 | "kityminder",
19 | "kity",
20 | "minder",
21 | "svg",
22 | "graphic",
23 | "javascript"
24 | ],
25 | "scripts": {
26 | "dev": "grunt dev",
27 | "build": "grunt build"
28 | },
29 | "bugs": {
30 | "url": "https://github.com/fex-team/kityminder-core/issues"
31 | },
32 | "licenses": [
33 | {
34 | "type": "BSD-3-Clause",
35 | "url": "https://github.com/fex-team/kityminder-core/blob/dev/LICENSE"
36 | }
37 | ],
38 | "dependencies": {
39 | "json-diff": "^0.5.2",
40 | "kity": "^2.0.4",
41 | "seajs": "^2.3.0"
42 | },
43 | "devDependencies": {
44 | "cz-conventional-changelog": "^1.1.5",
45 | "grunt": "^0.4.5",
46 | "grunt-browser-sync": "^2.2.0",
47 | "grunt-contrib-clean": "~0.5.0",
48 | "grunt-contrib-concat": "~0.5.0",
49 | "grunt-contrib-copy": "~0.8.2",
50 | "grunt-contrib-uglify": "~0.4.0",
51 | "grunt-contrib-watch": "^1.0.0",
52 | "grunt-module-dependence": "~0.2.1",
53 | "grunt-replace": "~0.8.0",
54 | "uglify-js": "^2.8.29"
55 | },
56 | "config": {
57 | "commitizen": {
58 | "path": "./node_modules/cz-conventional-changelog"
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/tool/key.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var keymap = require('./keymap');
3 |
4 | var CTRL_MASK = 0x1000;
5 | var ALT_MASK = 0x2000;
6 | var SHIFT_MASK = 0x4000;
7 |
8 | function hash(unknown) {
9 | if (typeof (unknown) == 'string') {
10 | return hashKeyExpression(unknown);
11 | }
12 | return hashKeyEvent(unknown);
13 | }
14 |
15 | function is(a, b) {
16 | return a && b && hash(a) == hash(b);
17 | }
18 | exports.hash = hash;
19 | exports.is = is;
20 |
21 | function hashKeyEvent(keyEvent) {
22 | var hashCode = 0;
23 | if (keyEvent.ctrlKey || keyEvent.metaKey) {
24 | hashCode |= CTRL_MASK;
25 | }
26 | if (keyEvent.altKey) {
27 | hashCode |= ALT_MASK;
28 | }
29 | if (keyEvent.shiftKey) {
30 | hashCode |= SHIFT_MASK;
31 | }
32 | if ([16, 17, 18, 91].indexOf(keyEvent.keyCode) === -1) {
33 | if (keyEvent.keyCode === 229 && keyEvent.keyIdentifier) {
34 | return hashCode |= parseInt(keyEvent.keyIdentifier.substr(2), 16);
35 | }
36 | hashCode |= keyEvent.keyCode;
37 | }
38 | return hashCode;
39 | }
40 |
41 | function hashKeyExpression(keyExpression) {
42 | var hashCode = 0;
43 | keyExpression.toLowerCase().split(/\s*\+\s*/).forEach(function (name) {
44 | switch (name) {
45 | case 'ctrl':
46 | case 'cmd':
47 | hashCode |= CTRL_MASK;
48 | break;
49 | case 'alt':
50 | hashCode |= ALT_MASK;
51 | break;
52 | case 'shift':
53 | hashCode |= SHIFT_MASK;
54 | break;
55 | default:
56 | hashCode |= keymap[name];
57 | }
58 | });
59 | return hashCode;
60 | }
61 | });
62 |
--------------------------------------------------------------------------------
/kityminder-core/README.md:
--------------------------------------------------------------------------------
1 | KityMinder Core
2 | ==========
3 |
4 | ## 简介
5 |
6 | KityMinder 是一款强大的脑图可视化/编辑工具,由百度 FEX 团队开发并维护。
7 |
8 | 本仓库是 KityMinder 的核心实现部分:
9 |
10 | * 包括脑图数据的可视化展示(Json 格式)
11 | * 包括简单的编辑功能(节点创建、编辑、删除)。更加强大编辑功能的 KityMinder 编辑器请移步 [kityminder-editor](https://github.com/fex-team/kityminder-editor)
12 | * 不包含第三方格式(FreeMind、XMind、MindManager)的支持,可以加载 [kityminder-protocol](https://github.com/fex-team/kityminder-third-party-protocol) 来扩展第三方格式支持。
13 | * 不包含文件存储的支持,需要自行实现存储。可参照[百度脑图](https://naotu.baidu.com)中的开源的 fio + 百度网盘方案进行实现。
14 |
15 | ## 使用
16 |
17 | 可以参考 [example.html](example.html) 进行使用。
18 |
19 | ```js
20 |
21 |
22 |
27 | ```
28 |
29 | 更多详细的开发资料可以参考 [wiki](https://github.com/fex-team/kityminder-core/wiki)
30 |
31 | ## 兼容性
32 |
33 | KityMinder 基于 SVG 技术实现,支持绝大多数的 HTML5 浏览器,包括:
34 |
35 | 1. Chrome
36 | 2. Firefox
37 | 3. Safari
38 | 4. Internet Explorer 10 或以上
39 |
40 | ## 使用说明
41 |
42 | kityminder-core 依赖于 [kity](https://github.com/fex-team/kity),开发中用到 seajs 进行异步加载。
43 | 例子中 dev.html 使用 seajs 进行包加载,example.html 使用同步加载的方式。
44 | 使用步骤如下:
45 |
46 | 1. 安装 [bower](http://bower.io/#install-bower)
47 | 2. 切换到 kityminder-core 目录下,运行:
48 |
49 | ```bash
50 | bower install
51 | ```
52 |
53 | ## 开发说明
54 |
55 | 1. 安装 [bower](http://bower.io/#install-bower)
56 | 2. 安装 [npm](https://www.npmjs.com/get-npm)
57 |
58 | ```bash
59 | bower install
60 | npm install
61 | npm run dev
62 | ```
63 |
64 | ## 联系我们
65 |
66 | 问题和建议反馈:[Github Issues](https://github.com/fex-team/kityminder-core/issues)
67 | 邮件组: kity@baidu.com
68 | QQ 讨论群: 374918234
69 |
--------------------------------------------------------------------------------
/hotbox/src/keymap.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var keymap = {
3 |
4 | 'Shift': 16,
5 | 'Control': 17,
6 | 'Alt': 18,
7 | 'CapsLock': 20,
8 |
9 | 'BackSpace': 8,
10 | 'Tab': 9,
11 | 'Enter': 13,
12 | 'Esc': 27,
13 | 'Space': 32,
14 |
15 | 'PageUp': 33,
16 | 'PageDown': 34,
17 | 'End': 35,
18 | 'Home': 36,
19 |
20 | 'Insert': 45,
21 |
22 | 'Left': 37,
23 | 'Up': 38,
24 | 'Right': 39,
25 | 'Down': 40,
26 |
27 | 'Direction': {
28 | 37: 1,
29 | 38: 1,
30 | 39: 1,
31 | 40: 1
32 | },
33 |
34 | 'Delete': 46,
35 |
36 | 'NumLock': 144,
37 |
38 | 'Cmd': 91,
39 | 'CmdFF': 224,
40 | 'F1': 112,
41 | 'F2': 113,
42 | 'F3': 114,
43 | 'F4': 115,
44 | 'F5': 116,
45 | 'F6': 117,
46 | 'F7': 118,
47 | 'F8': 119,
48 | 'F9': 120,
49 | 'F10': 121,
50 | 'F11': 122,
51 | 'F12': 123,
52 |
53 | '`': 192,
54 | '=': 187,
55 | '-': 189,
56 |
57 | '/': 191,
58 | '.': 190
59 | };
60 |
61 | // 小写适配
62 | for (var key in keymap) {
63 | if (keymap.hasOwnProperty(key)) {
64 | keymap[key.toLowerCase()] = keymap[key];
65 | }
66 | }
67 | var aKeyCode = 65;
68 | var aCharCode = 'a'.charCodeAt(0);
69 |
70 | // letters
71 | 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
72 | keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
73 | });
74 |
75 | // numbers
76 | var n = 9;
77 | do {
78 | keymap[n.toString()] = n + 48;
79 | } while (n--);
80 |
81 | module.exports = keymap;
82 | });
--------------------------------------------------------------------------------
/hotbox/src/key.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var keymap = require('./keymap');
3 |
4 | var CTRL_MASK = 0x1000;
5 | var ALT_MASK = 0x2000;
6 | var SHIFT_MASK = 0x4000;
7 |
8 | function hash(unknown) {
9 | if (typeof(unknown) == 'string') {
10 | return hashKeyExpression(unknown);
11 | }
12 | return hashKeyEvent(unknown);
13 | }
14 | function is(a, b) {
15 | return a && b && hash(a) == hash(b);
16 | }
17 | exports.hash = hash;
18 | exports.is = is;
19 |
20 |
21 | function hashKeyEvent(keyEvent) {
22 | var hashCode = 0;
23 | if (keyEvent.ctrlKey || keyEvent.metaKey) {
24 | hashCode |= CTRL_MASK;
25 | }
26 | if (keyEvent.altKey) {
27 | hashCode |= ALT_MASK;
28 | }
29 | if (keyEvent.shiftKey) {
30 | hashCode |= SHIFT_MASK;
31 | }
32 | // Shift, Control, Alt KeyCode ignored.
33 | if ([16, 17, 18, 91].indexOf(keyEvent.keyCode) == -1) {
34 | hashCode |= keyEvent.keyCode;
35 | }
36 | return hashCode;
37 | }
38 |
39 | function hashKeyExpression(keyExpression) {
40 | var hashCode = 0;
41 | keyExpression.toLowerCase().split(/\s*\+\s*/).forEach(function(name) {
42 | switch(name) {
43 | case 'ctrl':
44 | case 'cmd':
45 | hashCode |= CTRL_MASK;
46 | break;
47 | case 'alt':
48 | hashCode |= ALT_MASK;
49 | break;
50 | case 'shift':
51 | hashCode |= SHIFT_MASK;
52 | break;
53 | default:
54 | hashCode |= keymap[name];
55 | }
56 | });
57 | return hashCode;
58 | }
59 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/status.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 状态切换控制
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('./kity');
12 | var Minder = require('./minder');
13 |
14 | var sf = ~window.location.href.indexOf('status');
15 | var tf = ~window.location.href.indexOf('trace');
16 |
17 | Minder.registerInitHook(function() {
18 | this._initStatus();
19 | });
20 |
21 | kity.extendClass(Minder, {
22 |
23 | _initStatus: function() {
24 | this._status = 'normal';
25 | this._rollbackStatus = 'normal';
26 | },
27 |
28 | setStatus: function(status, force) {
29 | // 在 readonly 模式下,只有 force 为 true 才能切换回来
30 | if (this._status == 'readonly' && !force) return this;
31 | if (status != this._status) {
32 | this._rollbackStatus = this._status;
33 | this._status = status;
34 | this.fire('statuschange', {
35 | lastStatus: this._rollbackStatus,
36 | currentStatus: this._status
37 | });
38 | if (sf) {
39 | /* global console: true */
40 | console.log(window.event.type, this._rollbackStatus, '->', this._status);
41 | if (tf) {
42 | console.trace();
43 | }
44 | }
45 | }
46 | return this;
47 | },
48 |
49 | rollbackStatus: function() {
50 | this.setStatus(this._rollbackStatus);
51 | },
52 | getRollbackStatus:function(){
53 | return this._rollbackStatus;
54 | },
55 | getStatus: function() {
56 | return this._status;
57 | }
58 | });
59 |
60 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/expand.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
22 |
23 |
24 |
25 |
26 |
27 |
50 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/protocol/svg.js:
--------------------------------------------------------------------------------
1 | function exportSVG(minder) {
2 |
3 | var paper = minder.getPaper();
4 | var paperTransform = paper.shapeNode.getAttribute('transform');
5 | var svgXml;
6 | var $svg;
7 |
8 | var renderContainer = minder.getRenderContainer();
9 | var renderBox = renderContainer.getRenderBox();
10 | var transform = renderContainer.getTransform();
11 | var width = renderBox.width;
12 | var height = renderBox.height;
13 | var padding = 20;
14 |
15 | paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
16 | svgXml = paper.container.innerHTML;
17 | console.log(svgXml);
18 | paper.shapeNode.setAttribute('transform', paperTransform);
19 |
20 | $svg = $(svgXml).filter('svg');
21 | $svg.attr({
22 | width: width + padding * 2 | 0,
23 | height: height + padding * 2 | 0,
24 | style: 'font-family: Arial, "Microsoft Yahei", "Heiti SC"; background: ' + minder.getStyle('background')
25 | });
26 | $svg[0].setAttribute('viewBox', [renderBox.x - padding | 0,
27 | renderBox.y - padding | 0,
28 | width + padding * 2 | 0,
29 | height + padding * 2 | 0
30 | ].join(' '));
31 |
32 | svgXml = $('').append($svg).html();
33 | svgXml = $('').append($svg).html();
34 | svgXml = svgXml.replace(/ /g, ' ');
35 |
36 | var blob = new Blob([svgXml], {
37 | type: 'image/svg+xml'
38 | });
39 |
40 | var DOMURL = window.URL || window.webkitURL || window;
41 | var svgUrl = DOMURL.createObjectURL(blob);
42 |
43 | var mind = editor.minder.exportJson();
44 | downloadSVG(svgUrl, mind.root.data.text);
45 | }
46 |
47 | function downloadSVG(fileURI, fileName) {
48 | try {
49 | const link = document.createElement('a');
50 | link.href = fileURI;
51 | link.download = `${fileName}.svg`;
52 | document.body.appendChild(link);
53 | link.click();
54 | document.body.removeChild(link);
55 | } catch (err) {
56 | alert(err);
57 | }
58 | }
59 |
60 | export {
61 | exportSVG
62 | }
63 |
--------------------------------------------------------------------------------
/kityminder-core/src/connect/poly.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 提供折线相连的方法
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var connect = require('../core/connect');
13 |
14 | connect.register('poly', function(node, parent, connection, width) {
15 |
16 | // 连线起点和终点
17 | var po = parent.getLayoutVertexOut(),
18 | pi = node.getLayoutVertexIn();
19 |
20 | // 连线矢量和方向
21 | var v = parent.getLayoutVectorOut().normalize();
22 |
23 | var r = Math.round;
24 | var abs = Math.abs;
25 |
26 | var pathData = [];
27 | pathData.push('M', r(po.x), r(po.y));
28 |
29 | switch (true) {
30 | case abs(v.x) > abs(v.y) && v.x < 0:
31 | // left
32 | pathData.push('h', -parent.getStyle('margin-left'));
33 | pathData.push('v', pi.y - po.y);
34 | pathData.push('H', pi.x);
35 | break;
36 |
37 | case abs(v.x) > abs(v.y) && v.x >= 0:
38 | // right
39 | pathData.push('h', parent.getStyle('margin-right'));
40 | pathData.push('v', pi.y - po.y);
41 | pathData.push('H', pi.x);
42 | break;
43 |
44 | case abs(v.x) <= abs(v.y) && v.y < 0:
45 | // top
46 | pathData.push('v', -parent.getStyle('margin-top'));
47 | pathData.push('h', pi.x - po.x);
48 | pathData.push('V', pi.y);
49 | break;
50 |
51 | case abs(v.x) <= abs(v.y) && v.y >= 0:
52 | // bottom
53 | pathData.push('v', parent.getStyle('margin-bottom'));
54 | pathData.push('h', pi.x - po.x);
55 | pathData.push('V', pi.y);
56 | break;
57 |
58 | }
59 |
60 | connection.setMarker(null);
61 | connection.setPathData(pathData);
62 | });
63 | });
--------------------------------------------------------------------------------
/hotbox/hotbox.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["less/hotbox.less"],"names":[],"mappings":"AACA;EACI,oBAAoB,oBAAoB,mBAAmB,iCAA3D;EACA,kBAAA;EACA,OAAA;EACA,MAAA;EACA,iBAAA;;AALJ,OAMI;EACI,kBAAA;EACA,iBAAA;EACA,aAAA;;AATR,OAMI,OAII,QACI;AAXZ,OAMI,OAIa,MACL;EACI,kBAAA;EACA,WAAA;EACA,YAAA;EACA,kBAAA;EACA,iBAAA;EACA,mBAAA;EACA,uCAAA;;AAlBhB,OAMI,OAII,QAUI;AApBZ,OAMI,OAIa,MAUL;AApBZ,OAMI,OAII,QAUY;AApBpB,OAMI,OAIa,MAUG;EACJ,cAAA;EACA,kBAAA;EACA,kBAAA;EACA,sBAAA;;AAxBhB,OAMI,OAII,QAgBI;AA1BZ,OAMI,OAIa,MAgBL;EACI,eAAA;EACA,gBAAA;EACA,YAAA;EACA,mBAAA;EACA,gBAAA;;AA/BhB,OAMI,OAII,QAuBI;AAjCZ,OAMI,OAIa,MAuBL;EACI,eAAA;EACA,WAAA;;AAnChB,OAMI,OAgCI;EACI,kBAAA;EACA,WAAA;EACA,UAAA;EACA,qCAAA;EACA,mBAAA;EACA,uBAAA;;AA5CZ,OAMI,OAwCI;AA9CR,OAMI,OAwCU;EACF,kBAAA;EACA,mBAAA;;AAhDZ,OAMI,OAwCI,KAGI;AAjDZ,OAMI,OAwCU,QAGF;EACI,qBAAA;EACA,iBAAA;EACA,cAAA;EACA,mBAAA;EACA,uCAAA;EACA,kBAAA;;AAvDhB,OAMI,OAwCI,KAGI,QAQI;AAzDhB,OAMI,OAwCU,QAGF,QAQI;EACI,eAAA;EACA,iBAAA;EACA,sBAAA;EACA,YAAA;EACA,gBAAA;;AA9DpB,OAMI,OAwCI,KAGI,QAeI;AAhEhB,OAMI,OAwCU,QAGF,QAeI;EACI,eAAA;EACA,iBAAA;EACA,sBAAA;EACA,WAAA;EACA,gBAAA;;AACA,OAhEhB,OAwCI,KAGI,QAeI,KAMK;AAAD,OAhEhB,OAwCU,QAGF,QAeI,KAMK;EACG,SAAS,GAAT;;AAEJ,OAnEhB,OAwCI,KAGI,QAeI,KASK;AAAD,OAnEhB,OAwCU,QAGF,QAeI,KASK;EACG,SAAS,GAAT;;AA1ExB,OAMI,OAyEI;EACI,mBAAA;EACA,gBAAA;EACA,eAAA;;AAlFZ,OAMI,OAyEI,QAKI;AApFZ,OAMI,OAyEI,QAKU;EACF,YAAA;;AArFhB,OAMI,OAkFI,QAAO;EACH,iBAAA;;AAzFZ,OAMI,OAkFI,QAAO,QAGH;AA3FZ,OAMI,OAkFI,QAAO,QAGG;EACF,UAAA;;AAGJ,OAzFR,OAkFI,QAAO,QAOF;EACG,mBAAA;;AADJ,OAzFR,OAkFI,QAAO,QAOF,MAEG;EACI,YAAA;;AAHR,OAzFR,OAkFI,QAAO,QAOF,MAKG;EACI,cAAA;;AAGR,OAlGR,OAkFI,QAAO,QAgBF;EACG,oCAAA;EACA,mBAAA;;AAFJ,OAlGR,OAkFI,QAAO,QAgBF,SAGG;EACI,YAAA;;AAJR,OAlGR,OAkFI,QAAO,QAgBF,SAMG;EACI,cAAA;;AAGR,OA5GR,OAkFI,QAAO,QA0BF;AAAU,OA5GnB,OAkFI,QAAO,QA0BS;EACR,mBAAA;;AADJ,OA5GR,OAkFI,QAAO,QA0BF,QAEG;AAFO,OA5GnB,OAkFI,QAAO,QA0BS,OAER;EACI,YAAA;;AAHR,OA5GR,OAkFI,QAAO,QA0BF,QAKG;AALO,OA5GnB,OAkFI,QAAO,QA0BS,OAKR;EACI,cAAA;;AAxHpB,OA6HI,OAAM;EACF,cAAA;;AAIR;EACI;IAAK,WAAW,QAAX;;EACL;IAAM,WAAW,UAAX;;EACN;IAAO,WAAW,QAAX;;;AAGX;EACI,kBAAA;EACA,eAAA;EACA,cAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,SAAA","file":"hotbox.css"}
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/exports.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var png = require("../protocol/png");
3 | var svg = require("../protocol/svg");
4 | var json = require("../protocol/json");
5 | var plain = require("../protocol/plain");
6 | var md = require("../protocol/markdown");
7 | var mm = require("../protocol/freemind");
8 |
9 | function ExportRuntime() {
10 | var minder = this.minder;
11 | var hotbox = this.hotbox;
12 | var exps = [
13 | {label: '.json', key: 'j', cmd: exportJson},
14 | {label: '.png', key: 'p', cmd: exportImage},
15 | {label: '.svg', key: 's', cmd: exportSVG},
16 | {label: '.txt', key: 't', cmd: exportTextTree},
17 | {label: '.md', key: 'm', cmd: exportMarkdown},
18 | {label: '.mm', key: 'f', cmd: exportFreeMind}
19 | ];
20 |
21 | var main = hotbox.state('main');
22 | main.button({
23 | position: 'top',
24 | label: '导出',
25 | key: 'E',
26 | enable: canExp,
27 | next: 'exp'
28 | });
29 |
30 | var exp = hotbox.state('exp');
31 | exps.forEach(item => {
32 | exp.button({
33 | position: 'ring',
34 | label: item.label,
35 | key: null,
36 | action: item.cmd
37 | });
38 | });
39 |
40 | exp.button({
41 | position: 'center',
42 | label: '取消',
43 | key: 'esc',
44 | next: 'back'
45 | });
46 |
47 | function canExp() {
48 | return true;
49 | }
50 |
51 | function exportJson(){
52 | json.exportJson(minder);
53 | }
54 |
55 | function exportImage (){
56 | png.exportPNGImage(minder);
57 | }
58 |
59 | function exportSVG (){
60 | svg.exportSVG(minder);
61 | }
62 |
63 | function exportTextTree (){
64 | plain.exportTextTree(minder);
65 | }
66 |
67 | function exportMarkdown (){
68 | md.exportMarkdown(minder);
69 | }
70 |
71 | function exportFreeMind (){
72 | mm.exportFreeMind(minder);
73 | }
74 | }
75 |
76 | return module.exports = ExportRuntime;
77 | });
78 |
--------------------------------------------------------------------------------
/kityminder-core/src/core/utils.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports) {
2 | var kity = require('./kity');
3 | var uuidMap = {};
4 |
5 | exports.extend = kity.Utils.extend.bind(kity.Utils);
6 | exports.each = kity.Utils.each.bind(kity.Utils);
7 |
8 | exports.uuid = function(group) {
9 | uuidMap[group] = uuidMap[group] ? uuidMap[group] + 1 : 1;
10 | return group + uuidMap[group];
11 | };
12 |
13 | exports.guid = function() {
14 | return (+new Date() * 1e6 + Math.floor(Math.random() * 1e6)).toString(36);
15 | };
16 |
17 | exports.trim = function(str) {
18 | return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
19 | };
20 |
21 | exports.keys = function(plain) {
22 | var keys = [];
23 | for (var key in plain) {
24 | if (plain.hasOwnProperty(key)) {
25 | keys.push(key);
26 | }
27 | }
28 | return keys;
29 | };
30 |
31 | exports.clone = function(source) {
32 | return JSON.parse(JSON.stringify(source));
33 | };
34 |
35 | exports.comparePlainObject = function(a, b) {
36 | return JSON.stringify(a) == JSON.stringify(b);
37 | };
38 |
39 | exports.encodeHtml = function(str, reg) {
40 | return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function(a, b) {
41 | if (b) {
42 | return a;
43 | } else {
44 | return {
45 | '<': '<',
46 | '&': '&',
47 | '"': '"',
48 | '>': '>',
49 | '\'': '''
50 | }[a];
51 | }
52 | }) : '';
53 | };
54 |
55 | exports.clearWhiteSpace = function(str) {
56 | return str.replace(/[\u200b\t\r\n]/g, '');
57 | };
58 |
59 | exports.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function(v) {
60 | var toString = Object.prototype.toString;
61 | exports['is' + v] = function(obj) {
62 | return toString.apply(obj) == '[object ' + v + ']';
63 | };
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/progressBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
76 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/sequenceBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
82 |
--------------------------------------------------------------------------------
/hotbox/src/keycontrol.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 |
3 | var key = require('./key');
4 | var FOCUS_CLASS = 'hotbox-focus';
5 | var RECEIVER_CLASS = 'hotbox-key-receiver';
6 |
7 | function KeyControl(hotbox) {
8 | var _this = this;
9 | var _receiver;
10 | var _actived = true;
11 | var _receiverIsSelfCreated = false;
12 | var $container = hotbox.$container;
13 |
14 | _createReceiver();
15 | _bindReceiver();
16 | _bindContainer();
17 | _active();
18 |
19 | function _createReceiver() {
20 | _receiver = document.createElement('input');
21 | _receiver.classList.add(RECEIVER_CLASS);
22 | $container.appendChild(_receiver);
23 | _receiverIsSelfCreated = true;
24 | }
25 |
26 | function _bindReceiver() {
27 | _receiver.onkeyup = _handle;
28 | _receiver.onkeypress = _handle;
29 | _receiver.onkeydown = _handle;
30 | _receiver.onfocus = _active;
31 | _receiver.onblur = _deactive;
32 | if (_receiverIsSelfCreated) {
33 | _receiver.oninput = function(e) { _receiver.value = null; };
34 | }
35 | }
36 |
37 | function _bindContainer() {
38 | $container.onmousedown = function(e) {
39 | _active();
40 | e.preventDefault();
41 | };
42 | }
43 |
44 | function _handle(keyEvent) {
45 | if (!_actived) return;
46 | hotbox.dispatch(keyEvent);
47 | }
48 |
49 | function _active() {
50 | _receiver.select();
51 | _receiver.focus();
52 | _actived = true;
53 | $container.classList.add(FOCUS_CLASS);
54 | }
55 |
56 | function _deactive() {
57 | _receiver.blur();
58 | _actived = false;
59 | $container.classList.remove(FOCUS_CLASS);
60 | }
61 |
62 | this.handle = _handle;
63 | this.active = _active;
64 | this.deactive = _deactive;
65 | }
66 |
67 | module.exports = KeyControl;
68 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/keyreceiver.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('./kity');
3 | var utils = require('./utils');
4 | var Minder = require('./minder');
5 |
6 | function listen(element, type, handler) {
7 | type.split(' ').forEach(function(name) {
8 | element.addEventListener(name, handler, false);
9 | });
10 | }
11 |
12 | Minder.registerInitHook(function(option) {
13 | this.setDefaultOptions({
14 | enableKeyReceiver: true
15 | });
16 | if (this.getOption('enableKeyReceiver')) {
17 | this.on('paperrender', function() {
18 | this._initKeyReceiver();
19 | });
20 | }
21 | });
22 |
23 | kity.extendClass(Minder, {
24 | _initKeyReceiver: function() {
25 |
26 | if (this._keyReceiver) return;
27 |
28 | var receiver = this._keyReceiver = document.createElement('input');
29 | receiver.classList.add('km-receiver');
30 |
31 | var renderTarget = this._renderTarget;
32 | renderTarget.appendChild(receiver);
33 |
34 | var minder = this;
35 |
36 | listen(receiver, 'keydown keyup keypress copy paste blur focus input', function(e) {
37 | switch (e.type) {
38 | case 'blur':
39 | minder.blur();
40 | break;
41 | case 'focus':
42 | minder.focus();
43 | break;
44 | case 'input':
45 | receiver.value = null;
46 | break;
47 | }
48 | minder._firePharse(e);
49 | e.preventDefault();
50 | });
51 |
52 | this.on('focus', function() {
53 | receiver.select();
54 | receiver.focus();
55 | });
56 | this.on('blur', function() {
57 | receiver.blur();
58 | });
59 |
60 | if (this.isFocused()) {
61 | receiver.select();
62 | receiver.focus();
63 | }
64 | }
65 | });
66 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/view/styleOperation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
16 |
17 |
18 |
19 |
20 |
65 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/protocol/xmind.js:
--------------------------------------------------------------------------------
1 | var priorities = [
2 | {jp: 1, mp: 'full-1'},
3 | {jp: 2, mp: 'full-2'},
4 | {jp: 3, mp: 'full-3'},
5 | {jp: 4, mp: 'full-4'},
6 | {jp: 5, mp: 'full-5'},
7 | {jp: 6, mp: 'full-6'},
8 | {jp: 7, mp: 'full-7'},
9 | {jp: 8, mp: 'full-8'}
10 | ];
11 | var mmVersion = '';
20 |
21 | function exportXMind(minder) {
22 | var minds = minder.exportJson();
23 | var mmContent = mmVersion + traverseJson(minds.root) + entityNode + entityMap;
24 | try {
25 | const link = document.createElement('a');
26 | const blob = new Blob(["\ufeff" + mmContent], {
27 | type: 'text/xml'
28 | });
29 | link.href = window.URL.createObjectURL(blob);
30 | link.download = `${minds.root.data.text}.mm`;
31 | document.body.appendChild(link);
32 | link.click();
33 | document.body.removeChild(link);
34 | } catch (err) {
35 | alert(err);
36 | }
37 | }
38 |
39 | function traverseJson(node){
40 | var result = "";
41 | if (!node) {
42 | return;
43 | }
44 | result += concatNodes(node);
45 | if (node.children && node.children.length > 0) {
46 | for (var i = 0; i < node.children.length; i++) {
47 | result += traverseJson(node.children[i]);
48 | result += entityNode;
49 | }
50 | }
51 | return result;
52 | }
53 |
54 | function concatNodes(node) {
55 | var result = "";
56 | var datas = node.data;
57 | result += nodeCreated + datas.created + nodeId + datas.id + nodeText + datas.text + nodeSuffix;
58 | if (datas.priority) {
59 | var mapped = priorities.find(d => {
60 | return d.jp == datas.priority
61 | });
62 | if (mapped) {
63 | result += iconTextPrefix + mapped.mp + iconTextSuffix;
64 | }
65 | }
66 | return result;
67 | }
68 |
69 | export {
70 | exportXMind
71 | }
72 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/protocol/freemind.js:
--------------------------------------------------------------------------------
1 | var priorities = [
2 | {jp: 1, mp: 'full-1'},
3 | {jp: 2, mp: 'full-2'},
4 | {jp: 3, mp: 'full-3'},
5 | {jp: 4, mp: 'full-4'},
6 | {jp: 5, mp: 'full-5'},
7 | {jp: 6, mp: 'full-6'},
8 | {jp: 7, mp: 'full-7'},
9 | {jp: 8, mp: 'full-8'}
10 | ];
11 | var mmVersion = '';
20 |
21 | function exportFreeMind(minder) {
22 | var minds = minder.exportJson();
23 | var mmContent = mmVersion + traverseJson(minds.root) + entityNode + entityMap;
24 | try {
25 | const link = document.createElement('a');
26 | const blob = new Blob(["\ufeff" + mmContent], {
27 | type: 'text/xml'
28 | });
29 | link.href = window.URL.createObjectURL(blob);
30 | link.download = `${minds.root.data.text}.mm`;
31 | document.body.appendChild(link);
32 | link.click();
33 | document.body.removeChild(link);
34 | } catch (err) {
35 | alert(err);
36 | }
37 | }
38 |
39 | function traverseJson(node){
40 | var result = "";
41 | if (!node) {
42 | return;
43 | }
44 | result += concatNodes(node);
45 | if (node.children && node.children.length > 0) {
46 | for (var i = 0; i < node.children.length; i++) {
47 | result += traverseJson(node.children[i]);
48 | result += entityNode;
49 | }
50 | }
51 | return result;
52 | }
53 |
54 | function concatNodes(node) {
55 | var result = "";
56 | var datas = node.data;
57 | result += nodeCreated + datas.created + nodeId + datas.id + nodeText + datas.text + nodeSuffix;
58 | if (datas.priority) {
59 | var mapped = priorities.find(d => {
60 | return d.jp == datas.priority
61 | });
62 | if (mapped) {
63 | result += iconTextPrefix + mapped.mp + iconTextSuffix;
64 | }
65 | }
66 | return result;
67 | }
68 |
69 | export {
70 | exportFreeMind
71 | }
72 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/main/mainEditor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
74 |
75 |
78 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/insertBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
15 |
16 |
17 |
18 |
74 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/editMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
83 |
--------------------------------------------------------------------------------
/kityminder-core/src/layout/mind.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('../core/kity');
3 | var Layout = require('../core/layout');
4 | var Minder = require('../core/minder');
5 |
6 | Layout.register('mind', kity.createClass({
7 | base: Layout,
8 |
9 | doLayout: function(node, children) {
10 | var layout = this;
11 | var half = Math.ceil(node.children.length / 2);
12 | var right = [];
13 | var left = [];
14 |
15 | children.forEach(function(child) {
16 | if (child.getIndex() < half) right.push(child);
17 | else left.push(child);
18 | });
19 |
20 | var leftLayout = Minder.getLayoutInstance('left');
21 | var rightLayout = Minder.getLayoutInstance('right');
22 |
23 | leftLayout.doLayout(node, left);
24 | rightLayout.doLayout(node, right);
25 |
26 | var box = node.getContentBox();
27 | node.setVertexOut(new kity.Point(box.cx, box.cy));
28 | node.setLayoutVectorOut(new kity.Vector(0, 0));
29 | },
30 |
31 | getOrderHint: function(node) {
32 | var hint = [];
33 | var box = node.getLayoutBox();
34 | var offset = 5;
35 |
36 | hint.push({
37 | type: 'up',
38 | node: node,
39 | area: new kity.Box({
40 | x: box.x,
41 | y: box.top - node.getStyle('margin-top') - offset,
42 | width: box.width,
43 | height: node.getStyle('margin-top')
44 | }),
45 | path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
46 | });
47 |
48 | hint.push({
49 | type: 'down',
50 | node: node,
51 | area: new kity.Box({
52 | x: box.x,
53 | y: box.bottom + offset,
54 | width: box.width,
55 | height: node.getStyle('margin-bottom')
56 | }),
57 | path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
58 | });
59 | return hint;
60 | }
61 | }));
62 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/backAndRight.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 |
15 |
69 |
70 |
72 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/view/mold.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
20 |
21 |
22 |
23 |
56 |
--------------------------------------------------------------------------------
/kityminder-core/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | KityMinder Example
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 |
53 |
54 |
55 |
56 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/hotbox/README.md:
--------------------------------------------------------------------------------
1 | 热盒 UI
2 | ====
3 |
4 | 热盒 UI 是一种高效的上下文交互方式,在最大化编辑区域的同时(再也不需要臃肿的工具栏了)允许全键盘操作。
5 |
6 | 
7 |
8 | ## 使用示例
9 |
10 | ```js
11 | var hotbox = new HotBox('#editor');
12 |
13 | var main = hotbox.state('main');
14 | main.button({
15 | position: 'center',
16 | action: function() {
17 | // 编辑动作
18 | },
19 | label: '编辑',
20 | key: 'F2',
21 | next: 'idle'
22 | });
23 |
24 | hotbox.active('main', { x: 300, y: 300 });
25 | ```
26 |
27 | ## HotBox 类
28 |
29 | 用于构建热盒 UI。
30 |
31 | ### 构造函数 `HotBox.constructor`
32 |
33 | 直接使用 `new` 关键字创建 HotBox 实例。
34 |
35 | ```js
36 | var hotbox = new HotBox(selector);
37 | ```
38 |
39 | 构造函数接受一个**「必须」**的参数 `selector`,表示热盒渲染的位置。热盒创建之后的状态是 `idle`,这个状态下热盒是不可见的。
40 |
41 | ### 定义和获取状态 `state()` 方法
42 |
43 | 热盒在某个时刻有且只有一个状态(`state`),默认状态为 `idle`,此时热盒空闲,不会渲染,并且监听着按键,准备着进行定义的动作。用户需要通过 `state()` 方法来定义状态。
44 |
45 | ```js
46 | var main = hotbox.state('main');
47 | ```
48 |
49 | 该方法需要指定一个状态名称,返回指定名称的 `HotBoxState` 对象,该对象可以用于进一步定义状态。
50 |
51 | 热盒会自动把 `main` 状态作为主要状态,会在 `idle` 状态下监听 `main` 状态定义的按键。建议用户定义并使用 `main` 状态。
52 |
53 | ### 设置热盒当前状态 `active()` 方法
54 |
55 | 热盒默认在 `idle` 状态上,使用 `active` 方法,使热盒进入指定的状态。
56 |
57 | ```js
58 | hotbox.active('main', {x: 400, y: 400});
59 | ```
60 |
61 | 方法的完整签名为 `active(name, position)`。表示让热盒在 `position` 焦点位置渲染指定的状态。`position` 需要有 `x` 和 `y` 属性。
62 |
63 | ## HotBoxState 类
64 |
65 | `HotBoxState` 类用户无法创建,调用 `HotBox` 的 `.state()` 方法时返回。
66 |
67 | ### 为状态添加按钮 `button()`
68 |
69 | 使用 `button()` 方法为状态添加一个按钮。
70 |
71 | ```js
72 | var main = hotbox.state('main');
73 | main.button({
74 | label: '编辑',
75 | key: 'F2',
76 | action: function() { /* 执行的动作 */ }
77 | next: 'idle'
78 | });
79 | ```
80 |
81 | 下面是 `option` 对象支持的字段:
82 |
83 | 配置 | 类型 | 说明
84 | --- | --- | ---
85 | option.position | `String` | 按钮的位置。允许在以下位置:
`center` - 按钮在圆心处,只能定义一个
`ring` - 按钮在圆环处,能定义多个
`top` - 按钮在上栏,能定义多个
`bottom` - 按钮在下栏,能定义多个
86 | option.label | `String` | 按钮的标签文本
87 | option.key | `String` | 按钮的快捷键
88 | option.render | `Function` | 按钮的渲染器,如果指定,将使用指定的渲染器。如果不指定,将渲染标签。
渲染器需要返回按钮的 HTML 代码。
89 | option.enable | `Function` | 按钮是否可用的查询函数,如果不指定,则按钮始终可用。函数需要返回一个 `bool` 类型的值,来决定按钮是否可用。
90 | option.action | `Function` | 按钮执行的操作
91 | option.next | `string` | 操作执行之后热盒到达的状态。如不指定,默认到达 `idle`。可使用该参数来跳转到多级热盒。可以取值为 `back`
92 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/clipboard-mimetype.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | function MimeType() {
3 | var SPLITOR = '\uFEFF';
4 | var MIMETYPE = {
5 | 'application/km': '\uFFFF'
6 | };
7 | var SIGN = {
8 | '\uFEFF': 'SPLITOR',
9 | '\uFFFF': 'application/km'
10 | };
11 |
12 | function process(mimetype, text) {
13 | if (!this.isPureText(text)) {
14 | var _mimetype = this.whichMimeType(text);
15 | if (!_mimetype) {
16 | throw new Error('unknow mimetype!');
17 | };
18 | text = this.getPureText(text);
19 | };
20 | if (mimetype === false) {
21 | return text;
22 | };
23 | return mimetype + SPLITOR + text;
24 | }
25 |
26 | this.registMimeTypeProtocol = function (type, sign) {
27 | if (sign && SIGN[sign]) {
28 | throw new Error('sing has registed!');
29 | }
30 | if (type && !!MIMETYPE[type]) {
31 | throw new Error('mimetype has registed!');
32 | };
33 | SIGN[sign] = type;
34 | MIMETYPE[type] = sign;
35 | }
36 |
37 | this.getMimeTypeProtocol = function (type, text) {
38 | var mimetype = MIMETYPE[type] || false;
39 |
40 | if (text === undefined) {
41 | return process.bind(this, mimetype);
42 | };
43 |
44 | return process(mimetype, text);
45 | }
46 |
47 | this.getSpitor = function () {
48 | return SPLITOR;
49 | }
50 |
51 | this.getMimeType = function (sign) {
52 | if (sign !== undefined) {
53 | return SIGN[sign] || null;
54 | };
55 | return MIMETYPE;
56 | }
57 | }
58 |
59 | MimeType.prototype.isPureText = function (text) {
60 | return !(~text.indexOf(this.getSpitor()));
61 | }
62 |
63 | MimeType.prototype.getPureText = function (text) {
64 | if (this.isPureText(text)) {
65 | return text;
66 | };
67 | return text.split(this.getSpitor())[1];
68 | }
69 |
70 | MimeType.prototype.whichMimeType = function (text) {
71 | if (this.isPureText(text)) {
72 | return null;
73 | };
74 | return this.getMimeType(text.split(this.getSpitor())[0]);
75 | }
76 |
77 | function MimeTypeRuntime() {
78 | if (this.minder.supportClipboardEvent && !kity.Browser.gecko) {
79 | this.MimeType = new MimeType();
80 | };
81 | }
82 |
83 | return module.exports = MimeTypeRuntime;
84 | });
85 |
--------------------------------------------------------------------------------
/kityminder-core/.jscsrc:
--------------------------------------------------------------------------------
1 | /**
2 | * FEX Style Guide (Javascript)
3 | *
4 | * TODO:
5 | *
6 | * 1. 找不到选项:每行只允许一个语句
7 | * 2. 找不到选项:块状代码需要用大括号括起来
8 | */
9 | {
10 | // 缩进「MUST」使用 4 个空格
11 | "validateIndentation": 4,
12 |
13 | // 大括号(块状代码)前「MUST」使用空格
14 | "requireSpaceBeforeBlockStatements": true,
15 |
16 | // 下列关键字「MUST」使用空格
17 | "requireSpaceAfterKeywords": ["if", "else", "for", "while",
18 | "do", "try", "catch", "finally"
19 | ],
20 |
21 | // `,` 和 `;` 前面不允许「MUST NOT」使用空格。
22 | "requireLeftStickedOperators": [",", ";"],
23 |
24 | // 二元运算符前后「MUST」使用空格
25 | "requireSpaceBeforeBinaryOperators": [
26 | "+",
27 | "-",
28 | "*",
29 | "/",
30 | "=",
31 | "==",
32 | "===",
33 | "!=",
34 | "!==",
35 | "|",
36 | "||",
37 | "&",
38 | "&&"
39 | ],
40 | "requireSpaceAfterBinaryOperators": [
41 | "+",
42 | "-",
43 | "*",
44 | "/",
45 | "=",
46 | "==",
47 | "===",
48 | "!=",
49 | "!==",
50 | "|",
51 | "||",
52 | "&",
53 | "&&",
54 | ":"
55 | ],
56 |
57 | // 一元运算符与操作对象间「MUST NOT」使用空格
58 | "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
59 |
60 | // 函数参数小括号前「MUST NOT」使用空格
61 | "disallowSpacesInFunctionExpression": {
62 | "beforeOpeningRoundBrace": true
63 | },
64 |
65 | // 小括号里面「MUST NOT」使用空格
66 | "disallowSpacesInsideParentheses": true,
67 |
68 | // 行尾「MUST NOT」使用空格
69 | "disallowTrailingWhitespace": true,
70 |
71 | // 每行「MUST NOT」超过 120 个字符
72 | "maximumLineLength": 120,
73 |
74 | // 一下操作符「MUST NOT」放在一行的最前面,需要放在上一行的后面
75 | "requireOperatorBeforeLineBreak": [
76 | "?",
77 | "+",
78 | "-",
79 | "/",
80 | "*",
81 | "=",
82 | "==",
83 | "===",
84 | "!=",
85 | "!==",
86 | ">",
87 | ">=",
88 | "<",
89 | "<=",
90 | ",",
91 | ";",
92 | "&&",
93 | "&",
94 | "||",
95 | "|"
96 | ],
97 |
98 | // 字符串统一「MUST」使用单引号
99 | "validateQuoteMarks": "'",
100 |
101 | // 「MUST NOT」使用多行字符串
102 | "disallowMultipleLineStrings": true
103 | }
--------------------------------------------------------------------------------
/kityminder-core/src/core/paper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 初始化渲染容器
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function(require, exports, module) {
10 | var kity = require('./kity');
11 | var utils = require('./utils');
12 | var Minder = require('./minder');
13 |
14 | Minder.registerInitHook(function() {
15 | this._initPaper();
16 | });
17 |
18 | kity.extendClass(Minder, {
19 |
20 | _initPaper: function() {
21 |
22 | this._paper = new kity.Paper();
23 | this._paper._minder = this;
24 | this._paper.getNode().ondragstart = function(e) {
25 | e.preventDefault();
26 | };
27 | this._paper.shapeNode.setAttribute('transform', 'translate(0.5, 0.5)');
28 |
29 | this._addRenderContainer();
30 |
31 | this.setRoot(this.createNode());
32 |
33 | if (this._options.renderTo) {
34 | this.renderTo(this._options.renderTo);
35 | }
36 | },
37 |
38 | _addRenderContainer: function() {
39 | this._rc = new kity.Group().setId(utils.uuid('minder'));
40 | this._paper.addShape(this._rc);
41 | },
42 |
43 | renderTo: function(target) {
44 | if (typeof(target) == 'string') {
45 | target = document.querySelector(target);
46 | }
47 | if (target) {
48 | if (target.tagName.toLowerCase() == 'script') {
49 | var newTarget = document.createElement('div');
50 | newTarget.id = target.id;
51 | newTarget.class = target.class;
52 | target.parentNode.insertBefore(newTarget, target);
53 | target.parentNode.removeChild(target);
54 | target = newTarget;
55 | }
56 | target.classList.add('km-view');
57 | this._paper.renderTo(this._renderTarget = target);
58 | this._bindEvents();
59 | this.fire('paperrender');
60 | }
61 | return this;
62 | },
63 |
64 | getRenderContainer: function() {
65 | return this._rc;
66 | },
67 |
68 | getPaper: function() {
69 | return this._paper;
70 | },
71 |
72 | getRenderTarget: function() {
73 | return this._renderTarget;
74 | },
75 | });
76 | });
--------------------------------------------------------------------------------
/kityminder-core/dev.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | KityMinder Example
6 |
7 |
8 |
9 |
10 |
26 |
27 |
28 |
29 |
30 |
53 |
54 |
55 |
56 |
57 |
71 |
--------------------------------------------------------------------------------
/kityminder-core/src/layout/fish-bone-master.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 鱼骨图主骨架布局
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var Layout = require('../core/layout');
13 |
14 | Layout.register('fish-bone-master', kity.createClass('FishBoneMasterLayout', {
15 | base: Layout,
16 |
17 | doLayout: function(parent, children, round) {
18 |
19 | var upPart = [],
20 | downPart = [];
21 |
22 | var child = children[0];
23 | var pBox = parent.getContentBox();
24 |
25 | parent.setVertexOut(new kity.Point(pBox.right, pBox.cy));
26 | parent.setLayoutVectorOut(new kity.Vector(1, 0));
27 |
28 | if (!child) return;
29 |
30 | var cBox = child.getContentBox();
31 | var pMarginRight = parent.getStyle('margin-right');
32 | var cMarginLeft = child.getStyle('margin-left');
33 | var cMarginTop = child.getStyle('margin-top');
34 | var cMarginBottom = child.getStyle('margin-bottom');
35 |
36 | children.forEach(function(child, index) {
37 | child.setLayoutTransform(new kity.Matrix());
38 | var cBox = child.getContentBox();
39 |
40 | if (index % 2) {
41 | downPart.push(child);
42 | child.setVertexIn(new kity.Point(cBox.left, cBox.top));
43 | child.setLayoutVectorIn(new kity.Vector(1, 1));
44 | }
45 | else {
46 | upPart.push(child);
47 | child.setVertexIn(new kity.Point(cBox.left, cBox.bottom));
48 | child.setLayoutVectorIn(new kity.Vector(1, -1));
49 | }
50 |
51 | });
52 |
53 | this.stack(upPart, 'x');
54 | this.stack(downPart, 'x');
55 |
56 | this.align(upPart, 'bottom');
57 | this.align(downPart, 'top');
58 |
59 | var xAdjust = pBox.right + pMarginRight + cMarginLeft;
60 | var yAdjustUp = pBox.cy - cMarginBottom - parent.getStyle('margin-top');
61 | var yAdjustDown = pBox.cy + cMarginTop + parent.getStyle('margin-bottom');
62 |
63 | this.move(upPart, xAdjust, yAdjustUp);
64 | this.move(downPart, xAdjust + cMarginLeft, yAdjustDown);
65 | }
66 | }));
67 |
68 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/node.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | function NodeRuntime() {
3 | var runtime = this;
4 | var minder = this.minder;
5 | var hotbox = this.hotbox;
6 | var fsm = this.fsm;
7 |
8 | var main = hotbox.state('main');
9 |
10 | var buttons = [
11 | '前移:Alt+Up:ArrangeUp',
12 | '下级:Tab|Insert:AppendChildNode',
13 | '同级:Enter:AppendSiblingNode',
14 | '后移:Alt+Down:ArrangeDown',
15 | '删除:Delete|Backspace:RemoveNode',
16 | '上级:Shift+Tab|Shift+Insert:AppendParentNode'
17 | ];
18 |
19 | var AppendLock = 0;
20 |
21 | buttons.forEach(function (button) {
22 | var parts = button.split(':');
23 | var label = parts.shift();
24 | var key = parts.shift();
25 | var command = parts.shift();
26 | main.button({
27 | position: 'ring',
28 | label: label,
29 | key: key,
30 | action: function () {
31 | if (command.indexOf('Append') === 0) {
32 | AppendLock++;
33 | minder.execCommand(command, '分支主题');
34 |
35 | function afterAppend() {
36 | if (!--AppendLock) {
37 | runtime.editText();
38 | }
39 | minder.off('layoutallfinish', afterAppend);
40 | }
41 | minder.on('layoutallfinish', afterAppend);
42 | } else {
43 | minder.execCommand(command);
44 | fsm.jump('normal', 'command-executed');
45 | }
46 | },
47 | enable: function () {
48 | return minder.queryCommandState(command) != -1;
49 | }
50 | });
51 | });
52 |
53 | main.button({
54 | position: 'ring',
55 | key: '/',
56 | action: function () {
57 | if (!minder.queryCommandState('expand')) {
58 | minder.execCommand('expand');
59 | } else if (!minder.queryCommandState('collapse')) {
60 | minder.execCommand('collapse');
61 | }
62 | },
63 | enable: function () {
64 | return minder.queryCommandState('expand') != -1 || minder.queryCommandState('collapse') != -1;
65 | },
66 | beforeShow: function () {
67 | if (!minder.queryCommandState('expand')) {
68 | this.$button.children[0].innerHTML = '展开';
69 | } else {
70 | this.$button.children[0].innerHTML = '收起';
71 | }
72 | }
73 | })
74 | }
75 |
76 | return module.exports = NodeRuntime;
77 | });
78 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/noteBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 备注
7 |
8 |
9 | 插入备注
10 | 移除已有备注
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
91 |
92 |
94 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/store/actions.js:
--------------------------------------------------------------------------------
1 | export const actions = {
2 | changeCount: ({
3 | commit
4 | }) => commit('changeCount'),
5 |
6 | increment: ({
7 | commit
8 | }) => commit('increment'),
9 |
10 | decrement: ({
11 | commit
12 | }) => commit('decrement'),
13 |
14 | incrementIfOdd({
15 | commit,
16 | state
17 | }) {
18 | if ((state.count + 1) % 2 === 0) {
19 | commit('increment')
20 | }
21 | },
22 |
23 | incrementAsync({
24 | commit
25 | }) {
26 | return new Promise((resolve, reject) => {
27 | setTimeout(() => {
28 | commit('increment')
29 | resolve()
30 | }, 1000)
31 | })
32 | },
33 |
34 | setConfig: ({
35 | commit
36 | }) => commit('setConfig'),
37 |
38 | registerEvent: ({
39 | commit
40 | }) => commit('registerEvent', callback),
41 |
42 | executeCallback({
43 | commit,
44 | state
45 | }) {
46 | state.callbackQueue.forEach(function (ele) {
47 | ele.apply(this, arguments);
48 | })
49 | },
50 |
51 | isQuotaExceeded(e) {
52 | var quotaExceeded = false;
53 | if (e) {
54 | if (e.code) {
55 | switch (e.code) {
56 | case 22:
57 | quotaExceeded = true;
58 | break;
59 | case 1014:
60 | // Firefox
61 | if (e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
62 | quotaExceeded = true;
63 | }
64 | break;
65 | }
66 | } else if (e.number === -2147024882) {
67 | // Internet Explorer 8
68 | quotaExceeded = true;
69 | }
70 | }
71 | return quotaExceeded;
72 | index
73 | },
74 |
75 | getMemory({
76 | commit,
77 | state
78 | }, key) {
79 | var value = window.localStorage.getItem(key);
80 | var result = null || JSON.parse(value)
81 | console.log('action:' + result);
82 | return result;
83 | },
84 |
85 | setMemory({
86 | commit,
87 | state
88 | }, data) {
89 | try {
90 | window.localStorage.setItem(data.key, JSON.stringify(data.value));
91 | return true;
92 | } catch (e) {
93 | if (this.isQuotaExceeded(e)) {
94 | return false;
95 | }
96 | }
97 | },
98 |
99 | removeMemory(key) {
100 | var value = window.localStorage.getItem(key);
101 | window.localStorage.removeItem(key);
102 | return value;
103 | },
104 |
105 | clearMemory() {
106 | window.localStorage.clear();
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/kityminder-core/src/layout/fish-bone-slave.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | *
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var Layout = require('../core/layout');
13 |
14 | Layout.register('fish-bone-slave', kity.createClass('FishBoneSlaveLayout', {
15 | base: Layout,
16 |
17 | doLayout: function (parent, children, round) {
18 |
19 | var layout = this;
20 | var abs = Math.abs;
21 | var GOLD_CUT = 1 - 0.618;
22 |
23 | var pBox = parent.getContentBox();
24 | var vi = parent.getLayoutVectorIn();
25 |
26 | parent.setLayoutVectorOut(vi);
27 |
28 | var goldX = pBox.left + pBox.width * GOLD_CUT;
29 | var pout = new kity.Point(goldX, vi.y > 0 ? pBox.bottom : pBox.top);
30 | parent.setVertexOut(pout);
31 |
32 | var child = children[0];
33 | if (!child) return;
34 |
35 | var cBox = child.getContentBox();
36 |
37 | children.forEach(function(child, index) {
38 | child.setLayoutTransform(new kity.Matrix());
39 | child.setLayoutVectorIn(new kity.Vector(1, 0));
40 | child.setVertexIn(new kity.Point(cBox.left, cBox.cy));
41 | });
42 |
43 | this.stack(children, 'y');
44 | this.align(children, 'left');
45 |
46 | var xAdjust = 0, yAdjust = 0;
47 | xAdjust += pout.x;
48 |
49 | if (parent.getLayoutVectorOut().y < 0) {
50 | yAdjust -= this.getTreeBox(children).bottom;
51 | yAdjust += parent.getContentBox().top;
52 | yAdjust -= parent.getStyle('margin-top');
53 | yAdjust -= child.getStyle('margin-bottom');
54 | } else {
55 | yAdjust += parent.getContentBox().bottom;
56 | yAdjust += parent.getStyle('margin-bottom');
57 | yAdjust += child.getStyle('margin-top');
58 | }
59 |
60 | this.move(children, xAdjust, yAdjust);
61 |
62 | if (round == 2) {
63 | children.forEach(function(child) {
64 | var m = child.getLayoutTransform();
65 | var cbox = child.getContentBox();
66 | var pin = m.transformPoint(new kity.Point(cbox.left, 0));
67 | layout.move([child], abs(pin.y - pout.y), 0);
68 | });
69 | }
70 | }
71 | }));
72 | });
--------------------------------------------------------------------------------
/kityminder-core/src/module/layout.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 布局模块
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('../core/kity');
12 | var Command = require('../core/command');
13 | var Module = require('../core/module');
14 |
15 | /**
16 | * @command Layout
17 | * @description 设置选中节点的布局
18 | * 允许使用的布局可以使用 `kityminder.Minder.getLayoutList()` 查询
19 | * @param {string} name 布局的名称,设置为 null 则使用继承或默认的布局
20 | * @state
21 | * 0: 当前有选中的节点
22 | * -1: 当前没有选中的节点
23 | * @return 返回首个选中节点的布局名称
24 | */
25 | var LayoutCommand = kity.createClass('LayoutCommand', {
26 | base: Command,
27 |
28 | execute: function(minder, name) {
29 | var nodes = minder.getSelectedNodes();
30 | nodes.forEach(function(node) {
31 | node.layout(name);
32 | });
33 | },
34 |
35 | queryValue: function(minder) {
36 | var node = minder.getSelectedNode();
37 | if (node) {
38 | return node.getData('layout');
39 | }
40 | },
41 |
42 | queryState: function(minder) {
43 | return minder.getSelectedNode() ? 0 : -1;
44 | }
45 | });
46 |
47 | /**
48 | * @command ResetLayout
49 | * @description 重设选中节点的布局,如果当前没有选中的节点,重设整个脑图的布局
50 | * @state
51 | * 0: 始终可用
52 | * @return 返回首个选中节点的布局名称
53 | */
54 | var ResetLayoutCommand = kity.createClass('ResetLayoutCommand', {
55 | base: Command,
56 |
57 | execute: function(minder) {
58 | var nodes = minder.getSelectedNodes();
59 |
60 | if (!nodes.length) nodes = [minder.getRoot()];
61 |
62 | nodes.forEach(function(node) {
63 | node.traverse(function(child) {
64 | child.resetLayoutOffset();
65 | if (!child.isRoot()) {
66 | child.setData('layout', null);
67 | }
68 | });
69 | });
70 | minder.layout(300);
71 | },
72 |
73 | enableReadOnly: true
74 | });
75 |
76 | Module.register('LayoutModule', {
77 | commands: {
78 | 'layout': LayoutCommand,
79 | 'resetlayout': ResetLayoutCommand
80 | },
81 | contextmenu: [{
82 | command: 'resetlayout'
83 | }, {
84 | divider: true
85 | }],
86 |
87 | commandShortcutKeys: {
88 | 'resetlayout': 'Ctrl+Shift+L'
89 | }
90 | });
91 |
92 | });
--------------------------------------------------------------------------------
/kityminder-core/src/theme/fresh.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('../core/kity');
3 | var theme = require('../core/theme');
4 |
5 | function hsl(h, s, l) {
6 | return kity.Color.createHSL(h, s, l);
7 | }
8 |
9 | function generate(h, compat) {
10 | return {
11 | 'background': '#fbfbfb',
12 |
13 | 'root-color': 'white',
14 | 'root-background': hsl(h, 37, 60),
15 | 'root-stroke': hsl(h, 37, 60),
16 | 'root-font-size': 16,
17 | 'root-padding': compat ? [6, 12] : [12, 24],
18 | 'root-margin': compat ? 10 : [30, 100],
19 | 'root-radius': 5,
20 | 'root-space': 10,
21 |
22 | 'main-color': 'black',
23 | 'main-background': hsl(h, 33, 95),
24 | 'main-stroke': hsl(h, 37, 60),
25 | 'main-stroke-width': 1,
26 | 'main-font-size': 14,
27 | 'main-padding': [6, 20],
28 | 'main-margin': compat ? 8 : 20,
29 | 'main-radius': 3,
30 | 'main-space': 5,
31 |
32 | 'sub-color': 'black',
33 | 'sub-background': 'transparent',
34 | 'sub-stroke': 'none',
35 | 'sub-font-size': 12,
36 | 'sub-padding': compat ? [3, 5] : [5, 10],
37 | 'sub-margin': compat ? [4, 8] : [15, 20],
38 | 'sub-radius': 5,
39 | 'sub-space': 5,
40 |
41 | 'connect-color': hsl(h, 37, 60),
42 | 'connect-width': 1,
43 | 'connect-radius': 5,
44 |
45 | 'selected-stroke': hsl(h, 26, 30),
46 | 'selected-stroke-width': '3',
47 | 'blur-selected-stroke': hsl(h, 10, 60),
48 |
49 | 'marquee-background': hsl(h, 100, 80).set('a', 0.1),
50 | 'marquee-stroke': hsl(h, 37, 60),
51 |
52 | 'drop-hint-color': hsl(h, 26, 35),
53 | 'drop-hint-width': 5,
54 |
55 | 'order-hint-area-color': hsl(h, 100, 30).set('a', 0.5),
56 | 'order-hint-path-color': hsl(h, 100, 25),
57 | 'order-hint-path-width': 1,
58 |
59 | 'text-selection-color': hsl(h, 100, 20),
60 | 'line-height':1.5
61 | };
62 | }
63 |
64 | var plans = {
65 | red: 0,
66 | soil: 25,
67 | green: 122,
68 | blue: 204,
69 | purple: 246,
70 | pink: 334
71 | };
72 | var name;
73 | for (name in plans) {
74 | theme.register('fresh-' + name, generate(plans[name]));
75 | theme.register('fresh-' + name + '-compat', generate(plans[name], true));
76 | }
77 |
78 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/compatibility.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var utils = require('./utils');
3 |
4 | function compatibility(json) {
5 |
6 | var version = json.version || (json.root ? '1.4.0' : '1.1.3');
7 |
8 | switch (version) {
9 | case '1.1.3':
10 | c_113_120(json);
11 | /* falls through */
12 | case '1.2.0':
13 | case '1.2.1':
14 | c_120_130(json);
15 | /* falls through */
16 | case '1.3.0':
17 | case '1.3.1':
18 | case '1.3.2':
19 | case '1.3.3':
20 | case '1.3.4':
21 | case '1.3.5':
22 | /* falls through */
23 | c_130_140(json);
24 | }
25 | return json;
26 | }
27 |
28 | function traverse(node, fn) {
29 | fn(node);
30 | if (node.children) node.children.forEach(function(child) {
31 | traverse(child, fn);
32 | });
33 | }
34 |
35 | /* 脑图数据升级 */
36 | function c_120_130(json) {
37 | traverse(json, function(node) {
38 | var data = node.data;
39 | delete data.layout_bottom_offset;
40 | delete data.layout_default_offset;
41 | delete data.layout_filetree_offset;
42 | });
43 | }
44 |
45 | /**
46 | * 脑图数据升级
47 | * v1.1.3 => v1.2.0
48 | * */
49 | function c_113_120(json) {
50 | // 原本的布局风格
51 | var ocs = json.data.currentstyle;
52 | delete json.data.currentstyle;
53 |
54 | // 为 1.2 选择模板,同时保留老版本文件的皮肤
55 | if (ocs == 'bottom') {
56 | json.template = 'structure';
57 | json.theme = 'snow';
58 | } else if (ocs == 'default') {
59 | json.template = 'default';
60 | json.theme = 'classic';
61 | }
62 |
63 | traverse(json, function(node) {
64 | var data = node.data;
65 |
66 | // 升级优先级、进度图标
67 | if ('PriorityIcon' in data) {
68 | data.priority = data.PriorityIcon;
69 | delete data.PriorityIcon;
70 | }
71 | if ('ProgressIcon' in data) {
72 | data.progress = 1 + ((data.ProgressIcon - 1) << 1);
73 | delete data.ProgressIcon;
74 | }
75 |
76 | // 删除过时属性
77 | delete data.point;
78 | delete data.layout;
79 | });
80 | }
81 |
82 | function c_130_140(json) {
83 | json.root = {
84 | data: json.data,
85 | children: json.children
86 | };
87 | delete json.data;
88 | delete json.children;
89 | }
90 |
91 | return compatibility;
92 | });
--------------------------------------------------------------------------------
/kityminder-core/src/layout/tianpan.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 天盘模板
5 | *
6 | * @author: along
7 | * @copyright: bpd729@163.com, 2015
8 | */
9 | define(function(require, exports, module) {
10 | var kity = require('../core/kity');
11 | var Layout = require('../core/layout');
12 | var Minder = require('../core/minder');
13 |
14 | Layout.register('tianpan', kity.createClass({
15 | base: Layout,
16 |
17 | doLayout: function (parent, children) {
18 | if (children.length == 0) return;
19 |
20 | var layout = this;
21 | var pbox = parent.getContentBox();
22 |
23 | var x, y,box;
24 | var _theta = 5;
25 | var _r = Math.max(pbox.width, 50);
26 | children.forEach(function (child, index) {
27 | child.setLayoutTransform(new kity.Matrix());
28 | box = layout.getTreeBox(child);
29 | _r = Math.max(Math.max(box.width, box.height), _r);
30 | })
31 | _r = _r / 1.5 / Math.PI;
32 |
33 | children.forEach(function (child, index) {
34 | x = _r * (Math.cos(_theta) + Math.sin(_theta) * _theta);
35 | y = _r * (Math.sin(_theta) - Math.cos(_theta) * _theta);
36 |
37 | _theta += (0.9 - index * 0.02);
38 | child.setLayoutVectorIn(new kity.Vector(1, 0));
39 | child.setVertexIn(new kity.Point(pbox.cx, pbox.cy));
40 | child.setLayoutTransform(new kity.Matrix());
41 | layout.move([child], x, y);
42 | });
43 | },
44 |
45 | getOrderHint: function (node) {
46 | var hint = [];
47 | var box = node.getLayoutBox();
48 | var offset = 5;
49 |
50 | hint.push({
51 | type: 'up',
52 | node: node,
53 | area: {
54 | x: box.x,
55 | y: box.top - node.getStyle('margin-top') - offset,
56 | width: box.width,
57 | height: node.getStyle('margin-top')
58 | },
59 | path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
60 | });
61 |
62 | hint.push({
63 | type: 'down',
64 | node: node,
65 | area: {
66 | x: box.x,
67 | y: box.bottom + offset,
68 | width: box.width,
69 | height: node.getStyle('margin-bottom')
70 | },
71 | path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
72 | });
73 | return hint;
74 | }
75 | }));
76 | });
--------------------------------------------------------------------------------
/kityminder-core/src/connect/arc_tp.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * 圆弧连线
4 | *
5 | * @author: along
6 | * @copyright: bpd729@163.com , 2015
7 | */
8 | define(function(require, exports, module) {
9 | var kity = require('../core/kity');
10 | var connect = require('../core/connect');
11 |
12 | var connectMarker = new kity.Marker().pipe(function () {
13 | var r = 7;
14 | var dot = new kity.Circle(r - 1);
15 | this.addShape(dot);
16 | this.setRef(r - 1, 0).setViewBox(-r, -r, r + r, r + r).setWidth(r).setHeight(r);
17 | this.dot = dot;
18 | this.node.setAttribute('markerUnits', 'userSpaceOnUse');
19 | });
20 |
21 | /**
22 | * 天盘图连线除了连接当前节点和前一个节点外, 还需要渲染当前节点和后一个节点的连接, 防止样式上的断线
23 | * 这是天盘图与其余的模板不同的地方
24 | */
25 | connect.register('arc_tp', function (node, parent, connection, width, color) {
26 | var end_box = node.getLayoutBox(),
27 | start_box = parent.getLayoutBox();
28 |
29 | var index = node.getIndex();
30 | var nextNode = parent.getChildren()[index + 1];
31 |
32 |
33 | if (node.getIndex() > 0) {
34 | start_box = parent.getChildren()[index - 1].getLayoutBox();
35 | }
36 |
37 |
38 | var start, end, vector;
39 | var abs = Math.abs;
40 | var pathData = [];
41 | var side = end_box.x > start_box.x ? 'right' : 'left';
42 |
43 | node.getMinder().getPaper().addResource(connectMarker);
44 |
45 |
46 | start = new kity.Point(start_box.cx, start_box.cy);
47 | end = new kity.Point(end_box.cx, end_box.cy);
48 |
49 | var jl = Math.sqrt(Math.pow((start.x - end.x), 2) + Math.pow((start.y - end.y), 2)); //两圆中心点距离
50 |
51 | jl = node.getIndex() == 0 ? jl * 0.4 : jl;
52 |
53 |
54 | vector = kity.Vector.fromPoints(start, end);
55 | pathData.push('M', start);
56 | pathData.push('A', jl, jl, 0, 0, 1, end);
57 |
58 |
59 | connection.setMarker(connectMarker);
60 | connectMarker.dot.fill(color);
61 | connection.setPathData(pathData);
62 |
63 |
64 | // 设置下一个的节点的连接线
65 | if (nextNode && nextNode.getConnection()) {
66 | var nextConnection = nextNode.getConnection();
67 | var next_end_box = nextNode.getLayoutBox();
68 | var next_end = new kity.Point(next_end_box.cx, next_end_box.cy);
69 |
70 | var jl2 = Math.sqrt(Math.pow((end.x - next_end.x), 2) + Math.pow((end.y - next_end.y), 2)); //两圆中心点距离
71 |
72 | pathData = [];
73 |
74 | pathData.push('M', end);
75 | pathData.push('A', jl2, jl2, 0, 0, 1, next_end);
76 |
77 | nextConnection.setMarker(connectMarker);
78 | connectMarker.dot.fill(color);
79 |
80 | nextConnection.setPathData(pathData);
81 |
82 | }
83 |
84 | });
85 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-testcase-minder-editor",
3 | "version": "0.3.14",
4 | "private": false,
5 | "author": "chenhengjie",
6 | "main": "lib/VueTestcaseMinderEditor.umd.min.js",
7 | "files": [
8 | "lib/VueTestcaseMinderEditor.umd.min.js",
9 | "lib/VueTestcaseMinderEditor.css",
10 | "lib/fonts/*",
11 | "lib/img/*"
12 | ],
13 | "scripts": {
14 | "serve": "vue-cli-service serve",
15 | "build": "vue-cli-service build",
16 | "lint": "vue-cli-service lint",
17 | "lib": "vue-cli-service build --target lib --name VueTestcaseMinderEditor --dest lib packages/VueTestcaseMinderEditor/index.js && mv lib/VueTestcaseMinderEditor.umd.min.js lib/VueTestcaseMinderEditor.umd.min.js.bak && babel --plugins transform-object-rest-spread lib/VueTestcaseMinderEditor.umd.min.js.bak > lib/VueTestcaseMinderEditor.umd.min.js",
18 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
19 | },
20 | "dependencies": {
21 | "codemirror": "^5.24.2",
22 | "color-picker": "0.0.1",
23 | "core-js": "^3.6.5",
24 | "element-ui": "^2.12.0",
25 | "jquery": "^3.2.0",
26 | "json-diff": "^0.5.4",
27 | "kity": "^2.0.4",
28 | "marked": "^0.3.6",
29 | "screenfull": "^5.0.2",
30 | "vue": "^2.6.11",
31 | "vue-markdown": "^2.2.4",
32 | "vue-router": "^3.2.0",
33 | "vuex": "^3.1.0"
34 | },
35 | "devDependencies": {
36 | "@vue/cli-plugin-babel": "~4.5.0",
37 | "@vue/cli-plugin-eslint": "~4.5.0",
38 | "@vue/cli-plugin-router": "~4.5.0",
39 | "@vue/cli-service": "~4.5.0",
40 | "@vue/eslint-config-standard": "^5.1.2",
41 | "babel-cli": "^6.26.0",
42 | "babel-eslint": "^10.1.0",
43 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
44 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
45 | "babel-plugin-syntax-jsx": "^6.18.0",
46 | "babel-plugin-transform-imports": "1.5.0",
47 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
48 | "babel-plugin-transform-vue-jsx": "^3.7.0",
49 | "babel-polyfill": "^6.26.0",
50 | "babel-preset-env": "^1.3.2",
51 | "babel-preset-es2015": "^6.24.1",
52 | "babel-preset-stage-2": "^6.24.1",
53 | "babel-register": "^6.26.0",
54 | "conventional-changelog-cli": "^2.1.1",
55 | "eslint": "^6.7.2",
56 | "eslint-plugin-import": "^2.20.2",
57 | "eslint-plugin-node": "^11.1.0",
58 | "eslint-plugin-promise": "^4.2.1",
59 | "eslint-plugin-standard": "^4.0.0",
60 | "eslint-plugin-vue": "^6.2.2",
61 | "less": "^3.12.2",
62 | "less-loader": "^7.1.0",
63 | "node-sass": "^4.9.0",
64 | "sass-loader": "^7.0.1",
65 | "vue-template-compiler": "^2.6.11"
66 | },
67 | "eslintConfig": {
68 | "root": true,
69 | "env": {
70 | "node": true
71 | },
72 | "extends": [
73 | "plugin:vue/essential",
74 | "@vue/standard"
75 | ],
76 | "parserOptions": {
77 | "parser": "babel-eslint"
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/kityminder-core/src/core/keymap.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var keymap = {
3 | 'Backspace': 8,
4 | 'Tab': 9,
5 | 'Enter': 13,
6 |
7 | 'Shift': 16,
8 | 'Control': 17,
9 | 'Alt': 18,
10 | 'CapsLock': 20,
11 |
12 | 'Esc': 27,
13 |
14 | 'Spacebar': 32,
15 |
16 | 'PageUp': 33,
17 | 'PageDown': 34,
18 | 'End': 35,
19 | 'Home': 36,
20 |
21 | 'Insert': 45,
22 |
23 | 'Left': 37,
24 | 'Up': 38,
25 | 'Right': 39,
26 | 'Down': 40,
27 |
28 | 'direction': {
29 | 37: 1,
30 | 38: 1,
31 | 39: 1,
32 | 40: 1
33 | },
34 |
35 | 'Del': 46,
36 |
37 | 'NumLock': 144,
38 |
39 | 'Cmd': 91,
40 | 'CmdFF': 224,
41 | 'F1': 112,
42 | 'F2': 113,
43 | 'F3': 114,
44 | 'F4': 115,
45 | 'F5': 116,
46 | 'F6': 117,
47 | 'F7': 118,
48 | 'F8': 119,
49 | 'F9': 120,
50 | 'F10': 121,
51 | 'F11': 122,
52 | 'F12': 123,
53 |
54 | '`': 192,
55 | '=': 187,
56 | '-': 189,
57 |
58 | '/': 191,
59 | '.': 190,
60 | controlKeys: {
61 | 16: 1,
62 | 17: 1,
63 | 18: 1,
64 | 20: 1,
65 | 91: 1,
66 | 224: 1
67 | },
68 | 'notContentChange': {
69 | 13: 1,
70 | 9: 1,
71 |
72 | 33: 1,
73 | 34: 1,
74 | 35: 1,
75 | 36: 1,
76 |
77 | 16: 1,
78 | 17: 1,
79 | 18: 1,
80 | 20: 1,
81 | 91: 1,
82 |
83 | //上下左右
84 | 37: 1,
85 | 38: 1,
86 | 39: 1,
87 | 40: 1,
88 |
89 | 113: 1,
90 | 114: 1,
91 | 115: 1,
92 | 144: 1,
93 | 27: 1
94 | },
95 |
96 | 'isSelectedNodeKey': {
97 | //上下左右
98 | 37: 1,
99 | 38: 1,
100 | 39: 1,
101 | 40: 1,
102 | 13: 1,
103 | 9: 1
104 | }
105 | };
106 |
107 | // 小写适配
108 | for (var key in keymap) {
109 | if (keymap.hasOwnProperty(key)) {
110 | keymap[key.toLowerCase()] = keymap[key];
111 | }
112 | }
113 | var aKeyCode = 65;
114 | var aCharCode = 'a'.charCodeAt(0);
115 |
116 | // letters
117 | 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function(letter) {
118 | keymap[letter] = aKeyCode + (letter.charCodeAt(0) - aCharCode);
119 | });
120 |
121 | // numbers
122 | var n = 9;
123 | do {
124 | keymap[n.toString()] = n + 48;
125 | } while (--n);
126 |
127 | module.exports = keymap;
128 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/style/navigator.scss:
--------------------------------------------------------------------------------
1 | .nav-bar {
2 | position: absolute;
3 | width: 35px;
4 | height: 230px;
5 | padding: 5px 0;
6 | left: 10px;
7 | bottom: 10px;
8 | background: #fc8383;
9 | color: #fff;
10 | border-radius: 4px;
11 | z-index: 10;
12 | box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
13 | transition: -webkit-transform 0.7s 0.1s ease;
14 | transition: transform 0.7s 0.1s ease;
15 |
16 | .nav-btn {
17 | width: 35px;
18 | height: 24px;
19 | line-height: 24px;
20 | text-align: center;
21 |
22 | .icon {
23 | background: url("../../static/minder/icons.png");
24 | width: 20px;
25 | height: 20px;
26 | margin: 2px auto;
27 | display: block;
28 | }
29 |
30 | &.active {
31 | background-color: #5a6378;
32 | }
33 | }
34 |
35 | .zoom-in .icon {
36 | background-position: 0 -730px;
37 | }
38 |
39 | .zoom-out .icon {
40 | background-position: 0 -750px;
41 | }
42 |
43 | .hand .icon {
44 | background-position: 0 -770px;
45 | width: 25px;
46 | height: 25px;
47 | margin: 0 auto;
48 | }
49 |
50 | .camera .icon {
51 | background-position: 0 -870px;
52 | width: 25px;
53 | height: 25px;
54 | margin: 0 auto;
55 | }
56 |
57 | .nav-trigger .icon {
58 | background-position: 0 -845px;
59 | width: 25px;
60 | height: 25px;
61 | margin: 0 auto;
62 | }
63 |
64 | .zoom-pan {
65 | width: 2px;
66 | height: 70px;
67 | box-shadow: 0 1px #e50000;
68 | position: relative;
69 | background: white;
70 | margin: 3px auto;
71 | overflow: visible;
72 |
73 | .origin {
74 | position: absolute;
75 | width: 20px;
76 | height: 8px;
77 | left: -9px;
78 | margin-top: -4px;
79 | background: transparent;
80 |
81 | &:after {
82 | content: " ";
83 | display: block;
84 | width: 6px;
85 | height: 2px;
86 | background: white;
87 | left: 7px;
88 | top: 3px;
89 | position: absolute;
90 | }
91 | }
92 |
93 | .indicator {
94 | position: absolute;
95 | width: 8px;
96 | height: 8px;
97 | left: -3px;
98 | background: white;
99 | border-radius: 100%;
100 | margin-top: -4px;
101 | }
102 | }
103 | }
104 |
105 | .nav-previewer {
106 | background: #fff;
107 | width: 140px;
108 | height: 120px;
109 | position: absolute;
110 | left: 45px;
111 | bottom: 30px;
112 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
113 | border-radius: 0 2px 2px 0;
114 | padding: 1px;
115 | z-index: 9;
116 | cursor: crosshair;
117 | transition: -webkit-transform 0.7s 0.1s ease;
118 | transition: transform 0.7s 0.1s ease;
119 |
120 | &.grab {
121 | cursor: move;
122 | cursor: -webkit-grabbing;
123 | cursor: -moz-grabbing;
124 | cursor: grabbing;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/protocol/plain.js:
--------------------------------------------------------------------------------
1 | var LINE_ENDING = '\r';
2 | var LINE_ENDING_SPLITER = /\r\n|\r|\n/;
3 | var TAB_CHAR = '\t';
4 |
5 | function exportTextTree(minder) {
6 | var minds = minder.exportJson();
7 | try {
8 | const link = document.createElement('a');
9 | const blob = new Blob(["\ufeff" + encode(minds.root, 0)], {
10 | type: 'text/plain'
11 | });
12 | link.href = window.URL.createObjectURL(blob);
13 | link.download = `${minds.root.data.text}.txt`;
14 | document.body.appendChild(link);
15 | link.click();
16 | document.body.removeChild(link);
17 | } catch (err) {
18 | alert(err);
19 | }
20 | }
21 |
22 | function repeat(s, n) {
23 | var result = '';
24 | while (n--) result += s;
25 | return result;
26 | }
27 |
28 | function encode(json, level) {
29 | var local = '';
30 | level = level || 0;
31 | local += repeat(TAB_CHAR, level);
32 | local += json.data.text + LINE_ENDING;
33 | if (json.children) {
34 | json.children.forEach(function (child) {
35 | local += encode(child, level + 1);
36 | });
37 | }
38 | return local;
39 | }
40 |
41 | function isEmpty(line) {
42 | return !/\S/.test(line);
43 | }
44 |
45 | function getLevel(line) {
46 | var level = 0;
47 | while (line.charAt(level) === TAB_CHAR) level++;
48 | return level;
49 | }
50 |
51 | function getNode(line) {
52 | return {
53 | data: {
54 | text: line.replace(new RegExp('^' + TAB_CHAR + '*'), '')
55 | }
56 | };
57 | }
58 |
59 | /**
60 | * 文本解码
61 | *
62 | * @param {string} local 文本内容
63 | * @param {=boolean} root 自动根节点
64 | * @return {Object} 返回解析后节点
65 | */
66 | function decode(local, root) {
67 | var json,
68 | offset,
69 | parentMap = {},
70 | lines = local.split(LINE_ENDING_SPLITER),
71 | line, level, node;
72 |
73 | function addChild(parent, child) {
74 | var children = parent.children || (parent.children = []);
75 | children.push(child);
76 | }
77 | if (root) {
78 | parentMap[0] = json = getNode('root');
79 | offset = 1;
80 | } else {
81 | offset = 0;
82 | }
83 |
84 | for (var i = 0; i < lines.length; i++) {
85 | line = lines[i];
86 | if (isEmpty(line)) continue;
87 |
88 | level = getLevel(line) + offset;
89 | node = getNode(line);
90 |
91 | if (level === 0) {
92 | if (json) {
93 | throw new Error('Invalid local format');
94 | }
95 | json = node;
96 | } else {
97 | if (!parentMap[level - 1]) {
98 | throw new Error('Invalid local format');
99 | }
100 | addChild(parentMap[level - 1], node);
101 | }
102 | parentMap[level] = node;
103 | }
104 | return json;
105 | }
106 |
107 | export {
108 | exportTextTree
109 | }
110 |
--------------------------------------------------------------------------------
/kityminder-core/src/theme/fish.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var theme = require('../core/theme');
3 |
4 | theme.register('fish', {
5 | 'background': '#3A4144 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=") repeat',
6 |
7 | 'root-color': '#430',
8 | 'root-background': '#e9df98',
9 | 'root-stroke': '#e9df98',
10 | 'root-font-size': 24,
11 | 'root-padding': [35, 35],
12 | 'root-margin': 30,
13 | 'root-radius': 100,
14 | 'root-space': 10,
15 | 'root-shadow': 'rgba(0, 0, 0, .25)',
16 |
17 | 'main-color': '#333',
18 | 'main-background': '#a4c5c0',
19 | 'main-stroke': '#a4c5c0',
20 | 'main-font-size': 16,
21 | 'main-padding': [6, 20],
22 | 'main-margin': [20, 20],
23 | 'main-radius': 5,
24 | 'main-space': 5,
25 | 'main-shadow': 'rgba(0, 0, 0, .25)',
26 |
27 | 'sub-color': 'black',
28 | 'sub-background': 'white',
29 | 'sub-stroke': 'white',
30 | 'sub-font-size': 12,
31 | 'sub-padding': [5, 10],
32 | 'sub-margin': [10],
33 | 'sub-radius': 5,
34 | 'sub-space': 5,
35 |
36 | 'connect-color': 'white',
37 | 'connect-width': 3,
38 | 'main-connect-width': 3,
39 | 'connect-radius': 5,
40 |
41 | 'selected-background': 'rgb(254, 219, 0)',
42 | 'selected-stroke': 'rgb(254, 219, 0)',
43 |
44 | 'marquee-background': 'rgba(255,255,255,.3)',
45 | 'marquee-stroke': 'white',
46 |
47 | 'drop-hint-color': 'yellow',
48 | 'drop-hint-width': 4,
49 |
50 | 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
51 | 'order-hint-path-color': '#0f0',
52 | 'order-hint-path-width': 1,
53 |
54 | 'text-selection-color': 'rgb(27,171,255)',
55 | 'line-height':1.5
56 | });
57 | });
--------------------------------------------------------------------------------
/kityminder-core/src/core/template.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('./kity');
3 | var utils = require('./utils');
4 | var Minder = require('./minder');
5 | var Command = require('./command');
6 | var MinderNode = require('./node');
7 | var Module = require('./module');
8 |
9 | var _templates = {};
10 |
11 | function register(name, supports) {
12 | _templates[name] = supports;
13 | }
14 | exports.register = register;
15 |
16 | utils.extend(Minder, {
17 | getTemplateList: function() {
18 | return _templates;
19 | }
20 | });
21 |
22 | kity.extendClass(Minder, (function() {
23 | var originGetTheme = Minder.prototype.getTheme;
24 | return {
25 | useTemplate: function(name, duration) {
26 | this.setTemplate(name);
27 | this.refresh(duration || 800);
28 | },
29 |
30 | getTemplate: function() {
31 | return this._template || 'default';
32 | },
33 |
34 | setTemplate: function(name) {
35 | this._template = name || null;
36 | },
37 |
38 | getTemplateSupport: function(method) {
39 | var supports = _templates[this.getTemplate()];
40 | return supports && supports[method];
41 | },
42 |
43 | getTheme: function(node) {
44 | var support = this.getTemplateSupport('getTheme') || originGetTheme;
45 | return support.call(this, node);
46 | }
47 | };
48 | })());
49 |
50 |
51 | kity.extendClass(MinderNode, (function() {
52 | var originGetLayout = MinderNode.prototype.getLayout;
53 | var originGetConnect = MinderNode.prototype.getConnect;
54 | return {
55 | getLayout: function() {
56 | var support = this.getMinder().getTemplateSupport('getLayout') || originGetLayout;
57 | return support.call(this, this);
58 | },
59 |
60 | getConnect: function() {
61 | var support = this.getMinder().getTemplateSupport('getConnect') || originGetConnect;
62 | return support.call(this, this);
63 | }
64 | };
65 | })());
66 |
67 | Module.register('TemplateModule', {
68 | /**
69 | * @command Template
70 | * @description 设置当前脑图的模板
71 | * @param {string} name 模板名称
72 | * 允许使用的模板可以使用 `kityminder.Minder.getTemplateList()` 查询
73 | * @state
74 | * 0: 始终可用
75 | * @return 返回当前的模板名称
76 | */
77 | commands: {
78 | 'template': kity.createClass('TemplateCommand', {
79 | base: Command,
80 |
81 | execute: function(minder, name) {
82 | minder.useTemplate(name);
83 | minder.execCommand('camera');
84 | },
85 |
86 | queryValue: function(minder) {
87 | return minder.getTemplate() || 'default';
88 | }
89 | })
90 | }
91 | });
92 | });
--------------------------------------------------------------------------------
/kityminder-core/import.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | * 开发版本的文件导入
5 | */
6 | (function() {
7 | /* 可能的文件路径,已按照依赖关系排序 */
8 | var pathInfo = [
9 | /* 核心代码 */
10 | 'src/core/kityminder.js',
11 | 'src/core/utils.js',
12 |
13 | 'src/core/command.js',
14 | 'src/core/node.js',
15 |
16 | 'src/core/options.js',
17 | 'src/core/event.js',
18 | 'src/core/status.js',
19 | 'src/core/paper.js',
20 | 'src/core/select.js',
21 | 'src/core/module.js',
22 | 'src/core/data.js',
23 | 'src/core/readonly.js',
24 | 'src/core/layout.js',
25 | 'src/core/theme.js',
26 |
27 | 'src/core/compatibility.js',
28 | 'src/core/render.js',
29 | 'src/core/connect.js',
30 | 'src/core/template.js',
31 | 'src/core/keymap.js',
32 |
33 | /* 布局 */
34 | 'src/layout/mind.js',
35 | 'src/layout/filetree.js',
36 | 'src/layout/btree.js',
37 | 'src/layout/fish-bone-master.js',
38 | 'src/layout/fish-bone-slave.js',
39 |
40 | /* 连线 */
41 | 'src/connect/bezier.js',
42 | 'src/connect/poly.js',
43 | 'src/connect/arc.js',
44 | 'src/connect/under.js',
45 | 'src/connect/l.js',
46 | 'src/connect/fish-bone-master.js',
47 |
48 | /* 皮肤 */
49 | 'src/theme/default.js',
50 | 'src/theme/snow.js',
51 | 'src/theme/fresh.js',
52 | 'src/theme/fish.js',
53 | 'src/theme/wire.js',
54 |
55 | /* 模板 */
56 | 'src/template/default.js',
57 | 'src/template/structure.js',
58 | 'src/template/filetree.js',
59 | 'src/template/right.js',
60 | 'src/template/fish-bone.js',
61 |
62 | /* 模块 */
63 | 'src/module/node.js',
64 | 'src/module/text.js',
65 | 'src/module/expand.js',
66 | 'src/module/outline.js',
67 | 'src/module/history.js',
68 | 'src/module/progress.js',
69 | 'src/module/priority.js',
70 | 'src/module/image.js',
71 | 'src/module/resource.js',
72 | 'src/module/view.js',
73 | 'src/module/dragtree.js',
74 | 'src/module/keynav.js',
75 | 'src/module/select.js',
76 | 'src/module/history.js',
77 | 'src/module/editor.js',
78 | 'src/module/editor.keyboard.js',
79 | 'src/module/editor.range.js',
80 | 'src/module/editor.receiver.js',
81 | 'src/module/editor.selection.js',
82 | 'src/module/basestyle.js',
83 | 'src/module/font.js',
84 | 'src/module/zoom.js',
85 | 'src/module/hyperlink.js',
86 | 'src/module/arrange.js',
87 | 'src/module/clipboard.js',
88 | 'src/module/style.js'
89 | ];
90 |
91 | if (typeof(module) === 'object' && module.exports) {
92 | module.exports = pathInfo;
93 | }
94 |
95 | else if (document) {
96 | while (pathInfo.length) {
97 | var path = pathInfo.shift();
98 | window.document.write('');
99 | }
100 | }
101 | })();
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/receiver.js:
--------------------------------------------------------------------------------
1 | define(function (require, exports, module) {
2 | var key = require('../tool/key');
3 | var hotbox = require('./hotbox');
4 |
5 | function ReceiverRuntime() {
6 | var fsm = this.fsm;
7 | var minder = this.minder;
8 | var me = this;
9 |
10 | // 接收事件的 div
11 | var element = document.createElement('div');
12 | element.contentEditable = true;
13 | element.setAttribute("tabindex", -1);
14 | element.classList.add('receiver');
15 | element.onkeydown = element.onkeypress = element.onkeyup = dispatchKeyEvent;
16 | this.container.appendChild(element);
17 |
18 | // receiver 对象
19 | var receiver = {
20 | element: element,
21 | selectAll: function () {
22 | // 保证有被选中的
23 | if (!element.innerHTML) element.innerHTML = ' ';
24 | var range = document.createRange();
25 | var selection = window.getSelection();
26 | range.selectNodeContents(element);
27 | selection.removeAllRanges();
28 | selection.addRange(range);
29 | element.focus();
30 | },
31 | enable: function () {
32 | element.setAttribute("contenteditable", true);
33 | },
34 | disable: function () {
35 | element.setAttribute("contenteditable", false);
36 | },
37 | fixFFCaretDisappeared: function () {
38 | element.removeAttribute("contenteditable");
39 | element.setAttribute("contenteditable", "true");
40 | element.blur();
41 | element.focus();
42 | },
43 | onblur: function (handler) {
44 | element.onblur = handler;
45 | }
46 | };
47 | receiver.selectAll();
48 | minder.on('beforemousedown', receiver.selectAll);
49 | minder.on('receiverfocus', receiver.selectAll);
50 | minder.on('readonly', function () {
51 | // 屏蔽minder的事件接受,删除receiver和hotbox
52 | minder.disable();
53 | editor.receiver.element.parentElement.removeChild(editor.receiver.element);
54 | editor.hotbox.$container.removeChild(editor.hotbox.$element);
55 | });
56 |
57 | // 侦听器,接收到的事件会派发给所有侦听器
58 | var listeners = [];
59 |
60 | // 侦听指定状态下的事件,如果不传 state,侦听所有状态
61 | receiver.listen = function (state, listener) {
62 | if (arguments.length == 1) {
63 | listener = state;
64 | state = '*';
65 | }
66 | listener.notifyState = state;
67 | listeners.push(listener);
68 | };
69 |
70 | function dispatchKeyEvent(e) {
71 | e.is = function (keyExpression) {
72 | var subs = keyExpression.split('|');
73 | for (var i = 0; i < subs.length; i++) {
74 | if (key.is(this, subs[i])) return true;
75 | }
76 | return false;
77 | };
78 | var listener, jumpState;
79 | for (var i = 0; i < listeners.length; i++) {
80 |
81 | listener = listeners[i];
82 | // 忽略不在侦听状态的侦听器
83 | if (listener.notifyState != '*' && listener.notifyState != fsm.state()) {
84 | continue;
85 | }
86 |
87 | if (listener.call(null, e)) {
88 | return;
89 | }
90 | }
91 | }
92 |
93 | this.receiver = receiver;
94 | }
95 |
96 | return module.exports = ReceiverRuntime;
97 | });
98 |
--------------------------------------------------------------------------------
/kityminder-core/src/core/readonly.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 只读模式支持
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 |
10 | define(function(require, exports, module) {
11 | var kity = require('./kity');
12 | var Minder = require('./minder');
13 | var MinderEvent = require('./event');
14 |
15 | // 初始化时根据的传入的 options 决定是否要 disable
16 | Minder.registerInitHook(function(options) {
17 | if (options.readOnly) {
18 | this.disable();
19 | }
20 | });
21 |
22 | kity.extendClass(Minder, {
23 |
24 | disable: function() {
25 | var me = this;
26 | //禁用命令
27 | me.bkqueryCommandState = me.queryCommandState;
28 | me.bkqueryCommandValue = me.queryCommandValue;
29 | me.queryCommandState = function(type) {
30 | var cmd = this._getCommand(type);
31 | if (cmd && cmd.enableReadOnly) {
32 | return me.bkqueryCommandState.apply(me, arguments);
33 | }
34 | return -1;
35 | };
36 | me.queryCommandValue = function(type) {
37 | var cmd = this._getCommand(type);
38 | if (cmd && cmd.enableReadOnly) {
39 | return me.bkqueryCommandValue.apply(me, arguments);
40 | }
41 | return null;
42 | };
43 | this.setStatus('readonly');
44 | me._interactChange();
45 | },
46 |
47 | /**
48 | * @description 【二次开发新增】关闭指定模块命令
49 | * @param {Array} value 要关闭的模块名称。
50 | * 具体名称可从 minder 对象的 _commands 中获取
51 | */
52 | disableSpecificModule: function(moduleNames) {
53 | var me = this;
54 | //仅启用部分模块
55 | me.bkqueryCommandState = me.queryCommandState;
56 | me.bkqueryCommandValue = me.queryCommandValue;
57 | me.queryCommandState = function(type) {
58 | var cmd = this._getCommand(type);
59 | if (cmd && moduleNames.indexOf(cmd.__KityClassName) === -1) {
60 | return me.bkqueryCommandState.apply(me, arguments);
61 | }
62 | return -1;
63 | };
64 | me.queryCommandValue = function(type) {
65 | var cmd = this._getCommand(type);
66 | if (cmd && moduleNames.indexOf(cmd.__KityClassName) === -1) {
67 | return me.bkqueryCommandValue.apply(me, arguments);
68 | }
69 | return null;
70 | };
71 | this.setStatus('partEnable');
72 | me._interactChange();
73 | },
74 |
75 | enable: function() {
76 | var me = this;
77 |
78 | if (me.bkqueryCommandState) {
79 | me.queryCommandState = me.bkqueryCommandState;
80 | delete me.bkqueryCommandState;
81 | }
82 | if (me.bkqueryCommandValue) {
83 | me.queryCommandValue = me.bkqueryCommandValue;
84 | delete me.bkqueryCommandValue;
85 | }
86 |
87 | this.setStatus('normal');
88 |
89 | me._interactChange();
90 | }
91 | });
92 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/menu/edit/search/searchLabelBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
16 |
17 |
18 |
19 | P0
20 |
21 |
22 | P1
23 |
24 |
25 | P2
26 |
27 |
28 | P3
29 |
30 |
31 |
32 |
33 |
34 |
35 |
40 | {{ item.name }}
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
112 |
113 |
114 |
116 |
--------------------------------------------------------------------------------
/examples/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
97 |
--------------------------------------------------------------------------------
/hotbox/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
27 |
28 | 编辑区域获得焦点时,按空格呼出热盒。主菜单的快捷键可以直接执行
29 |
30 |
31 |
107 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/style/editor.scss:
--------------------------------------------------------------------------------
1 | @import "~codemirror/lib/codemirror.css";
2 | //@import "~kityminder-core/dist/kityminder.core.css";
3 | @import "~@/../kityminder-core/dist/kityminder.core.css";
4 | @import "navigator.scss";
5 | @import "hotbox.scss";
6 |
7 | // * {
8 | // box-sizing: border-box;
9 | // }
10 |
11 | .mind-editor {
12 | position: absolute;
13 | top: 91px;
14 | left: 0;
15 | right: 0;
16 | bottom: 0;
17 | }
18 |
19 | .km-editor {
20 | overflow: hidden;
21 | z-index: 2;
22 | }
23 |
24 | .km-editor > .mask {
25 | display: block;
26 | position: absolute;
27 | left: 0;
28 | right: 0;
29 | top: 0;
30 | bottom: 0;
31 | background-color: transparent;
32 | }
33 |
34 | .km-editor > .receiver {
35 | position: absolute;
36 | background: white;
37 | outline: none;
38 | box-shadow: 0 0 20px fadeout(black, 50%);
39 | left: 0;
40 | top: 0;
41 | padding: 3px 5px;
42 | margin-left: -3px;
43 | margin-top: -5px;
44 | max-width: 300px;
45 | width: auto;
46 | overflow: hidden;
47 | font-size: 14px;
48 | line-height: 1.4em;
49 | min-height: 1.4em;
50 | box-sizing: border-box;
51 | overflow: hidden;
52 | word-break: break-all;
53 | word-wrap: break-word;
54 | border: none;
55 | -webkit-user-select: text;
56 | pointer-events: none;
57 | opacity: 0;
58 | z-index: -1000;
59 |
60 | &.debug {
61 | opacity: 1;
62 | outline: 1px solid green;
63 | background: none;
64 | z-index: 0;
65 | }
66 |
67 | &.input {
68 | pointer-events: all;
69 | opacity: 1;
70 | z-index: 999;
71 | background: white;
72 | outline: none;
73 | }
74 | }
75 |
76 | div.minder-editor-container {
77 | position: absolute;
78 | top: 40px;
79 | bottom: 0;
80 | left: 0;
81 | right: 0;
82 | font-family: Arial, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
83 | }
84 |
85 | .minder-editor {
86 | position: absolute;
87 | top: 92px;
88 | left: 0;
89 | right: 0;
90 | bottom: 0;
91 | }
92 |
93 | .minder-viewer {
94 | position: absolute;
95 | top: 0;
96 | left: 0;
97 | right: 0;
98 | bottom: 0;
99 | }
100 |
101 | .control-panel {
102 | position: absolute;
103 | top: 0;
104 | right: 0;
105 | width: 250px;
106 | bottom: 0;
107 | border-left: 1px solid #ccc;
108 | }
109 |
110 | .minder-divider {
111 | position: absolute;
112 | top: 0;
113 | right: 250px;
114 | bottom: 0;
115 | width: 2px;
116 | background-color: rgb(251, 251, 251);
117 | cursor: ew-resize;
118 | }
119 |
120 | .hotbox .state .button.enabled.selected .key,
121 | .hotbox .state .ring .key {
122 | margin-top: 5px;
123 | font-size: 13px;
124 | }
125 |
126 | .hotbox .state .bottom .button .label,
127 | .hotbox .state .top .button .label {
128 | font-weight: 600;
129 | }
130 |
131 | .hotbox .exp .ring .button .label {
132 | margin-top: 28px;
133 | margin-left: -2px;
134 | }
135 |
136 | .hotbox .exp .ring .button .key {
137 | display: none;
138 | }
139 |
140 | .note-box {
141 | text-align: left;
142 | width: 400px;
143 | height: 200px;
144 | background: #feffdd;
145 | border-radius: 15px;
146 | box-shadow: 2px 2px 20px #000;
147 | overflow: auto;
148 | padding: 15px;
149 | position: fixed;
150 | z-index: 999;
151 | user-select: text;
152 | }
153 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/components/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
97 |
98 |
101 |
--------------------------------------------------------------------------------
/kityminder-core/src/layout/filetree.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var kity = require('../core/kity');
3 | var Layout = require('../core/layout');
4 |
5 | [-1, 1].forEach(registerLayoutForDir);
6 |
7 | function registerLayoutForDir(dir) {
8 | var name = 'filetree-' + (dir > 0 ? 'down' : 'up');
9 |
10 | Layout.register(name, kity.createClass({
11 | base: Layout,
12 |
13 | doLayout: function(parent, children, round) {
14 | var pBox = parent.getContentBox();
15 | var indent = 20;
16 |
17 | parent.setVertexOut(new kity.Point(pBox.left + indent, dir > 0 ? pBox.bottom : pBox.top));
18 | parent.setLayoutVectorOut(new kity.Vector(0, dir));
19 |
20 | if (!children.length) return;
21 |
22 | children.forEach(function(child) {
23 | var cbox = child.getContentBox();
24 | child.setLayoutTransform(new kity.Matrix());
25 |
26 | child.setVertexIn(new kity.Point(cbox.left, cbox.cy));
27 | child.setLayoutVectorIn(new kity.Vector(1, 0));
28 | });
29 |
30 | this.align(children, 'left');
31 | this.stack(children, 'y');
32 |
33 | var xAdjust = 0;
34 | xAdjust += pBox.left;
35 | xAdjust += indent;
36 | xAdjust += children[0].getStyle('margin-left');
37 |
38 | var yAdjust = 0;
39 |
40 | if (dir > 0) {
41 | yAdjust += pBox.bottom;
42 | yAdjust += parent.getStyle('margin-bottom');
43 | yAdjust += children[0].getStyle('margin-top');
44 | } else {
45 | yAdjust -= this.getTreeBox(children).bottom;
46 | yAdjust += pBox.top;
47 | yAdjust -= parent.getStyle('margin-top');
48 | yAdjust -= children[0].getStyle('margin-bottom');
49 | }
50 |
51 | this.move(children, xAdjust, yAdjust);
52 |
53 | },
54 |
55 | getOrderHint: function(node) {
56 | var hint = [];
57 | var box = node.getLayoutBox();
58 | var offset = node.getLevel() > 1 ? 3 : 5;
59 |
60 | hint.push({
61 | type: 'up',
62 | node: node,
63 | area: new kity.Box({
64 | x: box.x,
65 | y: box.top - node.getStyle('margin-top') - offset,
66 | width: box.width,
67 | height: node.getStyle('margin-top')
68 | }),
69 | path: ['M', box.x, box.top - offset, 'L', box.right, box.top - offset]
70 | });
71 |
72 | hint.push({
73 | type: 'down',
74 | node: node,
75 | area: new kity.Box({
76 | x: box.x,
77 | y: box.bottom + offset,
78 | width: box.width,
79 | height: node.getStyle('margin-bottom')
80 | }),
81 | path: ['M', box.x, box.bottom + offset, 'L', box.right, box.bottom + offset]
82 | });
83 | return hint;
84 | }
85 | }));
86 |
87 | }
88 |
89 | });
--------------------------------------------------------------------------------
/kityminder-core/src/theme/snow.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var theme = require('../core/theme');
3 |
4 | ['snow', 'snow-compact'].forEach(function(name) {
5 | var compact = name == 'snow-compact';
6 |
7 | /* jscs:disable maximumLineLength */
8 | theme.register(name, {
9 | 'background': '#3A4144 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=") repeat',
10 |
11 | 'root-color': '#430',
12 | 'root-background': '#e9df98',
13 | 'root-stroke': '#e9df98',
14 | 'root-font-size': 24,
15 | 'root-padding': compact ? [5, 10] : [15, 25],
16 | 'root-margin': compact ? 15 : 30,
17 | 'root-radius': 5,
18 | 'root-space': 10,
19 | 'root-shadow': 'rgba(0, 0, 0, .25)',
20 |
21 | 'main-color': '#333',
22 | 'main-background': '#a4c5c0',
23 | 'main-stroke': '#a4c5c0',
24 | 'main-font-size': 16,
25 | 'main-padding': compact ? [4, 10] : [6, 20],
26 | 'main-margin': compact ? [5, 10] : [20, 40],
27 | 'main-radius': 5,
28 | 'main-space': 5,
29 | 'main-shadow': 'rgba(0, 0, 0, .25)',
30 |
31 | 'sub-color': 'black',
32 | 'sub-background': 'white',
33 | 'sub-stroke': 'white',
34 | 'sub-font-size': 12,
35 | 'sub-padding': [5, 10],
36 | 'sub-margin': compact ? [5, 10] : [10, 20],
37 | 'sub-radius': 5,
38 | 'sub-space': 5,
39 |
40 | 'connect-color': 'white',
41 | 'connect-width': 2,
42 | 'main-connect-width': 3,
43 | 'connect-radius': 5,
44 |
45 | 'selected-background': 'rgb(254, 219, 0)',
46 | 'selected-stroke': 'rgb(254, 219, 0)',
47 |
48 | 'marquee-background': 'rgba(255,255,255,.3)',
49 | 'marquee-stroke': 'white',
50 |
51 | 'drop-hint-color': 'yellow',
52 | 'drop-hint-width': 4,
53 |
54 | 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
55 | 'order-hint-path-color': '#0f0',
56 | 'order-hint-path-width': 1,
57 |
58 | 'text-selection-color': 'rgb(27,171,255)',
59 | 'line-height':1.5
60 | });
61 | });
62 | });
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/src/script/runtime/fsm.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview
3 | *
4 | * 编辑器状态机
5 | *
6 | * @author: techird
7 | * @copyright: Baidu FEX, 2014
8 | */
9 | define(function (require, exports, module) {
10 |
11 | var Debug = require('../tool/debug');
12 | var debug = new Debug('fsm');
13 |
14 | function handlerConditionMatch(condition, when, exit, enter) {
15 | if (condition.when != when) return false;
16 | if (condition.enter != '*' && condition.enter != enter) return false;
17 | if (condition.exit != '*' && condition.exit != exit) return;
18 | return true;
19 | }
20 |
21 | function FSM(defaultState) {
22 | var currentState = defaultState;
23 | var BEFORE_ARROW = ' - ';
24 | var AFTER_ARROW = ' -> ';
25 | var handlers = [];
26 |
27 | /**
28 | * 状态跳转
29 | *
30 | * 会通知所有的状态跳转监视器
31 | *
32 | * @param {string} newState 新状态名称
33 | * @param {any} reason 跳转的原因,可以作为参数传递给跳转监视器
34 | */
35 | this.jump = function (newState, reason) {
36 | if (!reason) throw new Error('Please tell fsm the reason to jump');
37 |
38 | var oldState = currentState;
39 | var notify = [oldState, newState].concat([].slice.call(arguments, 1));
40 | var i, handler;
41 |
42 | // 跳转前
43 | for (i = 0; i < handlers.length; i++) {
44 | handler = handlers[i];
45 | if (handlerConditionMatch(handler.condition, 'before', oldState, newState)) {
46 | if (handler.apply(null, notify)) return;
47 | }
48 | }
49 |
50 | currentState = newState;
51 | debug.log('[{0}] {1} -> {2}', reason, oldState, newState);
52 |
53 | // 跳转后
54 | for (i = 0; i < handlers.length; i++) {
55 | handler = handlers[i];
56 | if (handlerConditionMatch(handler.condition, 'after', oldState, newState)) {
57 | handler.apply(null, notify);
58 | }
59 | }
60 | return currentState;
61 | };
62 |
63 | /**
64 | * 返回当前状态
65 | * @return {string}
66 | */
67 | this.state = function () {
68 | return currentState;
69 | };
70 |
71 | /**
72 | * 添加状态跳转监视器
73 | *
74 | * @param {string} condition
75 | * 监视的时机
76 | * "* => *" (默认)
77 | *
78 | * @param {Function} handler
79 | * 监视函数,当状态跳转的时候,会接收三个参数
80 | * * from - 跳转前的状态
81 | * * to - 跳转后的状态
82 | * * reason - 跳转的原因
83 | */
84 | this.when = function (condition, handler) {
85 | if (arguments.length == 1) {
86 | handler = condition;
87 | condition = '* -> *';
88 | }
89 |
90 | var when, resolved, exit, enter;
91 |
92 | resolved = condition.split(BEFORE_ARROW);
93 | if (resolved.length == 2) {
94 | when = 'before';
95 | } else {
96 | resolved = condition.split(AFTER_ARROW);
97 | if (resolved.length == 2) {
98 | when = 'after';
99 | }
100 | }
101 | if (!when) throw new Error('Illegal fsm condition: ' + condition);
102 |
103 | exit = resolved[0];
104 | enter = resolved[1];
105 |
106 | handler.condition = {
107 | when: when,
108 | exit: exit,
109 | enter: enter
110 | };
111 |
112 | handlers.push(handler);
113 | };
114 | }
115 |
116 | function FSMRumtime() {
117 | this.fsm = new FSM('normal');
118 | }
119 |
120 | return module.exports = FSMRumtime;
121 | });
122 |
--------------------------------------------------------------------------------
/packages/VueTestcaseMinderEditor/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
102 |
--------------------------------------------------------------------------------
/kityminder-core/src/theme/default.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module) {
2 | var theme = require('../core/theme');
3 |
4 | ['classic', 'classic-compact'].forEach(function(name) {
5 | var compact = name == 'classic-compact';
6 |
7 | /* jscs:disable maximumLineLength */
8 | theme.register(name, {
9 | 'background': '#3A4144 url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=") repeat',
10 |
11 | 'root-color': '#430',
12 | 'root-background': '#e9df98',
13 | 'root-stroke': '#e9df98',
14 | 'root-font-size': 24,
15 | 'root-padding': compact ? [10, 25] : [15, 25],
16 | 'root-margin': compact ? [15, 25] : [30, 100],
17 | 'root-radius': 30,
18 | 'root-space': 10,
19 | 'root-shadow': 'rgba(0, 0, 0, .25)',
20 |
21 | 'main-color': '#333',
22 | 'main-background': '#a4c5c0',
23 | 'main-stroke': '#a4c5c0',
24 | 'main-font-size': 16,
25 | 'main-padding': compact ? [5, 15] : [6, 20],
26 | 'main-margin': compact ? [5, 10] : 20,
27 | 'main-radius': 10,
28 | 'main-space': 5,
29 | 'main-shadow': 'rgba(0, 0, 0, .25)',
30 |
31 | 'sub-color': 'white',
32 | 'sub-background': 'transparent',
33 | 'sub-stroke': 'none',
34 | 'sub-font-size': 12,
35 | 'sub-padding': [5, 10],
36 | 'sub-margin': compact ? [5, 10] : [15, 20],
37 | 'sub-tree-margin': 30,
38 | 'sub-radius': 5,
39 | 'sub-space': 5,
40 |
41 | 'connect-color': 'white',
42 | 'connect-width': 2,
43 | 'main-connect-width': 3,
44 | 'connect-radius': 5,
45 |
46 | 'selected-background': 'rgb(254, 219, 0)',
47 | 'selected-stroke': 'rgb(254, 219, 0)',
48 | 'selected-color': 'black',
49 |
50 | 'marquee-background': 'rgba(255,255,255,.3)',
51 | 'marquee-stroke': 'white',
52 |
53 | 'drop-hint-color': 'yellow',
54 | 'sub-drop-hint-width': 2,
55 | 'main-drop-hint-width': 4,
56 | 'root-drop-hint-width': 4,
57 |
58 | 'order-hint-area-color': 'rgba(0, 255, 0, .5)',
59 | 'order-hint-path-color': '#0f0',
60 | 'order-hint-path-width': 1,
61 |
62 | 'text-selection-color': 'rgb(27,171,255)',
63 | 'line-height':1.5
64 | });
65 | });
66 | });
--------------------------------------------------------------------------------